Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 3583 → Rev 3584

/programs/network/netsurf/netsurf/Docs/BUILDING-AmigaCross
0,0 → 1,87
to install an Amiga cross-compiler in a Linux distribution, there are instructions at
 
http://utilitybase.com/article/show/2007/06/23/231/Installing+an+AmigaOS+4+cross+compiler
 
a more Mac-oriented article [though of potentially general utility] is at
http://utilitybase.com/article/show/2006/05/21/188/Building+Amiga+OS+4+GCC+Cross+Compiler+for+UNIX%252FMAC
 
more background at
http://cross.zerohero.se/os4.html
 
cross-compile additional libs/tools
SDK
http://www.hyperion-entertainment.biz/
 
newlib
http://sources.redhat.com/newlib/
 
clib2
http://sourceforge.net/projects/clib2/
 
ixemul
http://strohmayer.org/sfs/
 
libnix
http://sourceforge.net/projects/libnix/
 
though newlib / clib2 are apparently already included in the ppc-amigaos-gcc tarball
 
lha utility is debian package lha
 
then install linked libs in the correct place
 
[normally /usr/local/amiga]
so
sudo chmod --recursive 775 /usr/local/amiga
sudo chmod --recursive +s /usr/local/amiga
sudo chown --recursive `whoami` /usr/local/amiga
sudo chgrp --recursive root /usr/local/amiga
[mkdir /usr/local/amiga/include]
 
[may need to set ppc-amigaos-gcc libpaths]
 
zlib
download tarball from project homepage, untar in a storage directory /
download source from your distribution's repository [zlib1g in Ubuntu]
[cd to top-level directory of zlib containing configure script]
CC=ppc-amigaos-gcc AR=ppc-amigaos-ar RANLIB=ppc-amigaos-ranlib \
CFLAGS="-DNO_FSEEKO" ./configure --prefix=/usr/local/amiga
make
make install
 
regex [pre-compiled]
http://aminet.net/dev/lib/libregex-4.4.3.lha
 
libcurl
download the tarball from the project's homepage, untar in a storage directory /
download source from your distribution's repository
cd into the directory containing the configure file
./configure --prefix=/usr/local/amiga --host=ppc-amigaos
$ make
[you MUST have either POSIX or glibc strerror_r if strerror_r is found]
$ make install
 
alternative
http://www.aminet.net/dev/lib/libcurl.lha
 
libiconv [unnecessary as a non-overridable limited version is included in newlib]
 
openssl
 
libpng
 
libmng
http://www.aminet.net/dev/lib/libmng_so.lha
http://www.aminet.net/dev/lib/libmng.lha
 
liblcms
http://www.aminet.net/dev/lib/liblcms_so.lha
http://www.aminet.net/dev/lib/liblcms_so.lha
 
libjpeg
 
libparserutils
libhubbub
libcss
libnsbmp
libnsgif
/programs/network/netsurf/netsurf/Docs/BUILDING-AmigaOS
0,0 → 1,159
--------------------------------------------------------------------------------
Build Instructions for AmigaOS NetSurf 13 February 2010
--------------------------------------------------------------------------------
 
This document provides instructions for building the AmigaOS version of
NetSurf and provides guidance on obtaining NetSurf's build dependencies.
 
AmigaOS NetSurf has been tested on AmigaOS 4.0 July 2007 Update and AmigaOS
4.1. It will require modification for AmigaOS 3.9 or earlier, or other
Amiga-like platforms.
 
AmigaOS NetSurf will build against newlib by default, building against
clib2 has not been tested.
 
 
Building and executing NetSurf
================================
 
First of all, you should examine the contents of Makefile.defaults
and enable and disable relevant features as you see fit by creating
a Makefile.config. Some of these options can be automatically
detected and used, although it is better to explicitly enable or
disable options.
You should then obtain NetSurf's dependencies, keeping in mind which options
you have enabled in the configuration file. See the next section for
specifics.
Once done, to build AmigaOS NetSurf on OS4, simply run:
 
1> gmake
 
If that produces errors, you probably don't have some of NetSurf's build
dependencies installed. See "Obtaining NetSurf's dependencies" below, or turn
off the complaining features in a Makefile.config.
 
Running NetSurf from the build tree requires some setup:
 
1> makelink resources amiga/resources force
1> copy amiga/resources/themes/default/NetSurf.info NetSurf.info
 
It should then be possible to run NetSurf by executing NetSurf from the
Shell or by double-clicking on the icon.
 
 
Obtaining NetSurf's build dependencies
========================================
 
Many of NetSurf's dependencies are included with the OS4 SDK or available
from Aminet or OS4Depot. The remainder must be built manually.
 
The NetSurf project's libraries
---------------------------------
 
The NetSurf project has developed several libraries which are required by
the browser. To fetch each of these libraries, run the appropriate commands
from the Docs/LIBRARIES file.
 
To build and install these libraries, simply enter each of their directories
and run:
1> gmake install
 
| Note: We advise enabling iconv() support in libparserutils, which vastly
| increases the number of supported character sets. To do this,
| create a file called Makefile.config.override in the libparserutils
| directory, containing the following lines:
|
| CFLAGS += -DWITH_ICONV_FILTER
| LDFLAGS += -liconv
|
| This requires libiconv as iconv support in newlib.library is buggy.
|
| For more information, consult the libparserutils README file.
 
| Note: Building libsvgtiny requires gperf, which is available from Aminet:
|
| http://www.aminet.net/package/dev/c/gperf
 
 
cURL
------
 
A version of libcurl built for newlib is available from Aminet
 
http://www.aminet.net/package/dev/lib/libcurl
 
There is a shared object version included with some OWB releases. To use
this when compiling with Cairo support, a link must be made:
 
1> makelink sdk:local/newlib/lib/libcurl.so sobjs:libcurl-7.16.so soft
 
 
libmng
--------
 
NetSurf uses libMNG to display MNG and PNG files.
It builds without any problems on OS4, or available from Aminet:
 
http://www.aminet.net/package/dev/lib/libmng_so
 
 
OpenSSL
---------
 
NetSurf uses OpenSSL for encrypted transfers.
 
http://www.os4depot.net/share/development/library/misc/libopenssl.lha
 
There is a shared object version included with some OWB releases. To use
this when compiling with Cairo support, a link must be made:
 
1> makelink sdk:local/newlib/lib/libssl.so sobjs:libssl-0.9.8.so soft
1> makelink sdk:local/newlib/lib/libcrypto.so sobjs:libssl-0.9.8.so soft
 
 
Libharu
---------
 
NetSurf can use Haru PDF to enable PDF export. Haru PDF can be obtained
from http://libharu.org/. We require libharu 2.2 or later.
 
| Note: libharu cannot be auto-detected by the Makefile. If you wish to
| enable it, do so by creating a Makefile.config file.
 
 
libregex
----------
 
A version of the regular expression library can be obtained from Aminet:
 
http://www.aminet.net/package/dev/lib/libregex-4.4.3
 
 
openurl.library
-----------------
 
The AmigaOS mailto: URL support uses openurl.library, this and the includes
can be obtained from Aminet:
 
http://www.aminet.net/package/comm/www/OpenURL-OS4
 
 
General requirements
----------------------
 
SDK:newlib/include/strings.h needs to be modified by adding the following:
 
extern int strcasecmp(const char *, const char *);
extern int strncasecmp(const char *, const char *, size_t);
 
amiga/version.c is generated by version.rexx using the SVN command. If
the source has not been checked out from SVN, or is being cross-compiled,
this file will need to be created by hand. See the end of version.rexx
for the variables that are defined in the file.
 
Please note that building with Cairo (option NETSURF_AMIGA_USE_CAIRO) will
link NetSurf against shared objects, and require the OS4.1 SDK to build and
AmigaOS 4.1 to run.
/programs/network/netsurf/netsurf/Docs/BUILDING-BeOS
0,0 → 1,127
--------------------------------------------------------------------------------
Build Instructions for BeOS and Haiku NetSurf 13 February 2010
--------------------------------------------------------------------------------
 
This document provides instructions for building the BeOS and Haiku version
of NetSurf and provides guidance on obtaining NetSurf's build dependencies.
 
BeOS NetSurf has been tested on Zeta only for now. There are still some
issues to sort out for other BeOS versions.
 
 
There are still pending fixes against SVN before it can be build from BeOS
or Haiku.
 
 
Building and executing NetSurf
================================
 
To build NetSurf on a BeOS or Haiku, provided you have the relevant
build dependencies installed, simply run:
 
$ make
 
If that produces errors, you probably don't have some of NetSurf's build
dependencies installed. See "Obtaining NetSurf's dependencies" below. You
may need to "make clean" before attempting to build after installing the
dependencies. Also note BeOS has an old make command that won't work, see
below.
 
 
Obtaining NetSurf's dependencies
==================================
 
Many of NetSurf's dependencies are either installed or available for BeOS and
Haiku. The remainder must be installed manually.
 
The NetSurf project's libraries
---------------------------------
 
The NetSurf project has developed several libraries which are required by
the browser. To fetch each of these libraries, run the appropriate commands
from the Docs/LIBRARIES file.
 
To build and install these libraries, simply enter each of their directories
and run:
$ make install
 
| Note: We advise enabling iconv() support in libparserutils, which vastly
| increases the number of supported character sets. To do this,
| create a file called Makefile.config.override in the libparserutils
| directory, containing the following line:
|
| CFLAGS += -DWITH_ICONV_FILTER
|
| For more information, consult the libparserutils README file.
 
TODO: add some more here.
 
rc
----
 
Building NetSurf needs the Haiku resource compiler (rc), that allows
importing files from resource definitions (.rdef).
 
$ cd <haiku-trunk-directory>
$ TARGET_PLATFORM=r5 jam -q rc
$ cp generated/objects/dano/x86/release/tools/rc/rc /boot/home/config/bin/
 
 
GNU make 3.81
---------------
 
BeOS has an old make tool, which won't work when building NetSurf.
Haiku has 3.81 which is the one that works. For BeOS, one has to replace
the original make with one built from the Haiku tree, or install it as gmake:
 
$ cd <haiku-trunk-directory>
$ TARGET_PLATFORM=r5 jam -q make
$ cp generated/objects/r5/x86/release/bin/make/make /boot/home/config/bin/gmake
 
 
cURL
------
 
NetSurf uses cURL to fetch files from the network.
There is a patch against the official version on HaikuPorts.
 
TODO
 
 
libmng
--------
 
NetSurf uses libMNG to display MNG and PNG files.
It should build just fine on BeOS.
 
 
libjpeg
---------
 
NetSurf uses libjpeg to display JPEG files.
It should already be available in your dev kit.
 
 
OpenSSL
----------
 
NetSurf uses OpenSSL for encrypted transfers.
 
 
General requirements
----------------------
 
There is currently an issue on stdbool.h (unsigned char bool vs enum bool)
which needs to be fixed, for now one can use the Haiku version of the header
and copy it over the gcc-provided one.
$ cd <haiku-trunk-directory>
$ cp headers/build/gcc-2.95.3/stdbool.h /boot/develop/tools/gnupro/lib/gcc-lib/i586-pc-beos/2.95.3-beos-060710/include/stdbool.h
 
 
NetSurf might build on BeOS R5 but probably won't work on anything else than
BONE.
 
This will pull in loads of things, like all the GTK dev libraries, the PNG
and JPEG libraries, colour management libraries, zlib, OpenSSL etc that
NetSurf also depends on.
/programs/network/netsurf/netsurf/Docs/BUILDING-Cocoa
0,0 → 1,87
--------------------------------------------------------------------------------
Build Instructions for Cocoa NetSurf 13 January 2011
--------------------------------------------------------------------------------
 
This document provides instructions for building the Cocoa version of NetSurf
and provides guidance on obtaining NetSurf's build dependencies.
 
Cocoa NetSurf has been tested on Mac OS X 10.6 on Intel and on Mac OS X 10.5
on ppc.
 
 
Building NetSurf
==================
 
After installing the dependencies NetSurf can be built either using the Xcode
project file 'cocoa/NetSurf.xcodeproj' or on the command line using the
Makefile:
 
$ make TARGET=cocoa
 
In both cases the actual build process is controlled by the Makefile.
 
Obtaining NetSurf's build dependencies
========================================
 
Many of NetSurf's dependencies are packaged on various operating systems.
The remainder must be installed manually. Currently, some of the libraries
developed as part of the NetSurf project have not had official releases.
Hopefully they will soon be released with downloadable tarballs and packaged
in common distros. For now, you'll have to make do with Git checkouts.
 
Package installation
----------------------
 
For building the other NetSurf libraries and for configuring NetSurf the
"pkg-config" tool is required. It can be installed either via fink, macports
or homebrew or from source.
 
OpenSSL, LibPNG, curl, iconv and zlib are provided by Mac OS X.
 
The curl library provided by Mac OS X 10.6 causes a crash while fetching
https resources, so you should install version 7.21.4 (or newer) of libcurl
if you are running on 10.6.
 
LibJPEG and LibMNG can be installed from source or using one of the mentioned
package managers.
 
 
The NetSurf project's libraries
---------------------------------
 
The NetSurf project has developed several libraries which are required by
the browser. These are:
 
LibParserUtils -- Parser building utility functions
LibWapcaplet -- String internment
Hubbub -- HTML5 compliant HTML parser
LibCSS -- CSS parser and selection engine
LibNSGIF -- GIF format image decoder
LibNSBMP -- BMP and ICO format image decoder
LibROSprite -- RISC OS Sprite format image decoder
 
To fetch each of these libraries, run the appropriate commands from the
Docs/LIBRARIES file.
 
$ make
$ sudo make install
 
This command builds the libraries only for the active architecture. To build
universal binaries use those commands:
 
$ make UNIVERSAL="i386 x86_64 ppc ppc64"
$ sudo make install
 
If you are building NetSurf for using it on only one computer this is not
necessary, but if you want to distribute your binary you should build
universal binaries. You can also leave some of the platform names out, if
you don't require them.
 
| Note: We advise enabling iconv() support in libparserutils, which vastly
| increases the number of supported character sets. To do this,
| create a file called Makefile.config.override in the libparserutils
| directory, containing the following line:
|
| CFLAGS += -DWITH_ICONV_FILTER
|
| For more information, consult the libparserutils README file.
/programs/network/netsurf/netsurf/Docs/BUILDING-Framebuffer
0,0 → 1,281
--------------------------------------------------------------------------------
Build Instructions for Framebuffer NetSurf 13 February 2010
--------------------------------------------------------------------------------
 
This document provides instructions for building the Framebuffer version of
NetSurf and provides guidance on obtaining NetSurf's build dependencies.
 
Framebuffer NetSurf has been tested on Ubuntu and Debian.
 
Building and executing NetSurf
================================
 
First of all, you should examine the contents of Makefile.defaults
and enable and disable relevant features as you see fit in a
Makefile.config file. Some of these options can be automatically
detected and used, and where this is the case they are set to such.
Others cannot be automatically detected from the Makefile, so you
will either need to install the dependencies, or set them to NO.
You should then obtain NetSurf's dependencies, keeping in mind which options
you have enabled in the configuration file. See the "Obtaining NetSurf's
dependencies" section for specifics.
Once done, to build Framebuffer NetSurf on a UNIX-like platform, simply run:
 
$ make TARGET=framebuffer
 
If that produces errors, you probably don't have some of NetSurf's build
dependencies installed. See "Obtaining NetSurf's dependencies" below.
Or turn off the complaining features in your Makefile.config. You may
need to "make clean" before attempting to build after installing the
dependencies.
 
Run NetSurf by executing the "nsfb" program:
 
$ ./nsfb
 
| Note: NetSurf uses certain resources at run time. In order to find these
| resources, it searches three locations:
|
| 1. ~/.netsurf/
| 2. $NETSURFRES/
| 3. /usr/share/netsurf/
|
| In the build tree, the resources are located at
|
| framebuffer/res
|
| Setting $NETSURFRES to point at the resources in the build tree
| will enable you to run NetSurf from here without installation.
| To do this, run:
|
| export NETSURFRES=`pwd`/framebuffer/res
 
 
Fonts
=======
 
The framebuffer port currently has two choices for font
handling. The font handler may be selected at compile time by using
the NETSURF_FB_FONTLIB configuration key. Currently supported values
are internal and freetype
 
Internal
----------
 
The internal font system has a single built in monospaced face with
CP467 encoding. The internal font plotter requires no additional
resources and is very fast, it is also aesthetically unappealing.
 
Freetype
----------
 
The freetype font system (freetype version 2 API is used) has
support for a number of different font file formats and faces. The
framebuffer font handler takes advantage of the freetype library
caching system to give good performance.
 
The font glyphs are, by default, rendered as 256 level transparency
which gives excellent visual results even on small font sizes.
 
The default font is the DejaVu trutype font set. The default path they
are sourced from is /usr/share/fonts/truetype/ttf-dejavu/ .
 
The compiled in default paths may be altered by setting values in
the user configuration makefile Makefile.config. These values must
be set to teh absolute path of the relevant font file including its
.ttf extension. The variables are:
 
NETSURF_FB_FONT_SANS_SERIF
NETSURF_FB_FONT_SANS_SERIF_BOLD
NETSURF_FB_FONT_SANS_SERIF_ITALIC
NETSURF_FB_FONT_SANS_SERIF_ITALIC_BOLD
NETSURF_FB_FONT_SERIF
NETSURF_FB_FONT_SERIF_BOLD
NETSURF_FB_FONT_MONOSPACE
NETSURF_FB_FONT_MONOSPACE_BOLD
NETSURF_FB_FONT_CURSIVE
NETSURF_FB_FONT_FANTASY
The font selection may be changed by placing truetype font files
in the resources path. The resource files will be the generic names
sans_serif.ttf, sans_serif_bold.ttf etc.
 
The font system is configured at runtime by several options. The
fb_font_monochrome option causes the renderer to use monochrome
glyph rendering which is faster to plot but slower to render and
much less visually appealing.
 
The remaining seven options control the files to be used for font faces.
 
fb_face_sans_serif - The sans serif face
fb_face_sans_serif_bold - The bold sans serif face
fb_face_sans_serif_italic - The italic sans serif face
fb_face_sans_serif_italic_bold - The bold italic sans serif face.
fb_face_serif - The serif font
fb_serif_bold - The bold serif font
fb_face_monospace - The monospaced font
fb_face_monospace_bold - The bold monospaced font
fb_face_cursive - The cursive font
fb_face_fantasy - The fantasy font
 
Old Freetype
--------------
 
The framebuffer port Freetype font implementation was constructed
using a modern version of the library (2.3.5) to use versions 2.2.1
and prior the following patch is necessary.
 
 
Index: framebuffer/font_freetype.c
===================================================================
--- framebuffer/font_freetype.c (revision 6750)
+++ framebuffer/font_freetype.c (working copy)
@@ -311,6 +311,7 @@
FT_Glyph glyph;
FT_Error error;
fb_faceid_t *fb_face;
+ FTC_ImageTypeRec trec;
fb_fill_scalar(style, &srec);
@@ -318,15 +319,24 @@
glyph_index = FTC_CMapCache_Lookup(ft_cmap_cache, srec.face_id, fb_face->cidx, ucs4);
- error = FTC_ImageCache_LookupScaler(ft_image_cache,
- &srec,
- FT_LOAD_RENDER |
- FT_LOAD_FORCE_AUTOHINT |
- ft_load_type,
- glyph_index,
- &glyph,
- NULL);
+ trec.face_id = srec.face_id;
+ if (srec.pixel) {
+ trec.width = srec.width;
+ trec.height = srec.height;
+ } else {
+ /* Convert from 1/64 pts to pixels */
+ trec.width = srec.width * css_screen_dpi / 64 / srec.x_res;
+ trec.height = srec.height * css_screen_dpi / 64 / srec.y_res;
+ }
+ trec.flags = FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT | ft_load_type;
+
+ error = FTC_ImageCache_Lookup(ft_image_cache,
+ &trec,
+ glyph_index,
+ &glyph,
+ NULL);
+
return glyph;
}
 
 
Selecting a frontend and appropriate options
==============================================
 
The framebuffer port interfaces to its input and output devices
using the NetSurf Framebuffer library (libnsfb). This library
provides an abstraction layer to input and output devices.
 
The surface used by libnsfb is selected by using the -f switch to
NetSurf when executed. A surface in this context is simply the
combination of input and output devices.
 
A surface output device may be any linearly mapped area of
memory. The framebuffer may be treated as values at 32, 16 or 8 bits
per pixel. The input device is typically selected to complement the
output device and is completely specific to the surface.
 
There are several configuration options which may influence the
framebuffer surfaces. These are:
 
fb_refresh - The refresh rate (for physical displays)
fb_depth - The depth (in bits per pixel) of the framebuffer
window_width - The width of the framebuffer
window_height - The height of the framebuffer
 
The defaults are for 800 by 600 pixels at 16bpp and 70Hz refresh rate.
 
The documentation of libnsfb should be consulted for futher
information about supported frontends and their configuration.
 
 
Obtaining NetSurf's build dependencies
========================================
 
Many of NetSurf's dependencies are packaged on various operating systems.
The remainder must be installed manually. Currently, some of the libraries
developed as part of the NetSurf project have not had official releases.
Hopefully they will soon be released with downloadable tarballs and packaged
in common distros. For now, you'll have to make do with Git checkouts.
 
Package installation
----------------------
 
Debian-like OS:
 
$ apt-get install libcurl3-dev libmng-dev
 
Recent OS versions might need libcurl4-dev instead of libcurl3-dev but
note that when it has not been built with OpenSSL, the SSL_CTX is not
available and results that certification details won't be presented in case
they are invalid. But as this is currently unimplemented in the Framebuffer
flavour of NetSurf, this won't make a difference at all.
 
Fedora:
 
$ yum install curl-devel libmng-devel lcms-devel
 
Other:
 
You'll need to install the development resources for libcurl3 and libmng.
 
Note that if you don't require MNG or JNG image support, NetSurf can be
configured to use libpng instead of libmng. If you wish to do this, install
the libpng development package instead.
 
The NetSurf project's libraries
---------------------------------
 
The NetSurf project has developed several libraries which are required by
the browser. These are:
 
LibParserUtils -- Parser building utility functions
LibWapcaplet -- String internment
Hubbub -- HTML5 compliant HTML parser
LibCSS -- CSS parser and selection engine
LibNSGIF -- GIF format image decoder
LibNSBMP -- BMP and ICO format image decoder
LibROSprite -- RISC OS Sprite format image decoder
LibNSFB -- Framebuffer abstraction
 
To fetch each of these libraries, run the appropriate commands from the
Docs/LIBRARIES file.
 
To build and install these libraries, simply enter each of their directories
and run:
$ sudo make install
 
| Note: We advise enabling iconv() support in libparserutils, which vastly
| increases the number of supported character sets. To do this,
| create a file called Makefile.config.override in the libparserutils
| directory, containing the following line:
|
| CFLAGS += -DWITH_ICONV_FILTER
|
| For more information, consult the libparserutils README file.
 
General requirements
----------------------
 
Depending on the frontend selected the build may need specific
libraries installed, e.g. the SDL port requires SDL1.2 or later
 
Installing these libraries will often will pull in loads of things,
like the PNG and JPEG libraries, colour management libraries, zlib,
OpenSSL etc that NetSurf also depends on.
/programs/network/netsurf/netsurf/Docs/BUILDING-GTK
0,0 → 1,146
--------------------------------------------------------------------------------
Build Instructions for GTK NetSurf 8 April 2010
--------------------------------------------------------------------------------
 
This document provides instructions for building the GTK version of NetSurf
and provides guidance on obtaining NetSurf's build dependencies.
 
GTK NetSurf has been tested on Debian, Ubuntu, Fedora 8, FreeBSD, NetBSD and
Solaris 10.
 
 
Building and executing NetSurf
================================
 
First of all, you should examine the contents of Makefile.defaults
and enable and disable relevant features as you see fit by creating
a Makefile.config file. Some of these options can be automatically
detected and used, and where this is the case they are set to such.
Others cannot be automatically detected from the Makefile, so you
will either need to install the dependencies, or set them to NO.
You should then obtain NetSurf's dependencies, keeping in mind which options
you have enabled in the configuration file. See the next section for
specifics.
Once done, to build GTK NetSurf on a UNIX-like platform, simply run:
 
$ make
 
If that produces errors, you probably don't have some of NetSurf's
build dependencies installed. See "Obtaining NetSurf's dependencies"
below. Or turn off the complaining features in a Makefile.config
file. You may need to "make clean" before attempting to build after
installing the dependencies.
 
Run NetSurf by executing the "test-nsgtk" shell script:
 
$ ./test-nsgtk
 
This script makes it easy to run the nsgtk binary from the build tree. It
sets up some environment variables which enable NetSurf to find its
resources.
 
If you are packaging NetSurf, see the PACKAGING-GTK document.
 
 
Obtaining NetSurf's build dependencies
========================================
 
Many of NetSurf's dependencies are packaged on various operating systems.
The remainder must be installed manually. Currently, some of the libraries
developed as part of the NetSurf project have not had official releases.
Hopefully they will soon be released with downloadable tarballs and packaged
in common distros. For now, you'll have to make do with Git checkouts.
 
Some of NetSurf's own libraries will be installed in /usr/local/ by default.
Fedora, and perhaps some other distributions of Linux, do not ship a
pkg-config that will search here, so you will either need to change where
these libraries install, or do the following before building NetSurf itself;
$ PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
$ export PKG_CONFIG_PATH
 
Package installation
----------------------
 
Debian-like OS:
 
$ apt-get install libglade2-dev libcurl3-dev libmng-dev
$ apt-get install librsvg2-dev liblcms1-dev libjpeg-dev
 
Recent OS versions might need libcurl4-dev instead of libcurl3-dev but
note that when it has not been built with OpenSSL, the SSL_CTX is not
available and results that certification details won't be presented in case
they are invalid. But as this is currently unimplemented in the GTK
flavour of NetSurf, this won't make a difference at all.
 
For experimental javascript support the mozilla spiermonkey library
is required:
 
$ apt-get install libmozjs-dev
 
Fedora:
 
$ yum install libglade2-devel curl-devel libmng-devel
$ yum install librsvg2-devel lcms-devel
 
Other:
 
You'll need to install the development resources for libglade2, libcurl3,
libmng and librsvg.
 
Note that if you don't require MNG or JNG image support, NetSurf can be
configured to use libpng instead of libmng. If you wish to do this, install
the libpng development package instead.
 
The NetSurf project's libraries
---------------------------------
 
The NetSurf project has developed several libraries which are required by
the browser. These are:
 
LibParserUtils -- Parser building utility functions
LibWapcaplet -- String internment
Hubbub -- HTML5 compliant HTML parser
LibCSS -- CSS parser and selection engine
LibNSGIF -- GIF format image decoder
LibNSBMP -- BMP and ICO format image decoder
LibROSprite -- RISC OS Sprite format image decoder
 
To fetch each of these libraries, run the appropriate commands from the
Docs/LIBRARIES file.
 
To build and install these libraries, simply enter each of their directories
and run:
$ sudo make install
 
| Note: We advise enabling iconv() support in libparserutils, which vastly
| increases the number of supported character sets. To do this,
| create a file called Makefile.config.override in the libparserutils
| directory, containing the following line:
|
| CFLAGS += -DWITH_ICONV_FILTER
|
| For more information, consult the libparserutils README file.
 
Libharu
---------
 
NetSurf can use Haru PDF to enable PDF export. Haru PDF can be obtained
from http://libharu.org/. We require libharu 2.2 or later.
 
| Note: libharu cannot be auto-detected by the Makefile. If you wish to
| enable it, do so by creating a Makefile.config file.
 
General requirements
----------------------
 
NetSurf requires at minimum GTK 2.12. Earlier versions will not work. It also
depends on Cairo for rendering, but you should have this already with
versions of GTK 2.12 or later.
 
This will pull in loads of things, like all the GTK dev libraries, the PNG
and JPEG libraries, colour management libraries, zlib, OpenSSL etc that
NetSurf also depends on.
/programs/network/netsurf/netsurf/Docs/BUILDING-Monkey
0,0 → 1,104
--------------------------------------------------------------------------------
Build Instructions for Monkey NetSurf 13 March 2011
--------------------------------------------------------------------------------
 
This document provides instructions for building the Monkey
automation version of NetSurf and provides guidance on obtaining
NetSurf's build dependencies.
 
Monkey NetSurf has been tested on Ubuntu 10.10/amd64.
 
 
Building and executing NetSurf
==============================
 
First of all, you should examine the contents of Makefile.defaults
and enable and disable relevant features as you see fit by creating
a Makefile.config file. Some of these options can be automatically
detected and used, and where this is the case they are set to such.
Others cannot be automatically detected from the Makefile, so you
will either need to install the dependencies, or set them to NO.
You should then obtain NetSurf's dependencies, keeping in mind which options
you have enabled in the configuration file. See the next section for
specifics.
Once done, to build Monkey NetSurf on a UNIX-like platform, simply run:
 
$ make TARGET=monkey
 
If that produces errors, you probably don't have some of NetSurf's
build dependencies installed. See "Obtaining NetSurf's dependencies"
below. Or turn off the complaining features in a Makefile.config
file. You may need to "make clean" before attempting to build after
installing the dependencies.
 
Run NetSurf by executing the "nsmonkey" command from within the build tree.
 
$ ./nsmonkey
 
If you are packaging NetSurf, do NOT package nsmonkey. It is a debug tool.
 
 
Obtaining NetSurf's build dependencies
======================================
 
Many of NetSurf's dependencies are packaged on various operating systems.
The remainder must be installed manually. Currently, some of the libraries
developed as part of the NetSurf project have not had official releases.
Hopefully they will soon be released with downloadable tarballs and packaged
in common distros. For now, you'll have to make do with Git checkouts.
 
Some of NetSurf's own libraries will be installed in /usr/local/ by default.
Fedora, and perhaps some other distributions of Linux, do not ship a
pkg-config that will search here, so you will either need to change where
these libraries install, or do the following before building NetSurf itself;
$ PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
$ export PKG_CONFIG_PATH
 
Package installation
----------------------
 
Debian-like OS:
 
$ apt-get install libcurl3-dev
 
Recent OS versions might need libcurl4-dev instead of libcurl3-dev but
note that when it has not been built with OpenSSL, the SSL_CTX is not
available and results that certification details won't be presented in case
they are invalid. But as this is currently unimplemented in the GTK
flavour of NetSurf, this won't make a difference at all.
 
 
The NetSurf project's libraries
-------------------------------
 
The NetSurf project has developed several libraries which are required by
the browser. These are:
 
LibParserUtils -- Parser building utility functions
LibWapcaplet -- String internment
Hubbub -- HTML5 compliant HTML parser
LibCSS -- CSS parser and selection engine
LibNSGIF -- GIF format image decoder
LibNSBMP -- BMP and ICO format image decoder
LibROSprite -- RISC OS Sprite format image decoder
 
To fetch each of these libraries, run the appropriate commands from the
Docs/LIBRARIES file.
 
To build and install these libraries, simply enter each of their directories
and run:
$ sudo make install
 
| Note: We advise enabling iconv() support in libparserutils, which vastly
| increases the number of supported character sets. To do this,
| create a file called Makefile.config.override in the libparserutils
| directory, containing the following line:
|
| CFLAGS += -DWITH_ICONV_FILTER
|
| For more information, consult the libparserutils README file.
 
/programs/network/netsurf/netsurf/Docs/BUILDING-RISC_OS
0,0 → 1,121
--------------------------------------------------------------------------------
Build Instructions for RISC OS NetSurf 16 July 2012
--------------------------------------------------------------------------------
 
This document provides instructions for building the RISC OS NetSurf
natively on a RISC OS computer and provides guidance on obtaining NetSurf's
build dependencies.
 
RISC OS NetSurf should work on RISC OS 4.02 and above.
 
| Note: This guide assumes that you have the RISC OS SVN client installed,
| and that you have used it to fetch the NetSurf source. It also
| assumes that you have the following requirements installed:
|
| + OSLib 6.80 or later
| + Perl 5.8.8 or later
| + GCC 3.4.6 release 3 or later
| + The latest NSTools
 
If you want to cross-compile NetSurf for RISC OS, use the BUILDING-ROCross
document.
 
 
Building and executing NetSurf
================================
 
| Note: The version of make supplied with RISC OS GCC 3 is old and has a bug
| that prevents NetSurf from building. Either ensure that NSTools is
| seen before GCC, or replace the make inside "!GCC.bin" with the make
| from "!NSTools.bin".
| The minimum version of make that works is v3.81. You can check what
| version you have by running, '*make --version'.
 
| Note: The pre-built libraries currently supplied in NSTools are AOF format,
| and will not work with GCC4, which requires them to be in ELF format.
| If you want to build NetSurf with GCC4, you will need to build the
| libraries yourself. See "Obtaining NetSurf's dependencies" below for
| details.
 
You can examine the contents of Makefile.defaults and enable and disable
features as you see fit by creating a Makefile.config file. The default
settings will work fine.
 
You should then obtain NetSurf's dependencies, keeping in mind which options
you have enabled in the configuration file. See the next section for
specifics.
 
Once done, to build RISC OS NetSurf on a RISC OS system, set the CSD to the
directory containing the NetSurf sources, set the next slot to at least
6000K, and in a TaskWindow, simply run:
 
*make
 
If that produces errors, you probably don't have some of NetSurf's build
dependencies installed, or your libraries may be out of date.
See "Obtaining NetSurf's dependencies" below. Or turn off the complaining
features in a Makefile.config file. You may need to "make clean" before
attempting to build after installing the dependencies.
 
Once NetSurf is compiled, the !RunImage is put into the !NetSurf
application directory, so you can simply double click it as normal.
 
To confirm that you're running your own development NetSurf build, view the
Info window from the NetSurf iconbar menu. The Version string should read
 
#.0 (Development)
 
where # is the next major release version number.
 
 
Obtaining NetSurf's build dependencies
========================================
 
NSTools contains all of the tools needed to build NetSurf, such as make,
uname and ccres. It also contains pre-built libraries.
 
Currently NSTools contains libraries which are in a format that are in a
format which is compatible with RISC OS GCC3 but not RISC OS GCC4. Until
NSTools is updated with GCC4 compatible libraries, it is recommended that
you use GCC3 for native builds.
 
The NSTools on the web site is not auto-built, so it may not always have
the latest versions of the NetSurf project's own libraries. In this case
you will need to build the libraries yourself and update your copy of
NSTools.
 
Fetching the sources
----------------------
 
Use SVN to obtain the latest versions of each of the libraries. To do this,
set the CSD to a directory where you want to keep your copies of the library
sources, and run the appropriate commands from the Docs/LIBRARIES file.
 
The above will create a directory for each of the libraries containing their
sources.
 
| Note: We advise enabling iconv() support in libparserutils, which vastly
| increases the number of supported character sets. To do this,
| create a file called Makefile.config.override in the libparserutils
| directory, containing the following line:
|
| CFLAGS += -DWITH_ICONV_FILTER
|
| For more information, consult the libparserutils README file.
 
Updating NSTools' copies of the libraries
-------------------------------------------
 
Set the CSD to the directory of the library you want to build, set your next
slot to at least 6000K and in a TaskWindow, run
 
*svn update
 
This updates your local copy of the source to the latest version. To build
and install the library into NSTools, run:
 
*make install
 
| Note: If you are using GCC3, you may get a warning from AR when you run
| make. This can be ignored.
/programs/network/netsurf/netsurf/Docs/BUILDING-ROCross
0,0 → 1,116
--------------------------------------------------------------------------------
Creating a cross-compilation environment for RISC OS NetSurf
--------------------------------------------------------------------------------
 
| Note: If you want to do a native RISC OS build, on a RISC OS computer,
| consult the BUILDING-RISC_OS file.
 
These instructions assume that you're starting from ~.
They also assume that you've got GCCSDK's prerequisites installed.
 
 
Building the toolchain
========================
 
Run the following commands.
 
$ svn co svn://svn.riscos.info/gccsdk/trunk/ gccsdk
 
$ cd gccsdk/gcc4
 
$ ./build-world
 
$ export GCCSDK_INSTALL_CROSSBIN=/home/riscos/cross/bin
 
$ export GCCSDK_INSTALL_ENV=/home/riscos/env
 
Creating the environment
==========================
 
A. Autobuilder packages
-------------------------
 
$ cd ../
 
$ mkdir build-ab
 
$ cat > build-ab/build-setvars
GCCSDK_INSTALL_CROSSBIN=/home/riscos/cross/bin
GCCSDK_INSTALL_ENV=/home/riscos/env
RO_SHAREDLIBS=no
AB_ELFBUILD=yes
 
$ cd build-ab
 
$ ../autobuilder/build zlib1g
 
$ ../autobuilder/build c-ares
 
$ ../autobuilder/build libssl0.9.8
 
$ ../autobuilder/build libcurl3
 
$ ../autobuilder/build libjpeg62
 
$ ../autobuilder/build liblcms1
 
$ ../autobuilder/build libpng12-0
 
$ ../autobuilder/build libmng1
 
$ ../autobuilder/build oslib
 
B. NetSurf libraries
----------------------
 
Install the NetSirf project's libraries as follows.
 
$ cd ~
 
$ svn co svn://svn.netsurf-browser.org/trunk netsurf
 
$ (cd netsurf/libnsbmp ; make TARGET=riscos install)
 
$ (cd netsurf/libnsgif ; make TARGET=riscos install)
 
$ (cd netsurf/libsvgtiny ; make TARGET=riscos install)
 
$ (cd netsurf/rufl ; make install)
 
$ (cd netsurf/pencil ; make install)
 
$ (cd netsurf/libharu ; make TARGET=riscos PREFIX=$GCCSDK_INSTALL_ENV)
 
$ cd netsurf/libparserutils
 
$ cat >Makefile.config.override
CFLAGS += -DWITH_ICONV_FILTER
 
$ make TARGET=riscos install
 
$ cd ~
 
$ (cd netsurf/hubbub ; make TARGET=riscos install)
 
$ (cd netsurf/libwapcaplet ; make TARGET=riscos install)
 
$ (cd netsurf/libcss ; make TARGET=riscos install)
 
C. Ancilliary tools
---------------------
 
$ svn co svn://svn.riscos.info/ccres/trunk ccres
 
$ (cd ccres ; make install)
 
$ (cd netsurf/tools/makerun ; make install)
 
 
Compiling NetSurf
===================
 
Finally, to cross-compile NetSurf for RISC OS, do the following.
 
$ cd netsurf/netsurf
 
$ make TARGET=riscos
/programs/network/netsurf/netsurf/Docs/BUILDING-Windows
0,0 → 1,203
--------------------------------------------------------------------------------
Build Instructions for Windows NetSurf 13 February 2010
--------------------------------------------------------------------------------
 
This document provides instructions for building the Windows version
of NetSurf and provides guidance on obtaining NetSurf's build
dependencies.
 
Windows NetSurf has been tested on Wine and Vista.
 
 
Building and executing NetSurf
================================
 
The windows netsurf port uses the MinGW (Minimal GNU on Windows)
system as its build infrastructure. This allows the normal netsurf
build process to be used.
 
The method outlined here to create executables cross compiles
windows executable from a Linux OS host.
 
First of all, you should examine the contents of Makefile.defaults
and enable and disable relevant features as you see fit by creating
a Makefile.config file. Some of these options can be automatically
detected and used, and where this is the case they are set to such.
Others cannot be automatically detected from the Makefile, so you
will either need to install the dependencies, or set them to NO.
You should then obtain NetSurf's dependencies, keeping in mind which
options you have enabled in the configuration file. See the next
section for specifics.
Once done, to build windows NetSurf on a UNIX-like platform, simply run:
 
$ export MINGW_PREFIX=i586-mingw32msvc-
$ export MINGW_INSTALL_ENV=/usr/i586-mingw32msvc/
$ make TARGET=windows
 
If that produces errors, you probably don't have some of NetSurf's
build dependencies installed. See "Obtaining NetSurf's dependencies"
below. Or turn off the complaining features in a Makefile.config
file. You may need to "make clean" before attempting to build after
installing the dependencies.
 
You will need the libgnurx-0.dll from /usr/i586-mingw32msvc/bin/
copied next to the exe and the windows/res directory available, also
next to the executable.
 
Run NetSurf by executing it:
 
$ wine NetSurf.exe
 
The staticaly linked binary which is generated may be several
megabytes in size, this can be reduced by stripping the binary.
 
$ i586-mingw32msvc-strip NetSurf.exe
 
 
Obtaining NetSurf's build dependencies
========================================
 
Package installation
----------------------
 
Debian-based OS:
 
The mingw cross compilation tools are required. These can be
installed as pakages on Debian/Ubuntu systems:
 
$ sudo apt-get install mingw32 mingw32-binutils mingw32-runtime
 
These provide a suitable set of compilers and headers including the win32 API.
 
The includes and associated libraries are installed in
/usr/i586-mingw32msvc/ Which is where the build system will include
files from by default. The packages at time of writing only target
32bit windows builds.
 
Other:
 
For other OS the apropriate packages and environment must be installed.
 
pkg-config
------------
 
A pkg-config wrapper script is required to make things easier
 
cat > /usr/i586-mingw32msvc/bin/pkg-config <<EOF
#!/bin/bash
export PKG_CONFIG_LIBDIR=/usr/i586-mingw32msvc/lib/pkgconfig
/usr/bin/pkg-config $*
EOF
 
 
Base libraries
----------------
 
Unlike other OS the base libraries and their dependancies need to be
built and installed.
 
The instructions given here assume you will be installing on a
Debian derived OS using the mingw32 packages. The libraries should
be unpacked and built from a suitable temporary directory.
 
zlib:
$ apt-get source zlib1g
$ cd zlib-1.2.3.3.dfsg
$ CC=i586-mingw32msvc-gcc AR=i586-mingw32msvc-ar RANLIB=i586-mingw32msvc-ranlib CFLAGS="-DNO_FSEEKO" ./configure --prefix=/usr/i586-mingw32msvc/
$ make
$ sudo make install
 
libiconv:
 
$ wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.13.1.tar.gz
$ tar -zxf libiconv-1.13.1.tar.gz
$ cd libiconv-1.13.1
$ ./configure --prefix=/usr/i586-mingw32msvc/ --host=i586-mingw32msvc --disable-shared
$ make
$ sudo make install
 
regex:
 
$ wget http://kent.dl.sourceforge.net/project/mingw/Other/UserContributed/regex/mingw-regex-2.5.1/mingw-libgnurx-2.5.1-src.tar.gz
$ tar -zxf mingw-libgnurx-2.5.1-src.tar.gz
$ cd mingw-libgnurx-2.5.1
$ ./configure --prefix=/usr/i586-mingw32msvc/ --host=i586-mingw32msvc
$ make
$ sudo make install
 
openssl:
 
$ wget http://www.openssl.org/source/openssl-1.0.0a.tar.gz
$ tar -zxf openssl-1.0.0a.tar.gz
$ cd openssl-1.0.0a
$ PATH=/usr/i586-mingw32msvc/bin/:$PATH ./Configure no-shared disable-capieng --prefix=/usr/i586-mingw32msvc/ mingw
$ PATH=/usr/i586-mingw32msvc/bin/:$PATH make CC=i586-mingw32msvc-gcc RANLIB=i586-mingw32msvc-ranlib
$ sudo make install
 
libcurl:
 
$ wget http://curl.haxx.se/download/curl-7.26.0.tar.gz
$ tar -zxf curl-7.26.0.tar.gz
$ cd curl-7.26.0
$ LDFLAGS=-mwindows ./configure --prefix=/usr/i586-mingw32msvc/ --host=i586-mingw32msvc --disable-shared --disable-ldap --without-random
$ make
$ sudo make install
 
libpng:
 
$ wget http://kent.dl.sourceforge.net/project/libpng/libpng14/1.4.12/libpng-1.4.12.tar.gz
$ tar -zxf libpng-1.4.12.tar.gz
$ cd libpng-1.4.12
$ ./configure --prefix=/usr/i586-mingw32msvc/ --host=i586-mingw32msvc
$ make
$ sudo make install
 
libjpeg:
 
$ wget http://www.ijg.org/files/jpegsrc.v8d.tar.gz
$ tar -zxf jpegsrc.v8d.tar.gz
$ cd jpeg-8d
$ ./configure --prefix=/usr/i586-mingw32msvc/ --host=i586-mingw32msvc --disable-shared
$ make
$ sudo make install
 
The NetSurf project's libraries
---------------------------------
 
The NetSurf project has developed several libraries which are required by
the browser. These are:
 
LibParserUtils -- Parser building utility functions
LibWapcaplet -- String internment
Hubbub -- HTML5 compliant HTML parser
LibCSS -- CSS parser and selection engine
LibNSGIF -- GIF format image decoder
LibNSBMP -- BMP and ICO format image decoder
LibROSprite -- RISC OS Sprite format image decoder
 
To fetch each of these libraries, run the appropriate commands from the
Docs/LIBRARIES file.
 
To build and install these libraries.
 
Ensure the MINGW_INSTALL_ENV variable is correctly set.
 
$ export MINGW_INSTALL_ENV=/usr/i586-mingw32msvc/
 
Then simply enter each of their directories and run:
$ make TARGET=windows PREFIX=/usr/i586-mingw32msvc/
$ sudo make TARGET=windows PREFIX=/usr/i586-mingw32msvc/ install
 
Resources
-----------
 
The windows resources may be rebuilt. Currently there is 1 object
file included in the Git distribution of NetSurf that could be
manually compiled
 
$ cd windows/res
$ i586-mingw32msvc-windres resource.rc -O coff -o resource.o
/programs/network/netsurf/netsurf/Docs/Doxyfile
0,0 → 1,1828
# Doxyfile 1.8.1.1
 
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
#
# All text after a hash (#) is considered a comment and will be ignored.
# The format is:
# TAG = value [value, ...]
# For lists items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (" ").
 
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
 
# This tag specifies the encoding used for all characters in the config file
# that follow. The default is UTF-8 which is also the encoding used for all
# text before the first occurrence of this tag. Doxygen uses libiconv (or the
# iconv built into libc) for the transcoding. See
# http://www.gnu.org/software/libiconv for the list of possible encodings.
 
DOXYFILE_ENCODING = UTF-8
 
# The PROJECT_NAME tag is a single word (or sequence of words) that should
# identify the project. Note that if you do not use Doxywizard you need
# to put quotes around the project name if it contains spaces.
 
PROJECT_NAME = NetSurf
 
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
# if some version control system is used.
 
PROJECT_NUMBER =
 
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
# a quick idea about the purpose of the project. Keep the description short.
 
PROJECT_BRIEF =
 
# With the PROJECT_LOGO tag one can specify an logo or icon that is
# included in the documentation. The maximum height of the logo should not
# exceed 55 pixels and the maximum width should not exceed 200 pixels.
# Doxygen will copy the logo to the output directory.
 
PROJECT_LOGO =
 
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
 
OUTPUT_DIRECTORY =
 
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
# 4096 sub-directories (in 2 levels) under the output directory of each output
# format and will distribute the generated files over these directories.
# Enabling this option can be useful when feeding doxygen a huge amount of
# source files, where putting all generated files in the same directory would
# otherwise cause performance problems for the file system.
 
CREATE_SUBDIRS = NO
 
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# The default language is English, other supported languages are:
# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
 
OUTPUT_LANGUAGE = English
 
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
# include brief member descriptions after the members that are listed in
# the file and class documentation (similar to JavaDoc).
# Set to NO to disable this.
 
BRIEF_MEMBER_DESC = YES
 
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
# the brief description of a member or function before the detailed description.
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
 
REPEAT_BRIEF = YES
 
# This tag implements a quasi-intelligent brief description abbreviator
# that is used to form the text in various listings. Each string
# in this list, if found as the leading text of the brief description, will be
# stripped from the text and the result after processing the whole list, is
# used as the annotated text. Otherwise, the brief description is used as-is.
# If left blank, the following values are used ("$name" is automatically
# replaced with the name of the entity): "The $name class" "The $name widget"
# "The $name file" "is" "provides" "specifies" "contains"
# "represents" "a" "an" "the"
 
ABBREVIATE_BRIEF =
 
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# Doxygen will generate a detailed section even if there is only a brief
# description.
 
ALWAYS_DETAILED_SEC = NO
 
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
# inherited members of a class in the documentation of that class as if those
# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
 
INLINE_INHERITED_MEMB = NO
 
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
# path before files name in the file list and in the header files. If set
# to NO the shortest path that makes the file name unique will be used.
 
FULL_PATH_NAMES = YES
 
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
# can be used to strip a user-defined part of the path. Stripping is
# only done if one of the specified strings matches the left-hand part of
# the path. The tag can be used to show relative paths in the file list.
# If left blank the directory from which doxygen is run is used as the
# path to strip.
 
STRIP_FROM_PATH =
 
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
# the path mentioned in the documentation of a class, which tells
# the reader which header file to include in order to use a class.
# If left blank only the name of the header file containing the class
# definition is used. Otherwise one should specify the include paths that
# are normally passed to the compiler using the -I flag.
 
STRIP_FROM_INC_PATH =
 
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
# (but less readable) file names. This can be useful if your file system
# doesn't support long names like on DOS, Mac, or CD-ROM.
 
SHORT_NAMES = NO
 
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
# will interpret the first line (until the first dot) of a JavaDoc-style
# comment as the brief description. If set to NO, the JavaDoc
# comments will behave just like regular Qt-style comments
# (thus requiring an explicit @brief command for a brief description.)
 
JAVADOC_AUTOBRIEF = YES
 
# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
# interpret the first line (until the first dot) of a Qt-style
# comment as the brief description. If set to NO, the comments
# will behave just like regular Qt-style comments (thus requiring
# an explicit \brief command for a brief description.)
 
QT_AUTOBRIEF = NO
 
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
# treat a multi-line C++ special comment block (i.e. a block of //! or ///
# comments) as a brief description. This used to be the default behaviour.
# The new default is to treat a multi-line C++ comment block as a detailed
# description. Set this tag to YES if you prefer the old behaviour instead.
 
MULTILINE_CPP_IS_BRIEF = NO
 
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
# member inherits the documentation from any documented member that it
# re-implements.
 
INHERIT_DOCS = YES
 
# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
# a new page for each member. If set to NO, the documentation of a member will
# be part of the file/class/namespace that contains it.
 
SEPARATE_MEMBER_PAGES = NO
 
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
# Doxygen uses this value to replace tabs by spaces in code fragments.
 
TAB_SIZE = 8
 
# This tag can be used to specify a number of aliases that acts
# as commands in the documentation. An alias has the form "name=value".
# For example adding "sideeffect=\par Side Effects:\n" will allow you to
# put the command \sideeffect (or @sideeffect) in the documentation, which
# will result in a user-defined paragraph with heading "Side Effects:".
# You can put \n's in the value part of an alias to insert newlines.
 
ALIASES =
 
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding
# "class=itcl::class" will allow you to use the command class in the
# itcl::class meaning.
 
TCL_SUBST =
 
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
# sources only. Doxygen will then generate output that is more tailored for C.
# For instance, some of the names that are used will be different. The list
# of all members will be omitted, etc.
 
OPTIMIZE_OUTPUT_FOR_C = YES
 
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
# sources only. Doxygen will then generate output that is more tailored for
# Java. For instance, namespaces will be presented as packages, qualified
# scopes will look different, etc.
 
OPTIMIZE_OUTPUT_JAVA = NO
 
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
# sources only. Doxygen will then generate output that is more tailored for
# Fortran.
 
OPTIMIZE_FOR_FORTRAN = NO
 
# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
# sources. Doxygen will then generate output that is tailored for
# VHDL.
 
OPTIMIZE_OUTPUT_VHDL = NO
 
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given extension.
# Doxygen has a built-in mapping, but you can override or extend it using this
# tag. The format is ext=language, where ext is a file extension, and language
# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
 
EXTENSION_MAPPING =
 
# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
# comments according to the Markdown format, which allows for more readable
# documentation. See http://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you
# can mix doxygen, HTML, and XML commands with Markdown formatting.
# Disable only in case of backward compatibilities issues.
 
MARKDOWN_SUPPORT = YES
 
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should
# set this tag to YES in order to let doxygen match functions declarations and
# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
# func(std::string) {}). This also makes the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
 
BUILTIN_STL_SUPPORT = NO
 
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
 
CPP_CLI_SUPPORT = NO
 
# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
# Doxygen will parse them like normal C++ but will assume all classes use public
# instead of private inheritance when no explicit protection keyword is present.
 
SIP_SUPPORT = NO
 
# For Microsoft's IDL there are propget and propput attributes to indicate getter
# and setter methods for a property. Setting this option to YES (the default)
# will make doxygen replace the get and set methods by a property in the
# documentation. This will only work if the methods are indeed getting or
# setting a simple type. If this is not the case, or you want to show the
# methods anyway, you should set this option to NO.
 
IDL_PROPERTY_SUPPORT = YES
 
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES, then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
 
DISTRIBUTE_GROUP_DOC = NO
 
# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
# the same type (for instance a group of public functions) to be put as a
# subgroup of that type (e.g. under the Public Functions section). Set it to
# NO to prevent subgrouping. Alternatively, this can be done per class using
# the \nosubgrouping command.
 
SUBGROUPING = YES
 
# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
# unions are shown inside the group in which they are included (e.g. using
# @ingroup) instead of on a separate page (for HTML and Man pages) or
# section (for LaTeX and RTF).
 
INLINE_GROUPED_CLASSES = NO
 
# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
# unions with only public data fields will be shown inline in the documentation
# of the scope in which they are defined (i.e. file, namespace, or group
# documentation), provided this scope is documented. If set to NO (the default),
# structs, classes, and unions are shown on a separate page (for HTML and Man
# pages) or section (for LaTeX and RTF).
 
INLINE_SIMPLE_STRUCTS = NO
 
# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
# is documented as struct, union, or enum with the name of the typedef. So
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
# with name TypeT. When disabled the typedef will appear as a member of a file,
# namespace, or class. And the struct will be named TypeS. This can typically
# be useful for C code in case the coding convention dictates that all compound
# types are typedef'ed and only the typedef is referenced, never the tag name.
 
TYPEDEF_HIDES_STRUCT = NO
 
# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
# determine which symbols to keep in memory and which to flush to disk.
# When the cache is full, less often used symbols will be written to disk.
# For small to medium size projects (<1000 input files) the default value is
# probably good enough. For larger projects a too small cache size can cause
# doxygen to be busy swapping symbols to and from disk most of the time
# causing a significant performance penalty.
# If the system has enough physical memory increasing the cache will improve the
# performance by keeping more symbols in memory. Note that the value works on
# a logarithmic scale so increasing the size by one will roughly double the
# memory usage. The cache size is given by this formula:
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
# corresponding to a cache size of 2^16 = 65536 symbols.
 
SYMBOL_CACHE_SIZE = 0
 
# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
# their name and scope. Since this can be an expensive process and often the
# same symbol appear multiple times in the code, doxygen keeps a cache of
# pre-resolved symbols. If the cache is too small doxygen will become slower.
# If the cache is too large, memory is wasted. The cache size is given by this
# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
# corresponding to a cache size of 2^16 = 65536 symbols.
 
LOOKUP_CACHE_SIZE = 0
 
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
 
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# documentation are documented, even if no documentation was available.
# Private class members and static file members will be hidden unless
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
 
EXTRACT_ALL = YES
 
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
 
EXTRACT_PRIVATE = YES
 
# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation.
 
EXTRACT_PACKAGE = NO
 
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
 
EXTRACT_STATIC = YES
 
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
# defined locally in source files will be included in the documentation.
# If set to NO only classes defined in header files are included.
 
EXTRACT_LOCAL_CLASSES = YES
 
# This flag is only useful for Objective-C code. When set to YES local
# methods, which are defined in the implementation section but not in
# the interface are included in the documentation.
# If set to NO (the default) only methods in the interface are included.
 
EXTRACT_LOCAL_METHODS = NO
 
# If this flag is set to YES, the members of anonymous namespaces will be
# extracted and appear in the documentation as a namespace called
# 'anonymous_namespace{file}', where file will be replaced with the base
# name of the file that contains the anonymous namespace. By default
# anonymous namespaces are hidden.
 
EXTRACT_ANON_NSPACES = NO
 
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
# undocumented members of documented classes, files or namespaces.
# If set to NO (the default) these members will be included in the
# various overviews, but no documentation section is generated.
# This option has no effect if EXTRACT_ALL is enabled.
 
HIDE_UNDOC_MEMBERS = NO
 
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy.
# If set to NO (the default) these classes will be included in the various
# overviews. This option has no effect if EXTRACT_ALL is enabled.
 
HIDE_UNDOC_CLASSES = NO
 
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
# friend (class|struct|union) declarations.
# If set to NO (the default) these declarations will be included in the
# documentation.
 
HIDE_FRIEND_COMPOUNDS = NO
 
# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
# documentation blocks found inside the body of a function.
# If set to NO (the default) these blocks will be appended to the
# function's detailed documentation block.
 
HIDE_IN_BODY_DOCS = NO
 
# The INTERNAL_DOCS tag determines if documentation
# that is typed after a \internal command is included. If the tag is set
# to NO (the default) then the documentation will be excluded.
# Set it to YES to include the internal documentation.
 
INTERNAL_DOCS = NO
 
# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
# file names in lower-case letters. If set to YES upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
 
CASE_SENSE_NAMES = YES
 
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
# will show members with their full class and namespace scopes in the
# documentation. If set to YES the scope will be hidden.
 
HIDE_SCOPE_NAMES = NO
 
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put a list of the files that are included by a file in the documentation
# of that file.
 
SHOW_INCLUDE_FILES = YES
 
# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
# will list include files with double quotes in the documentation
# rather than with sharp brackets.
 
FORCE_LOCAL_INCLUDES = NO
 
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
# is inserted in the documentation for inline members.
 
INLINE_INFO = YES
 
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
# will sort the (detailed) documentation of file and class members
# alphabetically by member name. If set to NO the members will appear in
# declaration order.
 
SORT_MEMBER_DOCS = YES
 
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
# brief documentation of file, namespace and class members alphabetically
# by member name. If set to NO (the default) the members will appear in
# declaration order.
 
SORT_BRIEF_DOCS = NO
 
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
# will sort the (brief and detailed) documentation of class members so that
# constructors and destructors are listed first. If set to NO (the default)
# the constructors will appear in the respective orders defined by
# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
 
SORT_MEMBERS_CTORS_1ST = NO
 
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
# hierarchy of group names into alphabetical order. If set to NO (the default)
# the group names will appear in their defined order.
 
SORT_GROUP_NAMES = NO
 
# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
# sorted by fully-qualified names, including namespaces. If set to
# NO (the default), the class list will be sorted only by class name,
# not including the namespace part.
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
# Note: This option applies only to the class list, not to the
# alphabetical list.
 
SORT_BY_SCOPE_NAME = NO
 
# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
# do proper type resolution of all parameters of a function it will reject a
# match between the prototype and the implementation of a member function even
# if there is only one candidate or it is obvious which candidate to choose
# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
# will still accept a match between prototype and implementation in such cases.
 
STRICT_PROTO_MATCHING = NO
 
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
# commands in the documentation.
 
GENERATE_TODOLIST = YES
 
# The GENERATE_TESTLIST tag can be used to enable (YES) or
# disable (NO) the test list. This list is created by putting \test
# commands in the documentation.
 
GENERATE_TESTLIST = YES
 
# The GENERATE_BUGLIST tag can be used to enable (YES) or
# disable (NO) the bug list. This list is created by putting \bug
# commands in the documentation.
 
GENERATE_BUGLIST = YES
 
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
# disable (NO) the deprecated list. This list is created by putting
# \deprecated commands in the documentation.
 
GENERATE_DEPRECATEDLIST= YES
 
# The ENABLED_SECTIONS tag can be used to enable conditional
# documentation sections, marked by \if sectionname ... \endif.
 
ENABLED_SECTIONS =
 
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
# the initial value of a variable or macro consists of for it to appear in
# the documentation. If the initializer consists of more lines than specified
# here it will be hidden. Use a value of 0 to hide initializers completely.
# The appearance of the initializer of individual variables and macros in the
# documentation can be controlled using \showinitializer or \hideinitializer
# command in the documentation regardless of this setting.
 
MAX_INITIALIZER_LINES = 30
 
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
# at the bottom of the documentation of classes and structs. If set to YES the
# list will mention the files that were used to generate the documentation.
 
SHOW_USED_FILES = YES
 
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
# This will remove the Files entry from the Quick Index and from the
# Folder Tree View (if specified). The default is YES.
 
SHOW_FILES = YES
 
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
# Namespaces page.
# This will remove the Namespaces entry from the Quick Index
# and from the Folder Tree View (if specified). The default is YES.
 
SHOW_NAMESPACES = YES
 
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
# the version control system). Doxygen will invoke the program by executing (via
# popen()) the command <command> <input-file>, where <command> is the value of
# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
# provided by doxygen. Whatever the program writes to standard output
# is used as the file version. See the manual for examples.
 
FILE_VERSION_FILTER =
 
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
# by doxygen. The layout file controls the global structure of the generated
# output files in an output format independent way. To create the layout file
# that represents doxygen's defaults, run doxygen with the -l option.
# You can optionally specify a file name after the option, if omitted
# DoxygenLayout.xml will be used as the name of the layout file.
 
LAYOUT_FILE =
 
# The CITE_BIB_FILES tag can be used to specify one or more bib files
# containing the references data. This must be a list of .bib files. The
# .bib extension is automatically appended if omitted. Using this command
# requires the bibtex tool to be installed. See also
# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
# feature you need bibtex and perl available in the search path.
 
CITE_BIB_FILES =
 
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
 
# The QUIET tag can be used to turn on/off the messages that are generated
# by doxygen. Possible values are YES and NO. If left blank NO is used.
 
QUIET = NO
 
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated by doxygen. Possible values are YES and NO. If left blank
# NO is used.
 
WARNINGS = YES
 
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
# automatically be disabled.
 
WARN_IF_UNDOCUMENTED = YES
 
# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
# potential errors in the documentation, such as not documenting some
# parameters in a documented function, or documenting parameters that
# don't exist or using markup commands wrongly.
 
WARN_IF_DOC_ERROR = YES
 
# The WARN_NO_PARAMDOC option can be enabled to get warnings for
# functions that are documented, but have no documentation for their parameters
# or return value. If set to NO (the default) doxygen will only warn about
# wrong or incomplete parameter documentation, but not about the absence of
# documentation.
 
WARN_NO_PARAMDOC = YES
 
# The WARN_FORMAT tag determines the format of the warning messages that
# doxygen can produce. The string should contain the $file, $line, and $text
# tags, which will be replaced by the file and line number from which the
# warning originated and the warning text. Optionally the format may contain
# $version, which will be replaced by the version of the file (if it could
# be obtained via FILE_VERSION_FILTER)
 
WARN_FORMAT = "$file:$line: $text"
 
# The WARN_LOGFILE tag can be used to specify a file to which warning
# and error messages should be written. If left blank the output is written
# to stderr.
 
WARN_LOGFILE =
 
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
 
# The INPUT tag can be used to specify the files and/or directories that contain
# documented source files. You may enter file names like "myfile.cpp" or
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
 
INPUT = windows \
atari \
atari/plot \
gtk \
gtk/dialogs \
css \
cocoa \
monkey \
render \
desktop \
desktop/save_pdf \
amiga \
amiga/stringview \
content \
content/fetchers \
framebuffer \
framebuffer/fbtk \
riscos \
riscos/configure \
riscos/gui \
riscos/content-handlers \
riscos/templates \
riscos/scripts \
beos \
javascript \
javascript/jsapi \
utils \
utils/http
 
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
# also the default input encoding. Doxygen uses libiconv (or the iconv built
# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
# the list of possible encodings.
 
INPUT_ENCODING = UTF-8
 
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank the following patterns are tested:
# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
# *.f90 *.f *.for *.vhd *.vhdl
 
FILE_PATTERNS = *.c \
*.h \
*.y \
*.l
 
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
# If left blank NO is used.
 
RECURSIVE = NO
 
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
# Note that relative paths are relative to the directory from which doxygen is
# run.
 
EXCLUDE = css/css_enum.c \
css/css_enum.h \
css/parser.c \
css/parser.h \
css/scanner.c \
css/scanner.h
 
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
 
EXCLUDE_SYMLINKS = NO
 
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
# certain files from those directories. Note that the wildcards are matched
# against the file with absolute path, so to exclude all test directories
# for example use the pattern */test/*
 
EXCLUDE_PATTERNS =
 
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
 
EXCLUDE_SYMBOLS =
 
# The EXAMPLE_PATH tag can be used to specify one or more files or
# directories that contain example code fragments that are included (see
# the \include command).
 
EXAMPLE_PATH =
 
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank all files are included.
 
EXAMPLE_PATTERNS =
 
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
# searched for input files to be used with the \include or \dontinclude
# commands irrespective of the value of the RECURSIVE tag.
# Possible values are YES and NO. If left blank NO is used.
 
EXAMPLE_RECURSIVE = NO
 
# The IMAGE_PATH tag can be used to specify one or more files or
# directories that contain image that are included in the documentation (see
# the \image command).
 
IMAGE_PATH =
 
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
# by executing (via popen()) the command <filter> <input-file>, where <filter>
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
# input file. Doxygen will then use the output that the filter program writes
# to standard output.
# If FILTER_PATTERNS is specified, this tag will be
# ignored.
 
INPUT_FILTER =
 
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis.
# Doxygen will compare the file name with each pattern and apply the
# filter if there is a match.
# The filters are a list of the form:
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
# info on how filters are used. If FILTER_PATTERNS is empty or if
# non of the patterns match the file name, INPUT_FILTER is applied.
 
FILTER_PATTERNS =
 
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will be used to filter the input files when producing source
# files to browse (i.e. when SOURCE_BROWSER is set to YES).
 
FILTER_SOURCE_FILES = NO
 
# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
# and it is also possible to disable source filtering for a specific pattern
# using *.ext= (so without naming a filter). This option only has effect when
# FILTER_SOURCE_FILES is enabled.
 
FILTER_SOURCE_PATTERNS =
 
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
 
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
# be generated. Documented entities will be cross-referenced with these sources.
# Note: To get rid of all source code in the generated output, make sure also
# VERBATIM_HEADERS is set to NO.
 
SOURCE_BROWSER = YES
 
# Setting the INLINE_SOURCES tag to YES will include the body
# of functions and classes directly in the documentation.
 
INLINE_SOURCES = NO
 
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
# doxygen to hide any special comment blocks from generated source code
# fragments. Normal C, C++ and Fortran comments will always remain visible.
 
STRIP_CODE_COMMENTS = NO
 
# If the REFERENCED_BY_RELATION tag is set to YES
# then for each documented function all documented
# functions referencing it will be listed.
 
REFERENCED_BY_RELATION = YES
 
# If the REFERENCES_RELATION tag is set to YES
# then for each documented function all documented entities
# called/used by that function will be listed.
 
REFERENCES_RELATION = YES
 
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
# link to the source code.
# Otherwise they will link to the documentation.
 
REFERENCES_LINK_SOURCE = YES
 
# If the USE_HTAGS tag is set to YES then the references to source code
# will point to the HTML generated by the htags(1) tool instead of doxygen
# built-in source browser. The htags tool is part of GNU's global source
# tagging system (see http://www.gnu.org/software/global/global.html). You
# will need version 4.8.6 or higher.
 
USE_HTAGS = NO
 
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
# will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
 
VERBATIM_HEADERS = YES
 
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
 
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
# of all compounds will be generated. Enable this if the project
# contains a lot of classes, structs, unions or interfaces.
 
ALPHABETICAL_INDEX = NO
 
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
# in which this list will be split (can be a number in the range [1..20])
 
COLS_IN_ALPHA_INDEX = 5
 
# In case all classes in a project start with a common prefix, all
# classes will be put under the same header in the alphabetical index.
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
# should be ignored while generating the index headers.
 
IGNORE_PREFIX =
 
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
 
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
# generate HTML output.
 
GENERATE_HTML = YES
 
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `html' will be used as the default path.
 
HTML_OUTPUT = codedocs
 
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
# doxygen will generate files with .html extension.
 
HTML_FILE_EXTENSION = .html
 
# The HTML_HEADER tag can be used to specify a personal HTML header for
# each generated HTML page. If it is left blank doxygen will generate a
# standard header. Note that when using a custom header you are responsible
# for the proper inclusion of any scripts and style sheets that doxygen
# needs, which is dependent on the configuration options used.
# It is advised to generate a default header using "doxygen -w html
# header.html footer.html stylesheet.css YourConfigFile" and then modify
# that header. Note that the header is subject to change so you typically
# have to redo this when upgrading to a newer version of doxygen or when
# changing the value of configuration settings such as GENERATE_TREEVIEW!
 
HTML_HEADER =
 
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
# each generated HTML page. If it is left blank doxygen will generate a
# standard footer.
 
HTML_FOOTER =
 
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
# style sheet that is used by each HTML page. It can be used to
# fine-tune the look of the HTML output. If the tag is left blank doxygen
# will generate a default style sheet. Note that doxygen will try to copy
# the style sheet file to the HTML output directory, so don't put your own
# style sheet in the HTML output directory as well, or it will be erased!
 
HTML_STYLESHEET =
 
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note
# that these files will be copied to the base HTML output directory. Use the
# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
# files. In the HTML_STYLESHEET file, use the file name only. Also note that
# the files will be copied as-is; there are no commands or markers available.
 
HTML_EXTRA_FILES =
 
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
# Doxygen will adjust the colors in the style sheet and background images
# according to this color. Hue is specified as an angle on a colorwheel,
# see http://en.wikipedia.org/wiki/Hue for more information.
# For instance the value 0 represents red, 60 is yellow, 120 is green,
# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
# The allowed range is 0 to 359.
 
HTML_COLORSTYLE_HUE = 220
 
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
# the colors in the HTML output. For a value of 0 the output will use
# grayscales only. A value of 255 will produce the most vivid colors.
 
HTML_COLORSTYLE_SAT = 100
 
# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
# the luminance component of the colors in the HTML output. Values below
# 100 gradually make the output lighter, whereas values above 100 make
# the output darker. The value divided by 100 is the actual gamma applied,
# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
# and 100 does not change the gamma.
 
HTML_COLORSTYLE_GAMMA = 80
 
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting
# this to NO can help when comparing the output of multiple runs.
 
HTML_TIMESTAMP = YES
 
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
 
HTML_DYNAMIC_SECTIONS = NO
 
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
# entries shown in the various tree structured indices initially; the user
# can expand and collapse entries dynamically later on. Doxygen will expand
# the tree to such a level that at most the specified number of entries are
# visible (unless a fully collapsed tree already exceeds this amount).
# So setting the number of entries 1 will produce a full collapsed tree by
# default. 0 is a special value representing an infinite number of entries
# and will result in a full expanded tree by default.
 
HTML_INDEX_NUM_ENTRIES = 100
 
# If the GENERATE_DOCSET tag is set to YES, additional index files
# will be generated that can be used as input for Apple's Xcode 3
# integrated development environment, introduced with OSX 10.5 (Leopard).
# To create a documentation set, doxygen will generate a Makefile in the
# HTML output directory. Running make will produce the docset in that
# directory and running "make install" will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
# it at startup.
# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
 
GENERATE_DOCSET = NO
 
# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
# feed. A documentation feed provides an umbrella under which multiple
# documentation sets from a single provider (such as a company or product suite)
# can be grouped.
 
DOCSET_FEEDNAME = "Doxygen generated docs"
 
# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
# should uniquely identify the documentation set bundle. This should be a
# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
# will append .docset to the name.
 
DOCSET_BUNDLE_ID = org.doxygen.Project
 
# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
# the documentation publisher. This should be a reverse domain-name style
# string, e.g. com.mycompany.MyDocSet.documentation.
 
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
 
# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
 
DOCSET_PUBLISHER_NAME = Publisher
 
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
# of the generated HTML documentation.
 
GENERATE_HTMLHELP = NO
 
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
# be used to specify the file name of the resulting .chm file. You
# can add a path in front of the file if the result should not be
# written to the html output directory.
 
CHM_FILE =
 
# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
# be used to specify the location (absolute path including file name) of
# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
# the HTML help compiler on the generated index.hhp.
 
HHC_LOCATION =
 
# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
# controls if a separate .chi index file is generated (YES) or that
# it should be included in the master .chm file (NO).
 
GENERATE_CHI = NO
 
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
# is used to encode HtmlHelp index (hhk), content (hhc) and project file
# content.
 
CHM_INDEX_ENCODING =
 
# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
# controls whether a binary table of contents is generated (YES) or a
# normal table of contents (NO) in the .chm file.
 
BINARY_TOC = NO
 
# The TOC_EXPAND flag can be set to YES to add extra items for group members
# to the contents of the HTML help documentation and to the tree view.
 
TOC_EXPAND = NO
 
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
# that can be used as input for Qt's qhelpgenerator to generate a
# Qt Compressed Help (.qch) of the generated HTML documentation.
 
GENERATE_QHP = NO
 
# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
# be used to specify the file name of the resulting .qch file.
# The path specified is relative to the HTML output folder.
 
QCH_FILE =
 
# The QHP_NAMESPACE tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#namespace
 
QHP_NAMESPACE = org.doxygen.Project
 
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#virtual-folders
 
QHP_VIRTUAL_FOLDER = doc
 
# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
# add. For more information please see
# http://doc.trolltech.com/qthelpproject.html#custom-filters
 
QHP_CUST_FILTER_NAME =
 
# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see
# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
# Qt Help Project / Custom Filters</a>.
 
QHP_CUST_FILTER_ATTRS =
 
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's
# filter section matches.
# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
# Qt Help Project / Filter Attributes</a>.
 
QHP_SECT_FILTER_ATTRS =
 
# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
# be used to specify the location of Qt's qhelpgenerator.
# If non-empty doxygen will try to run qhelpgenerator on the generated
# .qhp file.
 
QHG_LOCATION =
 
# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
# will be generated, which together with the HTML files, form an Eclipse help
# plugin. To install this plugin and make it available under the help contents
# menu in Eclipse, the contents of the directory containing the HTML and XML
# files needs to be copied into the plugins directory of eclipse. The name of
# the directory within the plugins directory should be the same as
# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
# the help appears.
 
GENERATE_ECLIPSEHELP = NO
 
# A unique identifier for the eclipse help plugin. When installing the plugin
# the directory name containing the HTML and XML files should also have
# this name.
 
ECLIPSE_DOC_ID = org.doxygen.Project
 
# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
# at top of each HTML page. The value NO (the default) enables the index and
# the value YES disables it. Since the tabs have the same information as the
# navigation tree you can set this option to NO if you already set
# GENERATE_TREEVIEW to YES.
 
DISABLE_INDEX = NO
 
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information.
# If the tag value is set to YES, a side panel will be generated
# containing a tree-like index structure (just like the one that
# is generated for HTML Help). For this to work a browser that supports
# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
# Windows users are probably better off using the HTML help feature.
# Since the tree basically has the same information as the tab index you
# could consider to set DISABLE_INDEX to NO when enabling this option.
 
GENERATE_TREEVIEW = NO
 
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
# (range [0,1..20]) that doxygen will group on one line in the generated HTML
# documentation. Note that a value of 0 will completely suppress the enum
# values from appearing in the overview section.
 
ENUM_VALUES_PER_LINE = 4
 
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
# used to set the initial width (in pixels) of the frame in which the tree
# is shown.
 
TREEVIEW_WIDTH = 250
 
# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
# links to external symbols imported via tag files in a separate window.
 
EXT_LINKS_IN_WINDOW = NO
 
# Use this tag to change the font size of Latex formulas included
# as images in the HTML documentation. The default is 10. Note that
# when you change the font size after a successful doxygen run you need
# to manually remove any form_*.png images from the HTML output directory
# to force them to be regenerated.
 
FORMULA_FONTSIZE = 10
 
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are
# not supported properly for IE 6.0, but are supported on all modern browsers.
# Note that when changing this option you need to delete any form_*.png files
# in the HTML output before the changes have effect.
 
FORMULA_TRANSPARENT = YES
 
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
# (see http://www.mathjax.org) which uses client side Javascript for the
# rendering instead of using prerendered bitmaps. Use this if you do not
# have LaTeX installed or if you want to formulas look prettier in the HTML
# output. When enabled you may also need to install MathJax separately and
# configure the path to it using the MATHJAX_RELPATH option.
 
USE_MATHJAX = NO
 
# When MathJax is enabled you need to specify the location relative to the
# HTML output directory using the MATHJAX_RELPATH option. The destination
# directory should contain the MathJax.js script. For instance, if the mathjax
# directory is located at the same level as the HTML output directory, then
# MATHJAX_RELPATH should be ../mathjax. The default value points to
# the MathJax Content Delivery Network so you can quickly see the result without
# installing MathJax.
# However, it is strongly recommended to install a local
# copy of MathJax from http://www.mathjax.org before deployment.
 
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
 
# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
# names that should be enabled during MathJax rendering.
 
MATHJAX_EXTENSIONS =
 
# When the SEARCHENGINE tag is enabled doxygen will generate a search box
# for the HTML output. The underlying search engine uses javascript
# and DHTML and should work on any modern browser. Note that when using
# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
# (GENERATE_DOCSET) there is already a search function so this one should
# typically be disabled. For large projects the javascript based search engine
# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
 
SEARCHENGINE = NO
 
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a PHP enabled web server instead of at the web client
# using Javascript. Doxygen will generate the search PHP script and index
# file to put on the web server. The advantage of the server
# based approach is that it scales better to large projects and allows
# full text search. The disadvantages are that it is more difficult to setup
# and does not have live searching capabilities.
 
SERVER_BASED_SEARCH = NO
 
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
 
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
# generate Latex output.
 
GENERATE_LATEX = NO
 
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `latex' will be used as the default path.
 
LATEX_OUTPUT = latex
 
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked. If left blank `latex' will be used as the default command name.
# Note that when enabling USE_PDFLATEX this option is only used for
# generating bitmaps for formulas in the HTML output, but not in the
# Makefile that is written to the output directory.
 
LATEX_CMD_NAME = latex
 
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
# generate index for LaTeX. If left blank `makeindex' will be used as the
# default command name.
 
MAKEINDEX_CMD_NAME = makeindex
 
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
# LaTeX documents. This may be useful for small projects and may help to
# save some trees in general.
 
COMPACT_LATEX = NO
 
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, letter, legal and
# executive. If left blank a4wide will be used.
 
PAPER_TYPE = a4wide
 
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
 
EXTRA_PACKAGES =
 
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
# the generated latex document. The header should contain everything until
# the first chapter. If it is left blank doxygen will generate a
# standard header. Notice: only use this tag if you know what you are doing!
 
LATEX_HEADER =
 
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
# the generated latex document. The footer should contain everything after
# the last chapter. If it is left blank doxygen will generate a
# standard footer. Notice: only use this tag if you know what you are doing!
 
LATEX_FOOTER =
 
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
# contain links (just like the HTML output) instead of page references
# This makes the output suitable for online browsing using a pdf viewer.
 
PDF_HYPERLINKS = NO
 
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
# plain latex in the generated Makefile. Set this option to YES to get a
# higher quality PDF documentation.
 
USE_PDFLATEX = NO
 
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
# command to the generated LaTeX files. This will instruct LaTeX to keep
# running if errors occur, instead of asking the user for help.
# This option is also used when generating formulas in HTML.
 
LATEX_BATCHMODE = NO
 
# If LATEX_HIDE_INDICES is set to YES then doxygen will not
# include the index chapters (such as File Index, Compound Index, etc.)
# in the output.
 
LATEX_HIDE_INDICES = NO
 
# If LATEX_SOURCE_CODE is set to YES then doxygen will include
# source code with syntax highlighting in the LaTeX output.
# Note that which sources are shown also depends on other settings
# such as SOURCE_BROWSER.
 
LATEX_SOURCE_CODE = NO
 
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
# http://en.wikipedia.org/wiki/BibTeX for more info.
 
LATEX_BIB_STYLE = plain
 
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
 
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
# The RTF output is optimized for Word 97 and may not look very pretty with
# other RTF readers or editors.
 
GENERATE_RTF = NO
 
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `rtf' will be used as the default path.
 
RTF_OUTPUT = rtf
 
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
# RTF documents. This may be useful for small projects and may help to
# save some trees in general.
 
COMPACT_RTF = NO
 
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
# will contain hyperlink fields. The RTF file will
# contain links (just like the HTML output) instead of page references.
# This makes the output suitable for online browsing using WORD or other
# programs which support those fields.
# Note: wordpad (write) and others do not support links.
 
RTF_HYPERLINKS = NO
 
# Load style sheet definitions from file. Syntax is similar to doxygen's
# config file, i.e. a series of assignments. You only have to provide
# replacements, missing definitions are set to their default value.
 
RTF_STYLESHEET_FILE =
 
# Set optional variables used in the generation of an rtf document.
# Syntax is similar to doxygen's config file.
 
RTF_EXTENSIONS_FILE =
 
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
 
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
# generate man pages
 
GENERATE_MAN = NO
 
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `man' will be used as the default path.
 
MAN_OUTPUT = man
 
# The MAN_EXTENSION tag determines the extension that is added to
# the generated man pages (default is the subroutine's section .3)
 
MAN_EXTENSION = .3
 
# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
# then it will generate one additional man file for each entity
# documented in the real man page(s). These additional files
# only source the real man page, but without them the man command
# would be unable to find the correct page. The default is NO.
 
MAN_LINKS = NO
 
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
 
# If the GENERATE_XML tag is set to YES Doxygen will
# generate an XML file that captures the structure of
# the code including all documentation.
 
GENERATE_XML = NO
 
# The XML_OUTPUT tag is used to specify where the XML pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `xml' will be used as the default path.
 
XML_OUTPUT = xml
 
# The XML_SCHEMA tag can be used to specify an XML schema,
# which can be used by a validating XML parser to check the
# syntax of the XML files.
 
XML_SCHEMA =
 
# The XML_DTD tag can be used to specify an XML DTD,
# which can be used by a validating XML parser to check the
# syntax of the XML files.
 
XML_DTD =
 
# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
# dump the program listings (including syntax highlighting
# and cross-referencing information) to the XML output. Note that
# enabling this will significantly increase the size of the XML output.
 
XML_PROGRAMLISTING = YES
 
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
 
# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
# generate an AutoGen Definitions (see autogen.sf.net) file
# that captures the structure of the code including all
# documentation. Note that this feature is still experimental
# and incomplete at the moment.
 
GENERATE_AUTOGEN_DEF = NO
 
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
 
# If the GENERATE_PERLMOD tag is set to YES Doxygen will
# generate a Perl module file that captures the structure of
# the code including all documentation. Note that this
# feature is still experimental and incomplete at the
# moment.
 
GENERATE_PERLMOD = NO
 
# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
# the necessary Makefile rules, Perl scripts and LaTeX code to be able
# to generate PDF and DVI output from the Perl module output.
 
PERLMOD_LATEX = NO
 
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
# nicely formatted so it can be parsed by a human reader.
# This is useful
# if you want to understand what is going on.
# On the other hand, if this
# tag is set to NO the size of the Perl module output will be much smaller
# and Perl will parse it just the same.
 
PERLMOD_PRETTY = YES
 
# The names of the make variables in the generated doxyrules.make file
# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
# This is useful so different doxyrules.make files included by the same
# Makefile don't overwrite each other's variables.
 
PERLMOD_MAKEVAR_PREFIX =
 
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
 
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
# evaluate all C-preprocessor directives found in the sources and include
# files.
 
ENABLE_PREPROCESSING = YES
 
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
# names in the source code. If set to NO (the default) only conditional
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
 
MACRO_EXPANSION = NO
 
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
# PREDEFINED and EXPAND_AS_DEFINED tags.
 
EXPAND_ONLY_PREDEF = NO
 
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# pointed to by INCLUDE_PATH will be searched when a #include is found.
 
SEARCH_INCLUDES = YES
 
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by
# the preprocessor.
 
INCLUDE_PATH =
 
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
# directories. If left blank, the patterns specified with FILE_PATTERNS will
# be used.
 
INCLUDE_FILE_PATTERNS =
 
# The PREDEFINED tag can be used to specify one or more macro names that
# are defined before the preprocessor is started (similar to the -D option of
# gcc). The argument of the tag is a list of macros of the form: name
# or name=definition (no spaces). If the definition and the = are
# omitted =1 is assumed. To prevent a macro definition from being
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
 
PREDEFINED = gtk \
WITH_THEME_INSTALL
 
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
# Use the PREDEFINED tag if you want to use a different macro definition that
# overrules the definition found in the source code.
 
EXPAND_AS_DEFINED =
 
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
# doxygen's preprocessor will remove all references to function-like macros
# that are alone on a line, have an all uppercase name, and do not end with a
# semicolon, because these will confuse the parser if not removed.
 
SKIP_FUNCTION_MACROS = YES
 
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
 
# The TAGFILES option can be used to specify one or more tagfiles. For each
# tag file the location of the external documentation should be added. The
# format of a tag file without this location is as follows:
#
# TAGFILES = file1 file2 ...
# Adding location for the tag files is done as follows:
#
# TAGFILES = file1=loc1 "file2 = loc2" ...
# where "loc1" and "loc2" can be relative or absolute paths
# or URLs. Note that each tag file must have a unique name (where the name does
# NOT include the path). If a tag file is not located in the directory in which
# doxygen is run, you must also specify the path to the tagfile here.
 
TAGFILES =
 
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
# a tag file that is based on the input files it reads.
 
GENERATE_TAGFILE =
 
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
# in the class index. If set to NO only the inherited external classes
# will be listed.
 
ALLEXTERNALS = NO
 
# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
# in the modules index. If set to NO, only the current project's groups will
# be listed.
 
EXTERNAL_GROUPS = YES
 
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of `which perl').
 
PERL_PATH = /usr/bin/perl
 
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
 
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
# or super classes. Setting the tag to NO turns the diagrams off. Note that
# this option also works with HAVE_DOT disabled, but it is recommended to
# install and use dot, since it yields more powerful graphs.
 
CLASS_DIAGRAMS = YES
 
# You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see
# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
 
MSCGEN_PATH =
 
# If set to YES, the inheritance and collaboration graphs will hide
# inheritance and usage relations if the target is undocumented
# or is not a class.
 
HIDE_UNDOC_RELATIONS = YES
 
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz, a graph visualization
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default)
 
HAVE_DOT = YES
 
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
# allowed to run in parallel. When set to 0 (the default) doxygen will
# base this on the number of processors available in the system. You can set it
# explicitly to a value larger than 0 to get control over the balance
# between CPU load and processing speed.
 
DOT_NUM_THREADS = 0
 
# By default doxygen will use the Helvetica font for all dot files that
# doxygen generates. When you want a differently looking font you can specify
# the font name using DOT_FONTNAME. You need to make sure dot is able to find
# the font, which can be done by putting it in a standard location or by setting
# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
# directory containing the font.
 
DOT_FONTNAME = Helvetica
 
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
# The default size is 10pt.
 
DOT_FONTSIZE = 10
 
# By default doxygen will tell dot to use the Helvetica font.
# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
# set the path where dot can find it.
 
DOT_FONTPATH =
 
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect inheritance relations. Setting this tag to YES will force the
# CLASS_DIAGRAMS tag to NO.
 
CLASS_GRAPH = YES
 
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect implementation dependencies (inheritance, containment, and
# class references variables) of the class with other documented classes.
 
COLLABORATION_GRAPH = YES
 
# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for groups, showing the direct groups dependencies
 
GROUP_GRAPHS = YES
 
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
 
UML_LOOK = NO
 
# If the UML_LOOK tag is enabled, the fields and methods are shown inside
# the class node. If there are many fields or methods and many nodes the
# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
# threshold limits the number of items for each type to make the size more
# managable. Set this to 0 for no limit. Note that the threshold may be
# exceeded by 50% before the limit is enforced.
 
UML_LIMIT_NUM_FIELDS = 10
 
# If set to YES, the inheritance and collaboration graphs will show the
# relations between templates and their instances.
 
TEMPLATE_RELATIONS = NO
 
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
# tags are set to YES then doxygen will generate a graph for each documented
# file showing the direct and indirect include dependencies of the file with
# other documented files.
 
INCLUDE_GRAPH = YES
 
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
# documented header file showing the documented files that directly or
# indirectly include this file.
 
INCLUDED_BY_GRAPH = YES
 
# If the CALL_GRAPH and HAVE_DOT options are set to YES then
# doxygen will generate a call dependency graph for every global function
# or class method. Note that enabling this option will significantly increase
# the time of a run. So in most cases it will be better to enable call graphs
# for selected functions only using the \callgraph command.
 
CALL_GRAPH = YES
 
# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
# doxygen will generate a caller dependency graph for every global function
# or class method. Note that enabling this option will significantly increase
# the time of a run. So in most cases it will be better to enable caller
# graphs for selected functions only using the \callergraph command.
 
CALLER_GRAPH = NO
 
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
# will generate a graphical hierarchy of all classes instead of a textual one.
 
GRAPHICAL_HIERARCHY = YES
 
# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
# then doxygen will show the dependencies a directory has on other directories
# in a graphical way. The dependency relations are determined by the #include
# relations between the files in the directories.
 
DIRECTORY_GRAPH = YES
 
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. Possible values are svg, png, jpg, or gif.
# If left blank png will be used. If you choose svg you need to set
# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
# visible in IE 9+ (other browsers do not have this requirement).
 
DOT_IMAGE_FORMAT = png
 
# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
# enable generation of interactive SVG images that allow zooming and panning.
# Note that this requires a modern browser other than Internet Explorer.
# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
# visible. Older versions of IE do not have SVG support.
 
INTERACTIVE_SVG = NO
 
# The tag DOT_PATH can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found in the path.
 
DOT_PATH =
 
# The DOTFILE_DIRS tag can be used to specify one or more directories that
# contain dot files that are included in the documentation (see the
# \dotfile command).
 
DOTFILE_DIRS =
 
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the
# \mscfile command).
 
MSCFILE_DIRS =
 
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
# nodes that will be shown in the graph. If the number of nodes in a graph
# becomes larger than this value, doxygen will truncate the graph, which is
# visualized by representing a node as a red box. Note that doxygen if the
# number of direct children of the root node in a graph is already larger than
# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
 
DOT_GRAPH_MAX_NODES = 50
 
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
# graphs generated by dot. A depth value of 3 means that only nodes reachable
# from the root by following a path via at most 3 edges will be shown. Nodes
# that lay further from the root node will be omitted. Note that setting this
# option to 1 or 2 may greatly reduce the computation time needed for large
# code bases. Also note that the size of a graph can be further restricted by
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
 
MAX_DOT_GRAPH_DEPTH = 0
 
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not
# seem to support this out of the box. Warning: Depending on the platform used,
# enabling this option may lead to badly anti-aliased labels on the edges of
# a graph (i.e. they become hard to read).
 
DOT_TRANSPARENT = NO
 
# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10)
# support this, this feature is disabled by default.
 
DOT_MULTI_TARGETS = YES
 
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
# generate a legend page explaining the meaning of the various boxes and
# arrows in the dot generated graphs.
 
GENERATE_LEGEND = YES
 
# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
# remove the intermediate dot files that are used to generate
# the various graphs.
 
DOT_CLEANUP = YES
/programs/network/netsurf/netsurf/Docs/LIBRARIES
0,0 → 1,51
--------------------------------------------------------------------------------
NetSurf project libraries required 1 July 2012
--------------------------------------------------------------------------------
 
To build NetSurf, you need the libraries required by the core, and any extra
libraries required by the specific front end you are building.
 
 
NetSurf Core
==============
 
Required:
 
$ git clone git://git.netsurf-browser.org/buildsystem
$ git clone git://git.netsurf-browser.org/libwapcaplet
$ git clone git://git.netsurf-browser.org/libparserutils
$ git clone git://git.netsurf-browser.org/libhubbub
$ git clone git://git.netsurf-browser.org/libcss
$ git clone git://git.netsurf-browser.org/libdom
$ git clone git://git.netsurf-browser.org/libnsbmp
$ git clone git://git.netsurf-browser.org/libnsgif
 
Optional:
 
$ git clone git://git.netsurf-browser.org/libsvgtiny
 
 
RISC OS front end
===================
 
Required:
 
$ git clone git://git.netsurf-browser.org/libpencil
$ git clone git://git.netsurf-browser.org/rufl
 
 
Framebuffer front end
=======================
 
Required:
 
$ git clone git://git.netsurf-browser.org/libnsfb
 
 
Non RISC OS front ends
========================
 
Optional:
 
$ git clone git://git.netsurf-browser.org/librosprite
 
/programs/network/netsurf/netsurf/Docs/PACKAGING-GTK
0,0 → 1,86
--------------------------------------------------------------------------------
Packaging suggestions for NetSurf 30 July 2008
--------------------------------------------------------------------------------
 
This document lays out some suggestions for people interested in packaging
NetSurf for UNIX-like OSes.
 
We consider the Debian (and thus Ubuntu) packages excellent examples to
crib from. They do everything right.
 
 
Building NetSurf
==================
 
You should change Makefile.config to be specific (rather than rely on AUTO)
for the libraries and functionality you want to include. This will help
your packages be consistent. Also remember that you can turn off
functionality such as PDF export, RISC OS Sprite support, SVG rendering etc.
from here should you require a smaller, lighter build.
 
 
Launching NetSurf
===================
 
The GTK port of NetSurf requires access to some resources at run time.
These are stored in gtk/res/ in the source tree. Some of these files are
symlinks into the !NetSurf directory, which is the application container
for the native RISC OS build. None of the other files from the !NetSurf
directory are required - the symlinks are used only as a way of making
checkouts smaller and making sure changes to one set of resources updates
the other.
 
The binary that the build system produces is called "nsgtk". There is also
a shell script called "netsurf" that will set up the environment and launch
the nsgtk binary. Do not ship this shell script with your package. It is
included only as a convience for launching NetSurf from the build tree.
Instead, you should move nsgtk to /usr/bin/netsurf (or wherever your
distribution's packaging policy suggests) and copy the contents of
gtk/res/ (dereferencing the symlinks, obviously) to /usr/share/netsurf (or
wherever your packaging policy suggests).
 
You will need to tell NetSurf where to find its resources. NetSurf searches
three locations by default when trying to load them, in this order:
 
1. ~/.netsurf/
2. $NETSURFRES/
3. /usr/share/netsurf/
 
The second one is how the netsurf launcher script controls it. The third
location is controlled by the NETSURF_GTK_RESOURCES option in
Makefile.config, and this is the recommended way for packagers to change
the location it searches, as this still allows the user some flexibility in
changing what NetSurf uses.
 
 
User agent string
===================
 
You may also want to change NetSurf's user agent string to include the
name of your distribution. The user agent string is build by a function
kept in utils/useragent.c - you'll want to change the macro called
NETSURF_UA_FORMAT_STRING. It's processed via sprintf, so keep that in
mind when changing it. The first two printf parameters are major and minor
version numbers, the second two are OS name (uname -s) and architecture
(uname -m). You might want change this to something like:
 
"NetSurf/%d.%d (%s; %s; Debian GNU/Linux)"
 
or similar. Please don't be tempted to mention Mozilla or similar - let's
let that lie die.
 
 
Home page URL
===============
 
If the user hasn't specified a home page URL in their Preferences, NetSurf
defaults to a "portal" welcome page at about:netsurf - if you wish to
change this, you can do so by overriding the NETSURF_HOMEPAGE URL in
Makefile.config.
 
 
If you make significant changes to NetSurf in your package, please ask your
users to report bugs to your bug tracker, not ours. We'd also be interested
in seeing the diffs for these changes - we may be able to integrate them
to make your job easier in future.
 
/programs/network/netsurf/netsurf/Docs/USING-Framebuffer
0,0 → 1,201
--------------------------------------------------------------------------------
Usage Instructions for Framebuffer NetSurf 2nd October 2010
--------------------------------------------------------------------------------
 
This document provides usage instructions for the Framebuffer version of
NetSurf.
 
Framebuffer NetSurf has been tested on Ubuntu and Debian.
 
Overview
========
 
What it is
----------
 
The NetSurf framebuffer front end is primarily intended for kiosk
and embedded applications where there is insufficient Operating
System support for a full graphical windowing environment.
 
The framebuffer frontend features:
 
* A trivial occluded rectangle window management toolkit
 
* Font handling system using either:
- A trivial internal monochrome bitmap glyph set.
- An interface to fully anti-aliased glyphs using libfreetype 2
 
* Uses libnsfb to provide transparent support for:
- Numerous surface providers allowing usage on Linux, X, SDL, VNC
and any mapped linear memory region.
- Surface depths of 8, 16, 24 and 32bpp
- Optimised software plotters for lines, rectangles, polygons,
arbitrary ellipses (including circles), cubic and quadratic
splines, font glyphs and 32bpp RGBA bitmaps.
- Abstracted input handling.
What it is not
--------------
The framebuffer frontend is not a replacement for full native
ports. It lacks functionality and flexibility compared to such
implementations.
 
Limitations include:
- Single window interface.
- No tabbed interface.
- Expects to control the entire plotting surface.
- No ability to re-size a surface after initialisation.
- Inflexible input character mapping.
- Limited history view.
 
In addition it should be noted support for some libnsfb surfaces has
been implemented purely for debugging functionality (SDL
especially) and is not intended to replace native surface
handlers.
 
If a high level windowing system is available then a native NetSurf
frontend is almost certainly a better choice than attempting to use
the framebuffer frontend.
 
If there is a graphical environment which supports GTK then using
the GTK frontend is a vastly superior choice. The framebuffer
frontend will appear exceptionally limited on such capable systems.
 
 
Configuring
===========
 
Several resources are set at *compile* time and are not changeable at
run time such as the icon bitmaps, the font system to use and what
default surface to use. Refer to the BUILDING-Framebuffer document
for details.
 
Toolkit Options
---------------
 
The trivial toolkit has some configuration parameters allowing the
user to alter specific aspects of the UI. All the sizes are in
surface pixels however that is mapped.
 
fb_furniture_size
This is the size allowed for the scroll bar elements.
 
fb_toolbar_size
The height of the toolbar.
 
fb_toolbar_layout
The layout of the toolbar, layout uses a string to define buttons
type and position each character adds an element to the toolbar:
 
b - back
l - local history
f - forward
s - stop
r - refresh
u - url bar expands to fit remaining space
t - throbber/activity indicator
c - close the current window
 
The default layout is "blfsrut" there should be no more than a
single url bar entry. If the option is set to the empty string (no
spaces permitted) the toolbar is disabled altogether.
 
fb_osk
Whether the on screen keyboard should be enabled for input.
 
 
Framebuffer Surface
-------------------
 
There are four command line switches which override compiled in
defaults these are:
 
-f <handler>
Selects a surface handler to pass to libnsfb instead of the
default. (e.g. x, sdl, mem, linux)
 
-b <depth>
Selects the pixel depth to pass to libnsfb instead of the
compiled in default. (one of 8, 16, 24, 32)
 
-w <width>
Selects the surface width to pass to libnsfb instead of the
compiled in default.
 
-h <height>
Selects the surface height to pass to libnsfb instead of the
compiled in default.
 
As with any NetSurf frontend run-time configuration is read from a
"Choices-fb" file. This file is a simple key:value list. In addition
to the standard values supported by the NetSurf core there are a
number of values to control specific aspects of the framebuffer
version.
 
The libnsfb surface parameters are controlled with:
 
fb_refresh - The refresh rate (for physical displays)
fb_depth - The depth (in bits per pixel) of the surface
fb_device - The path to the device (for physical displays)
fb_input_devpath - The path to the input devices (for linux input layer)
fb_input_glob - The input device selection glob (for linux input layer)
window_width - The width of the framebuffer
window_height - The height of the framebuffer
 
The defaults are for 800 by 600 pixels at 16bpp and 70Hz refresh rate.
 
The documentation of libnsfb should be consulted for further
information about supported surfaces and their configuration.
 
Fonts
-----
 
If the compile time option is set to use the freetype font system
then several configuration options are available. If the simple
bitmap glyphs are used none of these options apply.
 
Font faces are provided for the css default styles of sans serif,
serif, monospace, cursive and fantasy. Only the sans serif
non-italic normal weight font is required to exist, If any of the
other faces are missing the sans serif font will be used instead.
 
The compiled in default font file paths are specified within the
build time Makefile.config. The default faces is the truetype DejaVu
font set in the directory /usr/share/fonts/truetype/ttf-dejavu/
 
The font glyphs are, by default, rendered as 256 level transparency
which gives excellent visual results even on small font sizes.
 
The font selection may be changed by placing truetype font files
in the resources path. The resource files will be the generic names
sans_serif.ttf, sans_serif_bold.ttf etc.
 
The font system is configured at run-time by several options:
 
fb_font_monochrome
This option causes the renderer to use monochrome glyph
rendering. This method of rendering is much less visually
appealing and while faster to plot it is slower to render.
 
fb_font_cachesize
This option sets the number of kilobytes of memory set aside for
caching the rendered glyphs. This caching significantly improves
the performance of using the freetype rendering system. It is set
to 2048 by default (2 Megabytes of memory) which impiracle testing
shows to be a suitable value for the seven default faces.
 
The remaining options control the files to be used for font faces. The
font file name options will override both the compiled in paths and
files found in the resource path.
 
fb_face_sans_serif - The sans serif face
fb_face_sans_serif_bold - The bold sans serif face
fb_face_sans_serif_italic - The italic sans serif face
fb_face_sans_serif_italic_bold - The bold italic sans serif face.
fb_face_serif - The serif font
fb_face_serif_bold - The bold serif font
fb_face_monospace - The monospaced font
fb_face_monospace_bold - The bold monospaced font
fb_face_cursive - The cursive font
fb_face_fantasy - The fantasy font
/programs/network/netsurf/netsurf/Docs/USING-Monkey
0,0 → 1,318
--------------------------------------------------------------------------------
Usage Instructions for Monkey NetSurf 13 March 2011
--------------------------------------------------------------------------------
 
This document provides usage instructions for the Monkey version of
NetSurf.
 
Monkey NetSurf has been tested on Ubuntu.
 
Overview
========
 
What it is
----------
 
The NetSurf Monkey front end is a developer debug tool used to
test how the core interacts with the user interface. It allows
the developers to profile NetSurf and to interact with the core
directly as though the developer were a front end.
What it is not
--------------
 
Monkey is not a tool for building web-crawling robots or indeed
anything other than a debug tool for the NetSurf developers.
 
How to interact with nsmonkey
-----------------------------
 
In brief, monkey will produce tagged output on stdout and expect
commands on stdin. Windows are numbered and for the most part
tokens are space separated. In some cases (e.g. title or status)
the final element on the output line is a string which might have
spaces embedded within it. As such, output from nsmonkey should be
parsed a token at a time, so that when such a string is encountered,
the parser can stop splitting and return the rest.
 
Commands to Monkey are namespaced. For example commands related to
browser windows are prefixed by WINDOW.
 
Top level tags for nsmonkey
---------------------------
 
QUIT
 
WINDOW
 
Top level response tags for nsmonkey
------------------------------------
 
GENERIC
 
WARN, ERROR, DIE
 
WINDOW
 
DOWNLOAD_WINDOW
 
SSLCERT
 
401LOGIN
 
PLOT
 
In the below, %something% indicates a substitution made by Monkey.
 
%url% will be a URL
%id% will be an opaque ID
%n% will be a number
%bool% will be TRUE or FALSE
%str% is a string and will only ever be at the end of an output line.
 
Warnings, errors etc
--------------------
 
Warnings (tagged WARN) come from the NetSurf core.
Errors (tagged ERROR) tend to come from Monkey's parsers
Death (tagged DIE) comes from the core and kills Monkey dead.
 
Commands
========
 
Generic commands
----------------
 
QUIT
Cause monkey to quit cleanly.
This will cleanly destroy open windows etc.
 
Window commands
---------------
 
WINDOW NEW [%url%]
Create a new browser window, optionally giving the core
a URL to immediately navigate to.
Minimally you will receive a WINDOW NEW WIN %id% response.
 
WINDOW DESTROY %id%
Destroy the given browser window.
Minimally you will recieve a WINDOW DESTROY WIN %id% response.
 
WINDOW GO %id% %url% [%url%]
Cause the given browser window to visit the given URL.
Optionally you can give a referrer URL to also use (simulating
a click in the browser on a link).
Minimally you can expect throbber, url etc responses.
 
WINDOW REDRAW %id% [%num% %num% %num% %num%]
Cause a browser window to redraw. Optionally you can give a
set of coordinates to simulate a partial expose of the window.
Said coordinates are in traditional X0 Y0 X1 Y1 order.
The coordinates are in canvas, not window, coordinates. So you
should take into account the scroll offsets when issuing this
command.
Minimally you can expect redraw start/stop messages and you
can likely expect some number of PLOT results.
 
WINDOW RELOAD %id%
Cause a browser window to reload its current content.
Expect responses similar to a GO command.
 
 
Responses
=========
 
Generic messages
----------------
 
GENERIC STARTED
Monkey has started and is ready for commands
 
GENERIC CLOSING_DOWN
Monkey has been told to shut down and is doing so
 
GENERIC FINISHED
Monkey has finished and will now exit
 
GENERIC LAUNCH URL %url%
The core asked monkey to launch the given URL
 
GENERIC THUMBNAIL URL %url%
The core asked monkey to thumbnail a content without
a window.
 
GENERIC POLL BLOCKING
Monkey reached a point where it could sleep waiting for
commands or scheduled timeouts. No fetches nor redraws
were pending.
 
Window messages
---------------
 
WINDOW NEW WIN %id% FOR %id% CLONE %id% NEWTAB %bool%
The core asked Monkey to open a new window. The IDs for 'FOR' and
'CLONE' are core window IDs, the WIN id is a Monkey window ID.
 
WINDOW SIZE WIN %id% WIDTH %n% HEIGHT %n%
The window specified has been set to the shown width and height.
 
WINDOW DESTROY WIN %id%
The core has instructed Monkey to destroy the named window.
 
WINDOW TITLE WIN %id% STR %str%
The core supplied a titlebar title for the given window.
 
WINDOW REDRAW WIN %id%
The core asked that Monkey redraw the given window.
 
WINDOW GET_DIMENSIONS WIN %id% WIDTH %n% HEIGHT %n%
The core asked Monkey what the dimensions of the window are.
Monkey has to respond immediately and returned the supplied width
and height values to the core.
 
WINDOW NEW_CONTENT WIN %id%
The core has informed Monkey that the named window has a new
content object.
 
WINDOW NEW_ICON WIN %id%
The core has informed Monkey that the named window hsa a new
icon (favicon) available.
 
WINDOW START_THROBBER WIN %id%
The core asked Monkey to start the throbber for the named
window. This indicates to the user that the window is busy.
 
WINDOW STOP_THROBBER WIN %id%
The core asked Monkey to stop the throbber for the named
window. This indicates to the user that the window is finished.
 
WINDOW SET_SCROLL WIN %id% X %n% Y %n%
The core asked Monkey to set the named window's scroll offsets
to the given X and Y position.
 
WINDOW UPDATE_BOX WIN %id% X %n% Y %n% WIDTH %n% HEIGHT %n%
The core asked Monkey to redraw the given portion of the content
display. Note these coordinates refer to the content, not the
viewport which Monkey is simulating.
 
WINDOW UPDATE_EXTENT WIN %id% WIDTH %n% HEIGHT %n%
The core has told us that the content in the given window has a
total width and height as shown. This allows us (along with the
window's width and height) to know the scroll limits.
WINDOW SET_STATUS WIN %id% STR %str%
The core has told us that the given window needs its status bar
updating with the given message.
 
WINDOW SET_POINTER WIN %id% POINTER %id%
The core has told us to update the mouse pointer for the given
window to the given pointer ID.
 
WINDOW SET_SCALE WIN %id% SCALE %n%
The core has asked us to scale the given window by the given scale
factor.
 
WINDOW SET_URL WIN %id% URL %url%
The core has informed us that the given window's URL bar needs
updating to the given url.
 
WINDOW GET_SCROLL WIN %id% X %n% Y %n%
The core asked Monkey for the scroll offsets. Monkey returned the
numbers shown for the window named.
 
WINDOW SCROLL_START WIN %id%
The core asked Monkey to scroll the named window to the top/left.
 
WINDOW POSITION_FRAME WIN %id% X0 %n% Y0 %n% X1 %n% Y1 %n%
The core asked Monkey to position the named window as a frame at
the given coordinates of its parent.
 
WINDOW SCROLL_VISIBLE WIN %id% X0 %n% Y0 %n% X1 %n% Y1 %n%
The core asked Monkey to scroll the named window until the
indicated box is visible.
 
WINDOW PLACE_CARET WIN %id% X %n% Y %n% HEIGHT %n%
The core asked Monkey to render a caret in the named window at the
indicated position with the indicated height.
 
WINDOW REMOVE_CARET WIN %id%
The core asked Monkey to remove any caret in the named window.
 
WINDOW SCROLL_START WIN %id% X0 %n% Y0 %n% X1 %n% Y1 %n%
The core asked Monkey to scroll the named window to the start of
the given box.
 
WINDOW SELECT_MENU WIN %id%
The core asked Monkey to produce a selection menu for the named
window.
 
WINDOW SAVE_LINK WIN %id% URL %url% TITLE %str%
The core asked Monkey to save a link from the given window with
the given URL and anchor title.
 
WINDOW THUMBNAIL WIN %id% URL %url%
The core asked Monkey to render a thumbnail for the given window
which is currently at the given URL.
 
WINDOW REDRAW WIN %id% START
WINDOW REDRAW WIN %id% STOP
The core wraps redraws in these messages. Thus PLOT responses can
be allocated to the appropriate window.
 
Download window messages
------------------------
 
DOWNLOAD_WINDOW CREATE DWIN %id% WIN %id%
The core asked Monkey to create a download window owned by the
given browser window.
 
DOWNLOAD_WINDOW DATA DWIN %id% SIZE %n% DATA %str%
The core asked Monkey to update the named download window with
the given byte size and data string.
 
DOWNLOAD_WINDOW ERROR DWIN %id% ERROR %str%
The core asked Monkey to update the named download window with
the given error message.
 
DOWNLOAD_WINDOW DONE DWIN %id%
The core asked Monkey to destroy the named download window.
 
SSL Certificate messages
------------------------
 
SSLCERT VERIFY CERT %id% URL %url%
The core asked Monkey to say whether or not a given SSL
certificate is OK.
 
401 Login messages
------------------
 
401LOGIN OPEN M4 %id% URL %url% REALM %str%
The core asked Monkey to ask for identification for the named
realm at the given URL.
 
Plotter messages
----------------
 
Note, Monkey won't clip coordinates, but sometimes the core does.
 
PLOT CLIP X0 %n% Y0 %n% X1 %n% Y1 %n%
The core asked Monkey to clip plotting to the given clipping
rectangle (X0,Y0) (X1,Y1)
 
PLOT TEXT X %n% Y %n% STR %str%
The core asked Monkey to plot the given string at the
given coordinates.
 
PLOT LINE X0 %n% Y0 %n% X1 %n% Y1 %n%
The core asked Monkey to plot a line with the given start
and end coordinates.
 
PLOT RECT X0 %n% Y0 %n% X1 %n% Y1 %n%
The core asked Monkey to plot a rectangle with the given
coordinates as the corners.
 
PLOT BITMAP X %n% Y %n% WIDTH %n% HEIGHT %n%
The core asked Monkey to plot a bitmap at the given
coordinates, scaled to the given width/height.
/programs/network/netsurf/netsurf/Docs/ideas/cache.txt
0,0 → 1,178
Content caching
===============
 
NetSurf's existing fetch/cache architecture has a number of problems:
 
1) Content dependencies are not modelled.
2) Content source data for non-shareable contents is duplicated.
3) Detection of content sharability is dependent on Content-Type, which
requires content cloning (which will fail for dependent contents).
4) Detection of cycles in content dependency graphs is not performed
(e.g. content1 includes content2, which includes content1).
5) All content caching is in-memory, there's no offline storage.
 
Proposal
--------
 
A split-level cache.
 
Low-level cache:
 
+ Responsible for source data (+header) management.
+ Interfaces with low-level fetch system to retrieve data from network.
+ Is responsible for offline storage (if any) of cache objects.
+ Returns opaque handles to low-level cache objects.
+ Handles HTTP redirects, recording URLs encountered when retrieving resource.
+ May perform content-type sniffing (requires usage context)
 
High-level cache:
 
+ Responsible for content objects.
+ Tracks content dependencies (and potential cycles).
+ Returns opaque handles to content objects.
+ Manages content sharability & reusability (see below).
+ Contents with unknown types are never shared and thus get unique handles.
+ Content handles <> content objects: they're an indirection mechanism.
 
Content sharability & reusability
--------------------------------
 
If a content is shareable, then it may have multiple concurrent users.
Otherwise, it may have at most one user.
 
If a content is reusable, then it may be retained in the cache for later use
when it has no users. Otherwise, it will be removed from the cache when
it has no users.
 
Example: retrieving a top-level resource
----------------------------------------
 
1) Client requests an URL, specifying no parent handle.
2) High-level cache asks low-level cache for low-level handle for URL.
3) Low-level cache looks for appropriate object in its index.
a) it finds one that's not stale and returns its handle
b) it finds only stale entries, or no appropiate entry,
so allocates a new entry, requests a fetch for it,
and returns the handle.
4) High-level cache looks for content objects that are using the low-level
handle.
a) it finds one that's shareable and selects its handle for use.
b) it finds only non-shareable entries, or no appropriate entry,
so allocates a new entry and selects its handle for use.
5) High-level cache registers the parent and client with the selected handle,
then returns the selected handle.
6) Client carries on, happy in the knowledge that a content is available.
 
Example: retrieving a child resource
------------------------------------
 
1) Client requests an URL, specifying parent handle.
2) High-level cache searches parent+ancestors for requested URL.
a) it finds the URL, so returns a non-fatal error.
b) it does not find the URL, so proceeds from step 2 of the
top-level resource algorithm.
 
NOTE: this approach means that shareable contents may have multiple parents.
 
Handling of contents of unknown type
------------------------------------
 
Contents of unknown type are, by definition, not shareable. Therefore, each
client will be issued with a different content handle.
 
Content types are only known once a resource's headers are fetched (or once
the type has been sniffed from the resource's data when the headers are
inconclusive).
 
As a resource is fetched, users of the resource are informed of the fetch
status. Therefore, the high-level cache is always informed of fetch progress.
Cache clients need not care about this: they are simply interested in
a content's readiness for use.
 
When the high-level cache is informed of a low-level cache object's type,
it is in a position to determine whether the corresponding content handles
can share a single content object or not.
 
If it detects that a single content object may be shared by multiple handles,
it simply creates the content object and registers each of the handles as
a user of the content.
 
If it detects that each handle requires a separate content object, then it
will create a content object for each handle and register the handle as a
user.
 
This approach requires that clients of the high-level cache get issued with
handles to content objects, rather than content objects (so that the decision
whether to create multiple content objects can be deferred until suitable
information is available).
 
Handles with no associated content object will act as if they had a content
object that was not ready for use.
 
A more concrete example
-----------------------
 
+ bw1 contains html1 which includes css1, css2, img1, img2
+ bw2 contains html2 which includes css1, img1, img2
+ bw3 contains img1
 
Neither HTML nor CSS contents are shareable.
All shareable contents are requested from the high-level cache
once their type is known.
 
Low-level cache contains source data for:
 
1 - html1
2 - html2
3 - css1
4 - css2
5 - img1
6 - img2
 
High-level cache contains:
 
Content objects (ll-handle in parentheses):
 
+ c1 (1 - html1)
+ c2 (2 - html2)
+ c3 (3 - css1)
+ c4 (4 - css2)
+ c5 (5 - img1)
+ c6 (6 - img2)
+ c7 (3 - css1)
 
Content handles (objects in parentheses):
 
+ h1 (c1, used by bw1)
+ h2 (c3, used by h1)
+ h3 (c4, used by h1)
+ h4 (c2, used by bw2)
+ h5 (c7, used by h4)
+ h6 (c5, used by h1,h4,bw3)
+ h7 (c6, used by h1,h4)
 
If img1 was not of known type when requested:
 
Content handles (objects in parentheses):
 
+ h1 (c1, used by bw1)
+ h2 (c3, used by h1)
+ h3 (c4, used by h1)
+ h4 (c2, used by bw2)
+ h5 (c7, used by h4)
+ h6 (c5, used by h1)
+ h7 (c6, used by h1,h4)
+ h8 (c5, used by h4)
+ h9 (c5, used by bw3)
 
This achieves the desired effect that:
 
+ source data is shared between contents
+ content objects are only created when absolutely necessary
+ content usage/dependency is tracked and cycles avoided
+ offline storage is possible
 
Achieving this requires the use of indirection objects, but these are expected
to be small in comparison to the content objects / ll-cache objects that they
are indirecting.
 
/programs/network/netsurf/netsurf/Docs/ideas/css-engine.txt
0,0 → 1,381
CSS engine
==========
 
Requirements
------------
 
+ Parse stylesheets conforming to the forward compatible CSS grammar
(Note that in the short term, the semantic analysis stage only need
support CSS2.1)
+ Stylesheet management/merging (i.e. multiple stylesheets may be added
to a single engine context and thus affect style selection)
+ Be able to select a style for a DOM node based upon the current stylesheets
in the engine context.
+ Implemented as a standalone, reusable, library -- ideally MIT licensed.
 
Suggested API
-------------
 
struct css_context;
struct css_style;
struct css_stylesheet;
 
typedef struct css_context css_context;
typedef struct css_style css_style;
typedef struct css_stylesheet css_stylesheet;
 
typedef enum css_error {
CSS_OK,
CSS_NOMEM,
/* etc */
} css_error;
 
typedef enum css_origin {
CSS_ORIGIN_UA,
CSS_ORIGIN_USER,
CSS_ORIGIN_AUTHOR
} css_origin;
 
#define CSS_MEDIA_SCREEN (1<<0)
#define CSS_MEDIA_PRINT (1<<1)
/* etc */
#define CSS_MEDIA_ALL (0xffffffff)
 
#define CSS_PSEUDO_CLASS_NONE (0)
#define CSS_PSEUDO_CLASS_LINK (1<<0)
#define CSS_PSEUDO_CLASS_VISITED (1<<1)
#define CSS_PSEUDO_CLASS_HOVER (1<<2)
#define CSS_PSEUDO_CLASS_ACTIVE (1<<3)
#define CSS_PSEUDO_CLASS_FOCUS (1<<4)
 
typedef enum css_property {
CSS_BACKGROUND_ATTACHMENT,
/* etc */
} css_property;
 
typedef struct css_value {
css_property property;
 
union {
css_background_attachment background_attachment;
/* etc */
} value;
} css_value;
 
typedef css_error (*css_import_handler)(void *pw, const char *url,
css_stylesheet *sheet);
 
/* Initialise library */
css_error css_init(void);
/* Finalise library */
css_error css_fini(void);
 
/* Create a stylesheet associated with the given URL,
* specifying the sheet's origin, the media type(s) it applies to and
* a callback routine for fetching imported sheets */
css_stylesheet *css_stylesheet_create(const char *url,
css_origin origin, uint32_t media,
css_import_handler import_callback, void *pw);
/* Destroy a stylesheet */
void css_stylesheet_destroy(css_stylesheet *sheet);
 
/* Append data to a stylesheet, parsing progressively */
css_error css_stylesheet_append_data(css_stylesheet *sheet,
const uint8_t *data, size_t len);
/* Tell stylesheet parser that there's no more data (will complete parsing) */
css_error css_stylesheet_data_done(css_stylesheet *sheet);
 
/* Retrieve the URL associated with a stylesheet */
const char *css_stylesheet_get_url(css_stylesheet *sheet);
/* Retrieve the origin of a stylesheet */
css_origin css_stylesheet_get_origin(css_stylesheet *sheet);
/* Retrieve the media type(s) applicable to a stylesheet */
uint32_t css_stylesheet_get_media(css_stylesheet *sheet);
 
/* Create a selection context */
css_context *css_context_create(void);
/* Destroy a selection context */
void css_context_destroy(css_context *context);
 
/* Append a top-level stylesheet to a selection context */
css_error css_context_append_sheet(css_context *context,
css_stylesheet *sheet);
/* Insert a top-level stylesheet into a selection context, at the given index */
css_error css_context_insert_sheet(css_context *context,
css_stylesheet *sheet, uint32_t index);
/* Remove a top-level stylesheet from a selection context */
css_error css_context_remove_sheet(css_context *context,
css_stylesheet *sheet);
 
/* Retrieve the total number of top-level sheets in a selection context */
uint32_t css_context_count_sheets(css_context *context);
/* Get a stylesheet from a selection context given an index [0, count) */
const css_stylesheet *css_context_get_sheet(css_context *context,
uint32_t index);
 
/* Select a style for a given DOM node with the given pseudo classes active
* and media type.
*
* If the document language contains non-CSS presentational hints (e.g. HTML
* presentational attributes etc), then these are passed in through
* property_list and treated as if they were encountered at the start of the
* author stylesheet with a specificity of 0. */
css_style *css_style_select(css_context *context,
<dom_node_type> *node, uint32_t pseudo_classes, uint32_t media,
css_value **property_list, uint32_t property_list_length);
/* Destroy a selected style */
void css_style_destroy(css_style *style);
 
/* Retrieve a property value from a style */
css_value *css_value_get(css_style *style, css_property property);
/* Destroy a property value */
void css_value_destroy(css_value *value);
 
Memory management
-----------------
 
+ Stylesheets are owned by their creator. Selection contexts reference them.
+ Selection contexts are owned by the client.
+ Selected styles are owned by the client.
+ Property values are owned by the client.
 
Therefore, the only difficulty lies within the handling of stylesheets
inserted into a selection context. The client code must ensure that a
stylesheet is destroyed after it has been removed from any selection
contexts which are using it.
 
DOM node types & tree traversal
-------------------------------
 
This is currently undecided. Either the CSS engine is tied to a DOM
implementation (and makes API calls directly), or it's more generic and
performs API calls through a vtable provided by the client.
 
Imported stylesheets
--------------------
 
Imported stylesheets are handled by the CSS engine creating an appropriate
css_stylesheet object for the imported sheet and then asking the client
to fetch the data and append it to the sheet. The imported sheet is then
stored in the sheet that imported it. This effectively creates a tree of
stylesheets beneath the initial top-level sheet created by the client.
 
Style selection algorithm
-------------------------
 
css_style_select(context, node, pseudo_classes, media,
property_list, property_list_length):
result = blank_style;
done_props = false;
foreach sheet in context:
# Assumes that sheets are in the order UA, USER, AUTHOR
if !done_props && css_stylesheet_get_origin(sheet) == CSS_ORIGIN_AUTHOR:
fake_rule = fake_rule(node, property_list, property_list_length);
cascade(result, fake_rule, CSS_ORIGIN_AUTHOR);
done_props = true;
process_sheet(sheet, node, pseudo_classes, media, result);
return result;
 
fake_rule(node, property_list, property_list_length):
rule = (node.name, 0); # Specificity is 0
foreach (property, value, importance) in property_list:
rule[property] = (value, importance);
return rule;
 
process_sheet(sheet, node, pseudo_classes, media, result):
if (css_stylesheet_get_media(sheet) & media) == 0:
return;
foreach import in sheet:
process_sheet(import, node, pseudo_classes, media, result);
origin = css_stylesheet_get_origin(sheet);
foreach rule in sheet:
if matches_rule(rule, node, pseudo_classes):
cascade(result, rule, origin);
 
cascade(result, rule, origin):
foreach (property, value, importance) in rule:
insert = false;
if result[property]:
rOrigin = result[property].origin;
rImportance = result[property].importance;
rSpecificity = result[property].specificity;
if rOrigin < origin:
if rImportance == "important":
if rOrigin != CSS_ORIGIN_USER:
insert = true;
else:
insert = true;
else if rOrigin == origin:
if rImportance == "" && importance == "important":
if rOrigin == CSS_ORIGIN_UA:
if rSpecificity <= rule.specificity:
insert = true;
else:
insert = true;
else if rImportance == "important" && importance == "":
if rOrigin == CSS_ORIGIN_UA:
if rSpecificity <= rule.specificity:
insert = true;
else:
if rSpecificity <= rule.specificity:
insert = true;
else:
if origin == CSS_ORIGIN_USER && importance == "important":
insert = true;
else:
insert = true;
if insert:
result[property] = (value, origin, importance, rule.specificity);
 
Outstanding issues
------------------
 
+ Parsing/selection quirks.
Probably as an argument to css_stylesheet_create() and possibly
css_style_select(). This could either take the form of a blanket
full/almost/not quirks mode flag or be more granular and permit the
toggling of individual quirks.
 
References:
 
+ http://developer.mozilla.org/en/docs/Mozilla_Quirks_Mode_Behavior
+ http://www.opera.com/docs/specs/doctype/
+ http://www.quirksmode.org/css/quirksmode.html
+ http://www.cs.tut.fi/~jkorpela/quirks-mode.html
+ Grep WebKit sources for inCompatMode()
 
+ The :lang pseudo-class
 
Need to pass the current language string into css_style_select()
 
+ Pseudo-elements
 
Probably as an argument to css_style_select(). Most likely a bitfield
like the way in which pseudo-classes are handled.
The inheritance model of :first-line and :first-letter is such that:
 
+ css_style_select() must begin with a blank style and not the
parent node's style
+ an API for cascading one style onto another is needed
 
This is because pseudo-elements may be nested inside children of the
node to which they are logically connected. e.g.:
 
<div>
<p>
first paragraph
</p>
</div>
is logically equivalent to
 
<div>
<p>
<div:first-line>
<p:first-line>
first paragraph
</p:first-line>
</div:first-line>
</p>
</div>
 
so the actual cascade order is only known at the time the render tree is
built. Note that, courtesy of scripting, the location of pseudo-elements
can move around (e.g. if some text was inserted just before the <p> within
the div, above, then <div:first-line> would move). Additionally, the actual
content that pseudo-elements apply to can change due to reflow.
 
Pseudo-elements may also affect the processing of inline boxes. e.g.:
 
<p>
<span>foo bar baz bat</span>
</p>
 
becomes (logically):
 
<p>
<p:first-line>
<span>foo bar baz </span>
</p:first-line>
<span>bat</span>
</p>
 
In terms of interaction between pseudo-elements, :first-letter inherits
from :first-line e.g.:
 
<p>
first line
second line
</p>
 
becomes (logically):
 
<p>
<p:first-line>
<p:first-letter>
f
</p:first-letter>
irst line
</p:first-line>
second line
</p>
 
:first-line and :first-letter apply to the relevant content _including_ any
text inserted using :before and :after.
 
List of CSS 3 pseudo-elements:
 
+ :(:)?first-line
+ :(:)?first-letter
+ :(:)?before
+ :(:)?after
+ ::selection
+ ::footnote-call
+ ::footnote-marker
+ ::before-page-break
+ ::after-page-break
+ ::line-number-left
+ ::line-number-right
+ ::line-number-inside
+ ::line-number-outside
+ ::slot()
+ ::value
+ ::choices
+ ::repeat-item
+ ::repeat-index
+ ::marker
+ ::outside
+ ::alternate
+ ::line-marker
 
References:
 
+ CSS 2.1 $$5.12 and $$12.1
 
+ Stylesheet charset handling
 
An embedded stylesheet shares the charset of the containing document.
 
The charset of a stand-alone stylesheet can be specified by (in order of
priority, highest -> lowest):
+ the transport layer
+ a BOM and/or @charset at the immediate start of the sheet
+ <link charset=""> or other metadata from the linking mechanism
+ charset of referring stylesheet or document
+ assuming UTF-8
 
The API currently has no way of conveying the first, third, or fourth of
these to the engine. This can be realised through the addition of a
parameter to css_stylesheet_create()
 
CSS 2.1 $4.4 specifies that a stylesheet's transport encoding must be a
superset of US-ASCII.
 
The internal encoding will be UTF-8.
 
All strings passed in by the client are assumed to be UTF-8 encoded.
Strings retrieved from DOM nodes are assumed to be UTF-8 encoded.
 
/programs/network/netsurf/netsurf/Docs/ideas/render-library.txt
0,0 → 1,121
Rendering library
=================
 
General notes
-------------
 
+ Potentially long-running routines probably want to exit early and
ask to be resumed (or similar)
+ There's loads of stuff missing from here (like a typesystem :)
 
Possible API
------------
 
/* Initialise library */
error html_init(void);
/* Finalise library */
error html_fini(void);
 
/* Create a context */
ctx html_create(void);
/* Destroy a context */
void html_destroy(ctx);
 
/* Configure a context
*
* Things that need configuring:
*
* Callbacks from library -> client:
*
* + Handler for embedded object fetch requests (how to handle frames?)
* + Event notification handler (e.g. form submission / link navigation,
* mouse pointer shape changing, redraw request, position caret, etc)
*
* Other stuff:
*
* + Scale? (should this be handled by the client?)
* + Whether to run scripts? (possibly, not needed yet)
*/
error html_setopt(ctx, opttype, optparams);
 
/* Feed HTML data to a context */
error html_process_data(ctx, data, len);
/* Flag end of data to context */
error html_data_done(ctx);
 
/* Reflow context, to given width/height */
error html_reflow(ctx, width, height);
 
/* Redraw context, using provided plotters */
error html_redraw(ctx, rect, plot_table);
 
/* Some kind of input event notification APIs.
* These are called by the client to notify the library
* that something's happened.
*
* e.g.:
*/
error html_mouse_move(ctx, x, y);
error html_mouse_press(ctx, x, y, buttons, modifiers);
error html_mouse_release(ctx, x, y, buttons, modifiers);
error html_key_press(ctx, key, modifiers);
error html_key_release(ctx, key, modifiers);
error html_scroll_x(ctx, offset);
error html_scroll_y(ctx, offset);
 
/* Retrieve properties of document in context
*
* e.g.:
*/
error html_get_title(ctx, title);
 
Example usage
-------------
 
/* Main routine */
main:
/* Initialise library */
html_init();
 
/* Create a context */
ctx = html_create();
 
/* Configure the context */
html_setopt(ctx, FETCH_HANDLER, my_fetcher);
html_setopt(ctx, EVENT_HANDLER, my_event_handler);
 
/* Get it to process data */
foreach (chunk, len) in data:
html_process_data(ctx, chunk, len);
html_data_done(ctx);
 
/* Reflow content to desired dimensions */
html_reflow(ctx, width, height);
 
/* Main client event loop -- processes UI-toolkit events */
do:
on mouse event:
html_mouse_{move,press,release}(ctx, event.x, event.y ...);
on key event:
html_key_{press,release}{ctx, event.key, event.modifiers);
on scroll event:
html_scroll_{x,y}(ctx, event.offset);
on redraw event:
html_redraw(ctx, event.rect, my_plotters);
until quit;
 
/* Destroy context */
html_destroy(ctx);
 
/* Finalise library */
html_fini();
 
/* Event handler for library-generated events */
my_event_handler:
on pointer shape change:
set_pointer_shape(shape);
on redraw request:
redraw_window(window);
on position caret:
position caret(x, y);
 
/programs/network/netsurf/netsurf/Makebig
0,0 → 1,263
# ----------------------------------------------------------------------------
# Options relating to all versions of NetSurf
# ----------------------------------------------------------------------------
 
# Enable NetSurf's use of libnsbmp for displaying BMPs and ICOs
# Valid options: YES, NO
NETSURF_USE_BMP := YES
 
# Enable NetSurf's use of libnsgif for displaying GIFs
# Valid options: YES, NO (highly recommended)
NETSURF_USE_GIF := YES
 
# Enable NetSurf's use of libjpeg for displaying JPEGs
# Valid options: YES, NO (highly recommended)
NETSURF_USE_JPEG := YES
 
# Enable NetSurf's use of libpng for displaying PNGs. If MNG and PNG
# are both enabled then NetSurf will choose libpng for PNGs, leaving
# MNGs and JNGs to libmng.
# Valid options: YES, NO (at least one of PNG/MNG highly recommended)
NETSURF_USE_PNG := NO
 
# Enable NetSurf's use of libmng for displaying MNGs, JNGs and PNGs
# Valid options: YES, NO (at least one of PNG/MNG highly recommended)
NETSURF_USE_MNG := NO
 
# Enable NetSurf's use of libwebp for displaying WebPs
# Valid options: YES, NO
NETSURF_USE_WEBP := NO
 
# Enable NetSurf's use of gstreamer for displaying videos
# Valid options: YES, NO
NETSURF_USE_VIDEO := NO
 
# Enable NetSurf's use of spidermonkey for javascript
# Valid options: YES, NO, AUTO
NETSURF_USE_JS := NO
# Javascript support in older debian/ubuntu versions
NETSURF_USE_MOZJS := NO
 
# Enable NetSurf's use of libharu for PDF export and GTK printing support.
# There is no auto-detection available for this, as it does not have a
# pkg-config file.
# Valid options: YES, NO
NETSURF_USE_HARU_PDF := NO
 
# Enable stripping the NetSurf binary
# Valid options: YES, NO
NETSURF_STRIP_BINARY := NO
 
# Template used for constructing the User Agent: string. The first two
# replacements are major/minor version, next is OS.
# Please don't be tempted to mention Mozilla here! Let's let that lie die.
NETSURF_UA_FORMAT_STRING := "NetSurf/%d.%d (%s)"
 
# Default home page, if one is not defined by the user. Note that this
# option does not apply to the RISC OS version, as it has its own local
# home page, and it can be changed by editing the end of gui_init2() in
# riscos/gui.c
NETSURF_HOMEPAGE := "about:welcome"
 
# Force using glibc internal iconv implementation instead of external libiconv
# Valid options: YES, NO
NETSURF_USE_LIBICONV_PLUG := YES
 
# Optimisation levels
CFLAGS += -O2
 
# Framebuffer default surface provider.
# Valid values are: x, sdl, linux, vnc, able,
NETSURF_FB_FRONTEND := sdl
 
# Use libharu to enable PDF export and GTK printing support.
# Valid options: YES, NO
NETSURF_USE_HARU_PDF := NO
 
# Enable NetSurf's use of librosprite for displaying RISC OS Sprites
# Valid options: YES, NO, AUTO
NETSURF_USE_ROSPRITE := NO
 
# Library to use for font plotting
# Valid options: internal, freetype
NETSURF_FB_FONTLIB := internal
 
# Default freetype font files
NETSURF_FB_FONT_SANS_SERIF := DejaVuSans.ttf
NETSURF_FB_FONT_SANS_SERIF_BOLD := DejaVuSans-Bold.ttf
NETSURF_FB_FONT_SANS_SERIF_ITALIC := DejaVuSans-Oblique.ttf
NETSURF_FB_FONT_SANS_SERIF_ITALIC_BOLD := DejaVuSans-BoldOblique.ttf
NETSURF_FB_FONT_SERIF := DejaVuSerif.ttf
NETSURF_FB_FONT_SERIF_BOLD := DejaVuSerif-Bold.ttf
NETSURF_FB_FONT_MONOSPACE := DejaVuSansMono.ttf
NETSURF_FB_FONT_MONOSPACE_BOLD := DejaVuSansMono-Bold.ttf
NETSURF_FB_FONT_CURSIVE := Comic_Sans_MS.ttf
NETSURF_FB_FONT_FANTASY := Impact.ttf
 
PREFIX ?= /usr/local
 
# Default binary install path
NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
 
# Default resource install path
NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
 
# Default framebuffer search path
NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
 
# freetype compiled in font serch path
NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
 
 
#
# NetSurf source file inclusion
#
# Included by main makefile -- indicates generic sources for every build.
#
 
S_CONTENT := content.c content_factory.c dirlist.c fetch.c hlcache.c \
llcache.c mimesniff.c urldb.c
 
S_FETCHERS := curl.c data.c file.c about.c resource.c
 
S_CSS := css.c dump.c internal.c select.c utils.c
 
S_RENDER := box.c box_construct.c box_normalise.c \
font.c form.c \
html.c html_script.c html_interaction.c html_redraw.c \
html_forms.c imagemap.c layout.c list.c search.c table.c \
textinput.c textplain.c
 
S_UTILS := base64.c corestrings.c filename.c filepath.c hashtable.c \
libdom.c locale.c log.c messages.c nsurl.c talloc.c url.c \
utf8.c utils.c useragent.c
 
S_HTTP := challenge.c generics.c primitives.c parameter.c \
content-disposition.c content-type.c www-authenticate.c
 
S_DESKTOP := cookies.c history_global_core.c hotlist.c knockout.c \
mouse.c options.c plot_style.c print.c search.c searchweb.c \
scrollbar.c sslcert.c textarea.c thumbnail.c tree.c \
tree_url_node.c version.c
 
# Javascript source
include Makefile.sources.javascript
 
# S_COMMON are sources common to all builds
S_COMMON := $(addprefix content/,$(S_CONTENT)) \
$(addprefix content/fetchers/,$(S_FETCHERS)) \
$(addprefix css/,$(S_CSS)) \
$(addprefix render/,$(S_RENDER)) \
$(addprefix utils/,$(S_UTILS)) \
$(addprefix utils/http/,$(S_HTTP)) \
$(addprefix desktop/,$(S_DESKTOP)) \
$(addprefix javascript/,$(S_JAVASCRIPT)) \
$(S_JSAPI_BINDING)
 
# S_IMAGE are sources related to image management
S_IMAGE_YES := image.c image_cache.c
S_IMAGE_NO :=
S_IMAGE_$(NETSURF_USE_BMP) += bmp.c ico.c
S_IMAGE_$(NETSURF_USE_GIF) += gif.c
S_IMAGE_$(NETSURF_USE_JPEG) += jpeg.c
S_IMAGE_$(NETSURF_USE_MNG) += mng.c
S_IMAGE_$(NETSURF_USE_ROSPRITE) += nssprite.c
S_IMAGE_$(NETSURF_USE_PNG) += png.c
S_IMAGE_$(NETSURF_USE_NSSVG) += svg.c
S_IMAGE_$(NETSURF_USE_RSVG) += rsvg.c
S_IMAGE_$(NETSURF_USE_WEBP) += webp.c
S_IMAGE_$(NETSURF_USE_VIDEO) += video.c
 
S_IMAGE := $(addprefix image/,$(S_IMAGE_YES))
 
# S_PDF are sources of the pdf plotter + the ones for paged-printing
S_PDF := pdf_plotters.c font_haru.c
S_PDF := $(addprefix desktop/save_pdf/,$(S_PDF))
 
# S_BROWSER are sources related to full browsers but are common
# between RISC OS, GTK, BeOS and AmigaOS builds
S_BROWSER := browser.c download.c frames.c history_core.c netsurf.c \
save_complete.c save_text.c selection.c textinput.c
 
S_BROWSER := $(addprefix desktop/,$(S_BROWSER))
 
 
 
$(eval $(call feature_enabled,MNG,-DWITH_MNG,-lmng,PNG/MNG/JNG (libmng)))
$(eval $(call feature_enabled,PNG,-DWITH_PNG,-lpng,PNG (libpng) ))
 
ifeq ($(NETSURF_FB_FONTLIB),freetype)
CFLAGS += -DFB_USE_FREETYPE $(shell freetype-config --cflags)
LDFLAGS += $(shell freetype-config --libs)
endif
 
# define additional CFLAGS and LDFLAGS requirements for pkg-configed libs here
NETSURF_FEATURE_RSVG_CFLAGS := -DWITH_RSVG
NETSURF_FEATURE_ROSPRITE_CFLAGS := -DWITH_NSSPRITE
NETSURF_FEATURE_HUBBUB_CFLAGS := -DWITH_HUBBUB
NETSURF_FEATURE_BMP_CFLAGS := -DWITH_BMP
NETSURF_FEATURE_GIF_CFLAGS := -DWITH_GIF
NETSURF_FEATURE_JS_CFLAGS := -DWITH_JS -DJS_HAS_FILE_OBJECT=0
NETSURF_FEATURE_MOZJS_CFLAGS := -DWITH_MOZJS -DJS_HAS_FILE_OBJECT=0
 
CFLAGS += -Dnsframebuffer
 
#resource path
CFLAGS += '-DNETSURF_FB_RESPATH="$(NETSURF_FB_RESPATH)"'
 
# compile time font locations
CFLAGS += '-DNETSURF_FB_FONTPATH="$(NETSURF_FB_FONTPATH)"'
CFLAGS += '-DNETSURF_FB_FONT_SANS_SERIF="$(NETSURF_FB_FONT_SANS_SERIF)"'
CFLAGS += '-DNETSURF_FB_FONT_SANS_SERIF_BOLD="$(NETSURF_FB_FONT_SANS_SERIF_BOLD)"'
CFLAGS += '-DNETSURF_FB_FONT_SANS_SERIF_ITALIC="$(NETSURF_FB_FONT_SANS_SERIF_ITALIC)"'
CFLAGS += '-DNETSURF_FB_FONT_SANS_SERIF_ITALIC_BOLD="$(NETSURF_FB_FONT_SANS_SERIF_ITALIC_BOLD)"'
CFLAGS += '-DNETSURF_FB_FONT_SERIF="$(NETSURF_FB_FONT_SERIF)"'
CFLAGS += '-DNETSURF_FB_FONT_SERIF_BOLD="$(NETSURF_FB_FONT_SERIF_BOLD)"'
CFLAGS += '-DNETSURF_FB_FONT_MONOSPACE="$(NETSURF_FB_FONT_MONOSPACE)"'
CFLAGS += '-DNETSURF_FB_FONT_MONOSPACE_BOLD="$(NETSURF_FB_FONT_MONOSPACE_BOLD)"'
CFLAGS += '-DNETSURF_FB_FONT_CURSIVE="$(NETSURF_FB_FONT_CURSIVE)"'
CFLAGS += '-DNETSURF_FB_FONT_FANTASY="$(NETSURF_FB_FONT_FANTASY)"'
 
$(eval $(call pkg_config_find_and_add_enabled,ROSPRITE,librosprite,Sprite))
$(eval $(call pkg_config_find_and_add_enabled,BMP,libnsbmp,BMP))
$(eval $(call pkg_config_find_and_add_enabled,GIF,libnsgif,GIF))
$(eval $(call pkg_config_find_and_add_enabled,MOZJS,mozjs185,JavaScript))
$(eval $(call pkg_config_find_and_add_enabled,JS,mozilla-js,JavaScript))
 
 
# ----------------------------------------------------------------------------
# Source file setup
# ----------------------------------------------------------------------------
 
# S_FRAMEBUFFER are sources purely for the framebuffer build
S_FRAMEBUFFER := gui.c framebuffer.c tree.c schedule.c \
thumbnail.c misc.c bitmap.c filetype.c login.c findfile.c \
localhistory.c system_colour.c clipboard.c
 
S_FRAMEBUFFER_FBTK := fbtk.c event.c fill.c bitmap.c user.c window.c \
text.c scroll.c osk.c
 
S_FRAMEBUFFER += font_$(NETSURF_FB_FONTLIB).c
 
ifeq ($(NETSURF_FB_FONTLIB),internal)
S_FRAMEBUFFER += nsfont_regular.c nsfont_italic.c nsfont_bold.c \
nsfont_italic_bold.c
endif
 
S_FRAMEBUFFER := $(addprefix framebuffer/,$(S_FRAMEBUFFER)) $(addprefix framebuffer/fbtk/,$(S_FRAMEBUFFER_FBTK))
 
# This is the final source build list
# Note this is deliberately *not* expanded here as common and image
# are not yet available
SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_FRAMEBUFFER) $(S_IMAGES)
EXETARGET := nsfb
 
# ----------------------------------------------------------------------------
# Install target
# ----------------------------------------------------------------------------
 
NETSURF_FRAMEBUFFER_RESOURCE_LIST := adblock.css credits.html \
default.css internal.css licence.html \
netsurf.png quirks.css welcome.html
 
 
/programs/network/netsurf/netsurf/Makefile
0,0 → 1,720
#
# Makefile for NetSurf
#
# Copyright 2007 Daniel Silverstone <dsilvers@netsurf-browser.org>
# Copyright 2008 Rob Kendrick <rjek@netsurf-browser.org>
#
# Trivially, invoke as:
# make
# to build native, or:
# make TARGET=riscos
# to cross-build for RO.
#
# Look at Makefile.config for configuration options.
#
# Tested on unix platforms (building for GTK and cross-compiling for RO) and
# on RO (building for RO).
#
# To clean, invoke as above, with the 'clean' target
#
# To build developer Doxygen generated documentation, invoke as above,
# with the 'docs' target:
# make docs
#
 
all: all-program
 
# Determine host type
# NOTE: HOST determination on RISC OS could fail because of missing bug fixes
# in UnixLib which only got addressed in UnixLib 5 / GCCSDK 4.
# When you don't have 'uname' available, you will see:
# File 'uname' not found
# When you do and using a 'uname' compiled with a buggy UnixLib, you
# will see the following printed on screen:
# RISC OS
# In both cases HOST make variable is empty and we recover from that by
# assuming we're building on RISC OS.
# In case you don't see anything printed (including the warning), you
# have an up-to-date RISC OS build system. ;-)
HOST := $(shell uname -s)
 
# Sanitise host
# TODO: Ideally, we want the equivalent of s/[^A-Za-z0-9]/_/g here
HOST := $(subst .,_,$(subst -,_,$(subst /,_,$(HOST))))
 
ifeq ($(HOST),)
HOST := riscos
$(warning Build platform determination failed but that's a known problem for RISC OS so we're assuming a native RISC OS build.)
else
ifeq ($(HOST),RISC OS)
# Fixup uname -s returning "RISC OS"
HOST := riscos
endif
endif
 
ifeq ($(HOST),riscos)
# Build happening on RO platform, default target is RO backend
ifeq ($(TARGET),)
TARGET := riscos
endif
else
ifeq ($(HOST),BeOS)
HOST := beos
endif
ifeq ($(HOST),Haiku)
# Haiku implements the BeOS API
HOST := beos
endif
ifeq ($(HOST),beos)
# Build happening on BeOS platform, default target is BeOS backend
ifeq ($(TARGET),)
TARGET := beos
endif
else
ifeq ($(HOST),AmigaOS)
HOST := amiga
ifeq ($(TARGET),)
TARGET := amiga
endif
else
ifeq ($(HOST),Darwin)
HOST := macosx
ifeq ($(TARGET),)
TARGET := cocoa
endif
endif
ifeq ($(HOST),FreeMiNT)
HOST := mint
endif
ifeq ($(HOST),mint)
ifeq ($(TARGET),)
TARGET := atari
endif
endif
ifeq ($(findstring MINGW,$(HOST)),MINGW)
# MSYS' uname reports the likes of "MINGW32_NT-6.0"
HOST := windows
endif
ifeq ($(HOST),windows)
ifeq ($(TARGET),)
TARGET := windows
endif
endif
 
# Default target is GTK backend
ifeq ($(TARGET),)
TARGET := gtk
endif
endif
endif
endif
SUBTARGET =
RESOURCES =
 
ifneq ($(TARGET),riscos)
ifneq ($(TARGET),gtk)
ifneq ($(TARGET),beos)
ifneq ($(findstring amiga,$(TARGET)),amiga)
ifneq ($(TARGET),framebuffer)
ifneq ($(TARGET),windows)
ifneq ($(TARGET),atari)
ifneq ($(TARGET),cocoa)
ifneq ($(TARGET),monkey)
$(error Unknown TARGET "$(TARGET)", should either be "riscos", "gtk", "beos", "amiga", "framebuffer", "windows", "atari" or "cocoa" or "monkey")
endif
endif
endif
endif
endif
endif
endif
endif
endif
 
Q=@
VQ=@
PERL=perl
MKDIR=mkdir
TOUCH=touch
STRIP=strip
 
# Override this only if the host compiler is called something different
HOST_CC := gcc
 
ifeq ($(TARGET),riscos)
ifeq ($(HOST),riscos)
# Build for RO on RO
GCCSDK_INSTALL_ENV := <NSLibs$$Dir>
CCRES := ccres
TPLEXT :=
MAKERUN := makerun
SQUEEZE := squeeze
RUNEXT :=
CC := gcc
CXX := g++
EXEEXT :=
PKG_CONFIG :=
else
# Cross-build for RO (either using GCCSDK 3.4.6 - AOF,
# either using GCCSDK 4 - ELF)
ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
ifneq ($(realpath /opt/netsurf/arm-unknown-riscos/env),)
GCCSDK_INSTALL_ENV := /opt/netsurf/arm-unknown-riscos/env
else
GCCSDK_INSTALL_ENV := /home/riscos/env
endif
endif
 
ifeq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
ifneq ($(realpath /opt/netsurf/arm-unknown-riscos/cross/bin),)
GCCSDK_INSTALL_CROSSBIN := /opt/netsurf/arm-unknown-riscos/cross/bin
else
GCCSDK_INSTALL_CROSSBIN := /home/riscos/cross/bin
endif
endif
 
CCRES := $(GCCSDK_INSTALL_CROSSBIN)/ccres
TPLEXT := ,fec
MAKERUN := $(GCCSDK_INSTALL_CROSSBIN)/makerun
SQUEEZE := $(GCCSDK_INSTALL_CROSSBIN)/squeeze
RUNEXT := ,feb
CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
ifneq (,$(findstring arm-unknown-riscos-gcc,$(CC)))
SUBTARGET := -elf
EXEEXT := ,e1f
ELF2AIF := $(GCCSDK_INSTALL_CROSSBIN)/elf2aif
else
SUBTARGET := -aof
EXEEXT := ,ff8
endif
CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
PKG_CONFIG := $(GCCSDK_INSTALL_ENV)/ro-pkg-config
endif
else
ifeq ($(TARGET),beos)
# Building for BeOS/Haiku
#ifeq ($(HOST),beos)
# Build for BeOS on BeOS
GCCSDK_INSTALL_ENV := /boot/develop
CC := gcc
CXX := g++
EXEEXT :=
PKG_CONFIG :=
#endif
else
ifeq ($(TARGET),windows)
ifneq ($(HOST),windows)
# Set Mingw defaults
GCCSDK_INSTALL_ENV ?= /opt/netsurf/i686-w64-mingw32/env
GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/i686-w64-mingw32/cross/bin
 
CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
WINDRES := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*windres)
 
PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
else
# Building on Windows
CC := gcc
PKG_CONFIG :=
endif
else
ifeq ($(findstring amiga,$(TARGET)),amiga)
ifeq ($(findstring amiga,$(HOST)),amiga)
PKG_CONFIG := pkg-config
else
ifeq ($(TARGET),amigaos3)
GCCSDK_INSTALL_ENV ?= /opt/netsurf/m68k-unknown-amigaos/env
GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/m68k-unknown-amigaos/cross/bin
 
SUBTARGET = os3
else
GCCSDK_INSTALL_ENV ?= /opt/netsurf/ppc-amigaos/env
GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/ppc-amigaos/cross/bin
endif
 
override TARGET := amiga
 
CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
 
PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
endif
else
ifeq ($(TARGET),cocoa)
PKG_CONFIG := PKG_CONFIG_PATH="$(PKG_CONFIG_PATH):/usr/local/lib/pkgconfig" pkg-config
else
ifeq ($(TARGET),atari)
ifeq ($(HOST),atari)
PKG_CONFIG := pkg-config
else
ifeq ($(HOST),mint)
PKG_CONFIG := pkg-config
else
GCCSDK_INSTALL_ENV ?= /opt/netsurf/m68k-atari-mint/env
GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/m68k-atari-mint/cross/bin
 
CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
 
PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
endif
endif
else
ifeq ($(TARGET),monkey)
ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
PKG_CONFIG := pkg-config
else
PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
endif
 
ifneq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
endif
else
# All other targets (GTK, Framebuffer)
PKG_CONFIG := pkg-config
endif
endif
endif
endif
endif
endif
endif
 
# compiler versioning to adjust warning flags
CC_VERSION := $(shell $(CC) -dumpversion)
CC_MAJOR := $(word 1,$(subst ., ,$(CC_VERSION)))
CC_MINOR := $(word 2,$(subst ., ,$(CC_VERSION)))
define cc_ver_ge
$(shell expr $(CC_MAJOR) \>= $(1) \& $(CC_MINOR) \>= $(2))
endef
 
# CCACHE
ifeq ($(origin CCACHE),undefined)
CCACHE=$(word 1,$(shell ccache -V 2>/dev/null))
endif
CC := $(CCACHE) $(CC)
 
# Target paths
OBJROOT = build-$(HOST)-$(TARGET)$(SUBTARGET)
DEPROOT := $(OBJROOT)/deps
TOOLROOT := $(OBJROOT)/tools
 
 
# 1: Feature name (ie, NETSURF_USE_BMP -> BMP)
# 2: Parameters to add to CFLAGS
# 3: Parameters to add to LDFLAGS
# 4: Human-readable name for the feature
define feature_enabled
ifeq ($$(NETSURF_USE_$(1)),YES)
CFLAGS += $(2)
LDFLAGS += $(3)
ifneq ($(MAKECMDGOALS),clean)
$$(info M.CONFIG: $(4) enabled (NETSURF_USE_$(1) := YES))
endif
else ifeq ($$(NETSURF_USE_$(1)),NO)
ifneq ($(MAKECMDGOALS),clean)
$$(info M.CONFIG: $(4) disabled (NETSURF_USE_$(1) := NO))
endif
else
$$(info M.CONFIG: $(4) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
$$(error NETSURF_USE_$(1) must be YES or NO)
endif
endef
 
# Extend flags with appropriate values from pkg-config for enabled features
#
# 1: pkg-config required modules for feature
# 2: Human-readable name for the feature
define pkg_config_find_and_add
ifeq ($$(PKG_CONFIG),)
$$(error pkg-config is required to auto-detect feature availability)
endif
 
PKG_CONFIG_$(1)_EXISTS := $$(shell $$(PKG_CONFIG) --exists $(1) && echo yes)
 
ifeq ($$(PKG_CONFIG_$(1)_EXISTS),yes)
CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(1))
LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(1))
ifneq ($(MAKECMDGOALS),clean)
$$(info PKG.CNFG: $(2) ($(1)) enabled)
endif
else
ifneq ($(MAKECMDGOALS),clean)
$$(info PKG.CNFG: $(2) ($(1)) failed)
$$(error Unable to find library for: $(2) ($(1)))
endif
endif
endef
 
# Extend flags with appropriate values from pkg-config for enabled features
#
# 1: Feature name (ie, NETSURF_USE_RSVG -> RSVG)
# 2: pkg-config required modules for feature
# 3: Human-readable name for the feature
define pkg_config_find_and_add_enabled
ifeq ($$(PKG_CONFIG),)
$$(error pkg-config is required to auto-detect feature availability)
endif
 
NETSURF_FEATURE_$(1)_AVAILABLE := $$(shell $$(PKG_CONFIG) --exists $(2) && echo yes)
 
ifeq ($$(NETSURF_USE_$(1)),YES)
ifeq ($$(NETSURF_FEATURE_$(1)_AVAILABLE),yes)
CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(2)) $$(NETSURF_FEATURE_$(1)_LDFLAGS)
ifneq ($(MAKECMDGOALS),clean)
$$(info M.CONFIG: $(3) ($(2)) enabled (NETSURF_USE_$(1) := YES))
endif
else
ifneq ($(MAKECMDGOALS),clean)
$$(info M.CONFIG: $(3) ($(2)) failed (NETSURF_USE_$(1) := YES))
$$(error Unable to find library for: $(3) ($(2)))
endif
endif
else ifeq ($$(NETSURF_USE_$(1)),AUTO)
ifeq ($$(NETSURF_FEATURE_$(1)_AVAILABLE),yes)
CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(2)) $$(NETSURF_FEATURE_$(1)_LDFLAGS)
ifneq ($(MAKECMDGOALS),clean)
$$(info M.CONFIG: $(3) ($(2)) auto-enabled (NETSURF_USE_$(1) := AUTO))
NETSURF_USE_$(1) := YES
endif
else
ifneq ($(MAKECMDGOALS),clean)
$$(info M.CONFIG: $(3) ($(2)) auto-disabled (NETSURF_USE_$(1) := AUTO))
NETSURF_USE_$(1) := NO
endif
endif
else ifeq ($$(NETSURF_USE_$(1)),NO)
ifneq ($(MAKECMDGOALS),clean)
$$(info M.CONFIG: $(3) ($(2)) disabled (NETSURF_USE_$(1) := NO))
endif
else
ifneq ($(MAKECMDGOALS),clean)
$$(info M.CONFIG: $(3) ($(2)) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
$$(error NETSURF_USE_$(1) must be YES, NO, or AUTO)
endif
endif
endef
 
# ----------------------------------------------------------------------------
# General flag setup
# ----------------------------------------------------------------------------
 
# Set up the WARNFLAGS here so that they can be overridden in the Makefile.config
WARNFLAGS = -W -Wall -Wundef -Wpointer-arith \
-Wcast-align -Wwrite-strings -Wstrict-prototypes \
-Wmissing-prototypes -Wmissing-declarations -Wredundant-decls \
-Wnested-externs -Wuninitialized
ifneq ($(CC_MAJOR),2)
WARNFLAGS += -Wno-unused-parameter
endif
# deal with lots of unwanted warnings from javascript
ifeq ($(call cc_ver_ge,4,6),1)
WARNFLAGS += -Wno-unused-but-set-variable
endif
 
# Pull in the configuration
include Makefile.defaults
 
$(eval $(call feature_enabled,JPEG,-DWITH_JPEG,-ljpeg,JPEG (libjpeg)))
$(eval $(call feature_enabled,MNG,-DWITH_MNG,-lmng,JNG/MNG/PNG (libmng)))
 
$(eval $(call feature_enabled,HARU_PDF,-DWITH_PDF_EXPORT,-lhpdf -lpng,PDF export (haru)))
$(eval $(call feature_enabled,LIBICONV_PLUG,-DLIBICONV_PLUG,,glibc internal iconv))
 
# common libraries without pkg-config support
LDFLAGS += -lz
 
# add top level and build directory to include search path
CFLAGS += -I. -I$(OBJROOT)
 
# export the user agent format
CFLAGS += -DNETSURF_UA_FORMAT_STRING=\"$(NETSURF_UA_FORMAT_STRING)\"
 
# set the default homepage to use
CFLAGS += -DNETSURF_HOMEPAGE=\"$(NETSURF_HOMEPAGE)\"
 
# ----------------------------------------------------------------------------
# General make rules
# ----------------------------------------------------------------------------
 
$(OBJROOT)/created:
$(VQ)echo " MKDIR: $(OBJROOT)"
$(Q)$(MKDIR) $(OBJROOT)
$(Q)$(TOUCH) $(OBJROOT)/created
 
$(DEPROOT)/created: $(OBJROOT)/created
$(VQ)echo " MKDIR: $(DEPROOT)"
$(Q)$(MKDIR) $(DEPROOT)
$(Q)$(TOUCH) $(DEPROOT)/created
 
$(TOOLROOT)/created: $(OBJROOT)/created
$(VQ)echo " MKDIR: $(TOOLROOT)"
$(Q)$(MKDIR) $(TOOLROOT)
$(Q)$(TOUCH) $(TOOLROOT)/created
 
CLEANS := clean-target clean-testament
 
POSTEXES :=
 
# ----------------------------------------------------------------------------
# Target specific setup
# ----------------------------------------------------------------------------
 
include $(TARGET)/Makefile.target
 
# ----------------------------------------------------------------------------
# General source file setup
# ----------------------------------------------------------------------------
 
include Makefile.sources
 
# ----------------------------------------------------------------------------
# Source file setup
# ----------------------------------------------------------------------------
 
# Force exapnsion of source file list
SOURCES := $(SOURCES)
 
ifeq ($(SOURCES),)
$(error Unable to build NetSurf, could not determine set of sources to build)
endif
 
OBJECTS := $(sort $(addprefix $(OBJROOT)/,$(subst /,_,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(patsubst %.m,%.o,$(patsubst %.s,%.o,$(SOURCES))))))))
 
$(EXETARGET): $(OBJECTS) $(RESOURCES)
$(VQ)echo " LINK: $(EXETARGET)"
ifneq ($(TARGET)$(SUBTARGET),riscos-elf)
$(Q)$(CC) -o $(EXETARGET) $(OBJECTS) $(LDFLAGS)
else
$(Q)$(CXX) -o $(EXETARGET:,ff8=,e1f) $(OBJECTS) $(LDFLAGS)
$(Q)$(ELF2AIF) $(EXETARGET:,ff8=,e1f) $(EXETARGET)
$(Q)$(RM) $(EXETARGET:,ff8=,e1f)
endif
ifeq ($(TARGET),windows)
$(Q)$(TOUCH) windows/res/preferences
endif
ifeq ($(TARGET),gtk)
$(Q)$(TOUCH) gtk/res/toolbarIndices
endif
ifeq ($(NETSURF_STRIP_BINARY),YES)
$(VQ)echo " STRIP: $(EXETARGET)"
$(Q)$(STRIP) $(EXETARGET)
endif
ifeq ($(TARGET),beos)
$(VQ)echo " XRES: $(EXETARGET)"
$(Q)$(BEOS_XRES) -o $(EXETARGET) $(RSRC_BEOS)
$(VQ)echo " SETVER: $(EXETARGET)"
$(Q)$(BEOS_SETVER) $(EXETARGET) \
-app $(VERSION_MAJ) $(VERSION_MIN) 0 d 0 \
-short "NetSurf $(VERSION_FULL)" \
-long "NetSurf $(VERSION_FULL) © 2003 - 2012 The NetSurf Developers"
$(VQ)echo " MIMESET: $(EXETARGET)"
$(Q)$(BEOS_MIMESET) $(EXETARGET)
endif
 
ifeq ($(TARGET),beos)
$(RDEF_IMP_BEOS): $(RDEP_BEOS)
$(VQ)echo " GEN: $@"
$(Q)n=5000; for f in $^; do echo "resource($$n,\"$${f#beos/res/}\") #'data' import \"$${f#beos/}\";"; n=$$(($$n+1)); done > $@
 
$(RSRC_BEOS): $(RDEF_BEOS) $(RDEF_IMP_BEOS)
$(VQ)echo " RC: $<"
$(Q)$(BEOS_RC) -I beos -o $@ $^
endif
 
ifeq ($(TARGET),riscos)
# Native RO build is different as 1) it can't do piping and 2) ccres on
# RO does not understand Unix filespec
ifeq ($(HOST),riscos)
define compile_template
!NetSurf/Resources/$(1)/Templates$$(TPLEXT): $(2)
$$(VQ)echo "TEMPLATE: $(2)"
$$(Q)$$(CC) -x c -E -P $$(CFLAGS) -o processed_template $(2)
$$(Q)$$(CCRES) processed_template $$(subst /,.,$$@)
$$(Q)$(RM) processed_template
CLEAN_TEMPLATES += !NetSurf/Resources/$(1)/Templates$$(TPLEXT)
 
endef
else
define compile_template
!NetSurf/Resources/$(1)/Templates$$(TPLEXT): $(2)
$$(VQ)echo "TEMPLATE: $(2)"
$$(Q)mkdir -p !NetSurf/Resources/$(1)
$$(Q)$$(CC) -x c -E -P $$(CFLAGS) $(2) | $$(CCRES) - $$@
CLEAN_TEMPLATES += !NetSurf/Resources/$(1)/Templates$$(TPLEXT)
 
endef
endif
 
clean-templates:
$(VQ)echo " CLEAN: $(CLEAN_TEMPLATES)"
$(Q)$(RM) $(CLEAN_TEMPLATES)
CLEANS += clean-templates
 
$(eval $(foreach TPL,$(TPL_RISCOS), \
$(call compile_template,$(notdir $(TPL)),$(TPL))))
endif
 
clean-target:
$(VQ)echo " CLEAN: $(EXETARGET)"
$(Q)$(RM) $(EXETARGET)
 
clean-testament:
$(VQ)echo " CLEAN: utils/testament.h"
$(Q)$(RM) utils/testament.h
 
clean-builddir:
$(VQ)echo " CLEAN: $(OBJROOT)"
$(Q)$(RM) -r $(OBJROOT)
CLEANS += clean-builddir
 
all-program: $(EXETARGET) post-exe
 
.PHONY: testament
testament utils/testament.h:
$(Q)if test -d .svn; then \
$(PERL) utils/svn-testament.pl $(CURDIR) utils/testament.h; \
else \
$(PERL) utils/git-testament.pl $(CURDIR) utils/testament.h; \
fi
 
post-exe: $(POSTEXES)
 
.SUFFIXES:
 
DEPFILES :=
# Now some macros which build the make system
 
# 1 = Source file
# 2 = dep filename, no prefix
# 3 = obj filename, no prefix
define dependency_generate_c
DEPFILES += $(2)
$$(DEPROOT)/$(2): $$(DEPROOT)/created $(1) Makefile.config
 
endef
 
# 1 = Source file
# 2 = dep filename, no prefix
# 3 = obj filename, no prefix
define dependency_generate_s
DEPFILES += $(2)
$$(DEPROOT)/$(2): $$(DEPROOT)/created $(1)
 
endef
 
# 1 = Source file
# 2 = obj filename, no prefix
# 3 = dep filename, no prefix
ifeq ($(CC_MAJOR),2)
# simpler deps tracking for gcc2...
define compile_target_c
$$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
$$(VQ)echo " DEP: $(1)"
$$(Q)$$(RM) $$(DEPROOT)/$(3)
$$(Q)$$(CC) $$(CFLAGS) -MM \
$(1) | sed 's,^.*:,$$(DEPROOT)/$(3) $$(OBJROOT)/$(2):,' \
> $$(DEPROOT)/$(3)
$$(VQ)echo " COMPILE: $(1)"
$$(Q)$$(RM) $$(OBJROOT)/$(2)
$$(Q)$$(CC) $$(CFLAGS) -o $$(OBJROOT)/$(2) -c $(1)
 
endef
else
define compile_target_c
$$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
$$(VQ)echo " COMPILE: $(1)"
$$(Q)$$(RM) $$(DEPROOT)/$(3)
$$(Q)$$(RM) $$(OBJROOT)/$(2)
$$(Q)$$(CC) $$(CFLAGS) -MMD -MT '$$(DEPROOT)/$(3) $$(OBJROOT)/$(2)' \
-MF $$(DEPROOT)/$(3) -o $$(OBJROOT)/$(2) -c $(1)
 
endef
endif
 
define compile_target_cpp
$$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
$$(VQ)echo " DEP: $(1)"
$$(Q)$$(RM) $$(DEPROOT)/$(3)
$$(Q)$$(CC) $$(CFLAGS) -MM \
$(1) | sed 's,^.*:,$$(DEPROOT)/$(3) $$(OBJROOT)/$(2):,' \
> $$(DEPROOT)/$(3)
$$(VQ)echo " COMPILE: $(1)"
$$(Q)$$(RM) $$(OBJROOT)/$(2)
$$(Q)$$(CXX) $$(CFLAGS) -o $$(OBJROOT)/$(2) -c $(1)
 
endef
 
# 1 = Source file
# 2 = obj filename, no prefix
# 3 = dep filename, no prefix
define compile_target_s
$$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
$$(VQ)echo "ASSEMBLE: $(1)"
$$(Q)$$(RM) $$(DEPROOT)/$(3)
$$(Q)$$(RM) $$(OBJROOT)/$(2)
$$(Q)$$(CC) $$(ASFLAGS) -MMD -MT '$$(DEPROOT)/$(3) $$(OBJROOT)/$(2)' \
-MF $$(DEPROOT)/$(3) -o $$(OBJROOT)/$(2) -c $(1)
 
endef
 
# Rules to construct dep lines for each object...
$(eval $(foreach SOURCE,$(filter %.c,$(SOURCES)), \
$(call dependency_generate_c,$(SOURCE),$(subst /,_,$(SOURCE:.c=.d)),$(subst /,_,$(SOURCE:.c=.o)))))
 
$(eval $(foreach SOURCE,$(filter %.cpp,$(SOURCES)), \
$(call dependency_generate_c,$(SOURCE),$(subst /,_,$(SOURCE:.cpp=.d)),$(subst /,_,$(SOURCE:.cpp=.o)))))
 
$(eval $(foreach SOURCE,$(filter %.m,$(SOURCES)), \
$(call dependency_generate_c,$(SOURCE),$(subst /,_,$(SOURCE:.m=.d)),$(subst /,_,$(SOURCE:.m=.o)))))
 
# Cannot currently generate dep files for S files because they're objasm
# when we move to gas format, we will be able to.
 
#$(eval $(foreach SOURCE,$(filter %.s,$(SOURCES)), \
# $(call dependency_generate_s,$(SOURCE),$(subst /,_,$(SOURCE:.s=.d)),$(subst /,_,$(SOURCE:.s=.o)))))
 
ifneq ($(MAKECMDGOALS),clean)
-include $(sort $(addprefix $(DEPROOT)/,$(DEPFILES)))
-include $(D_JSAPI_BINDING)
endif
 
# And rules to build the objects themselves...
 
$(eval $(foreach SOURCE,$(filter %.c,$(SOURCES)), \
$(call compile_target_c,$(SOURCE),$(subst /,_,$(SOURCE:.c=.o)),$(subst /,_,$(SOURCE:.c=.d)))))
 
$(eval $(foreach SOURCE,$(filter %.cpp,$(SOURCES)), \
$(call compile_target_cpp,$(SOURCE),$(subst /,_,$(SOURCE:.cpp=.o)),$(subst /,_,$(SOURCE:.cpp=.d)))))
 
$(eval $(foreach SOURCE,$(filter %.m,$(SOURCES)), \
$(call compile_target_c,$(SOURCE),$(subst /,_,$(SOURCE:.m=.o)),$(subst /,_,$(SOURCE:.m=.d)))))
 
$(eval $(foreach SOURCE,$(filter %.s,$(SOURCES)), \
$(call compile_target_s,$(SOURCE),$(subst /,_,$(SOURCE:.s=.o)),$(subst /,_,$(SOURCE:.s=.d)))))
 
.PHONY: all clean docs install package-$(TARGET) package install-$(TARGET)
 
clean: $(CLEANS)
 
# Target builds a distribution package
package: all-program package-$(TARGET)
 
FAT_LANGUAGES=de en fr it nl
# 1 = front end name (gtk, ro, ami, etc)
# 2 = Destination directory (where resources being installed, creates en/Messages etc)
# 3 = suffix after language name
define split_install_messages
$(foreach LANG, $(FAT_LANGUAGES), @echo MSGSPLIT: $(1)/$(LANG) to $(2)
$(Q)mkdir -p $(2)/$(LANG)$(3)
$(Q)$(PERL) utils/split-messages.pl $(LANG) $(1) < resources/FatMessages | gzip -9n > $(2)$(3)/$(LANG)/Messages
)
endef
 
# Target installs executable on the host system
install: all-program install-$(TARGET)
 
docs:
doxygen Docs/Doxyfile
/programs/network/netsurf/netsurf/Makefile.config.example
0,0 → 1,40
#
# NetSurf build configuration example
#
#
# To configure NetSurf's build options create a Makefile.config file. This is
# an example Makefile.config.
#
# To see the available config options, look at Makefile.defaults, but make any
# alterations in your Makefile.config
 
 
# To enable/disable MNG support, uncomment the appropriate line below.
 
### NETSURF_USE_MNG := YES
### NETSURF_USE_MNG := NO
 
 
# To enable/disable SVGTiny support, uncomment the appropriate line below.
 
### override NETSURF_USE_NSSVG := YES
### override NETSURF_USE_NSSVG := NO
 
 
# To enable/disable RSVG support, uncomment the appropriate line below.
 
### override NETSURF_USE_RSVG := YES
### override NETSURF_USE_RSVG := NO
 
 
# To enable/disable BMP support, uncomment the appropriate line below.
 
### override NETSURF_USE_BMP := YES
### override NETSURF_USE_BMP := NO
 
 
# To make the framebuffer front end use freetype for text, uncomment the
# following line
 
### override NETSURF_FB_FONTLIB := freetype
 
/programs/network/netsurf/netsurf/Makefile.defaults
0,0 → 1,110
#
# NetSurf default build setup
#
#
# | WARNING: You should NOT be editing this file.
# |
# | If you want to configure your build, create a 'Makefile.config'
# | file with 'override' statements to override the settings here.
# | Follow the example in 'Makefile.config.example'.
#
#
# This file should be treated as INVIOLATE and only altered to alter
# the defaults by a core developer. If you wish to configure the build
# of NetSurf then instead please create a file called Makefile.config
# and simply override the statements you require in that. Remember
# that Makefile.config cannot override the TARGET. That must be set on
# the commandline. i.e. 'make TARGET=framebuffer' However
# Makefile.config can use the TARGET variable to control what to set
# the configuration options to.
#
# Some of these options support an 'AUTO' option, as well as YES and NO.
# When an option is set to AUTO, the Makefile will attempt to detect if that
# feature is available, enabling it if possible.
#
# Options marked "highly recommended" have a severe impact on NetSurf's
# use as a web browser and should be set to YES unless there is a particularly
# good reason not to.
#
 
# ----------------------------------------------------------------------------
# Options relating to all versions of NetSurf
# ----------------------------------------------------------------------------
 
# Enable NetSurf's use of libnsbmp for displaying BMPs and ICOs
# Valid options: YES, NO
NETSURF_USE_BMP := YES
 
# Enable NetSurf's use of libnsgif for displaying GIFs
# Valid options: YES, NO (highly recommended)
NETSURF_USE_GIF := YES
 
# Enable NetSurf's use of libjpeg for displaying JPEGs
# Valid options: YES, NO (highly recommended)
NETSURF_USE_JPEG := YES
 
# Enable NetSurf's use of libpng for displaying PNGs. If MNG and PNG
# are both enabled then NetSurf will choose libpng for PNGs, leaving
# MNGs and JNGs to libmng.
# Valid options: YES, NO (at least one of PNG/MNG highly recommended)
NETSURF_USE_PNG := YES
 
# Enable NetSurf's use of libmng for displaying MNGs, JNGs and PNGs
# Valid options: YES, NO (at least one of PNG/MNG highly recommended)
NETSURF_USE_MNG := NO
 
# Enable NetSurf's use of libwebp for displaying WebPs
# Valid options: YES, NO
NETSURF_USE_WEBP := NO
 
# Enable NetSurf's use of gstreamer for displaying videos
# Valid options: YES, NO
NETSURF_USE_VIDEO := NO
 
# Enable NetSurf's use of spidermonkey for javascript
# Valid options: YES, NO, AUTO
NETSURF_USE_JS := NO
# Javascript support in older debian/ubuntu versions
NETSURF_USE_MOZJS := NO
 
# Enable NetSurf's use of libharu for PDF export and GTK printing support.
# There is no auto-detection available for this, as it does not have a
# pkg-config file.
# Valid options: YES, NO
NETSURF_USE_HARU_PDF := NO
 
# Enable stripping the NetSurf binary
# Valid options: YES, NO
NETSURF_STRIP_BINARY := NO
 
# Template used for constructing the User Agent: string. The first two
# replacements are major/minor version, next is OS.
# Please don't be tempted to mention Mozilla here! Let's let that lie die.
NETSURF_UA_FORMAT_STRING := "NetSurf/%d.%d (%s)"
 
# Default home page, if one is not defined by the user. Note that this
# option does not apply to the RISC OS version, as it has its own local
# home page, and it can be changed by editing the end of gui_init2() in
# riscos/gui.c
NETSURF_HOMEPAGE := "about:welcome"
 
# Force using glibc internal iconv implementation instead of external libiconv
# Valid options: YES, NO
NETSURF_USE_LIBICONV_PLUG := YES
 
# Initial CFLAGS. Optimisation level etc. tend to be target specific.
CFLAGS :=
 
# Default installation/execution prefix
PREFIX ?= /usr/local
 
# Incude defaults specific to a TARGET
-include $(TARGET)/Makefile.defaults
 
# Include any local configuration
ifneq ($(MAKEFILE_DEFAULTS_FINISHED),)
$(error Makefile.defaults has been double-included. If you did something utterly brain-dead such as copying Makefile.defaults to Makefile.config then you deserve all the pain you can imagine. Do NOT do that. Why not read the comments at the top of Makefile.defaults. They are there to help you, you numpty)
endif
MAKEFILE_DEFAULTS_FINISHED=yes
-include Makefile.config
 
/programs/network/netsurf/netsurf/Makefile.sources
0,0 → 1,76
#
# NetSurf source file inclusion
#
# Included by main makefile -- indicates generic sources for every build.
#
 
S_CONTENT := content.c content_factory.c dirlist.c fetch.c hlcache.c \
llcache.c mimesniff.c urldb.c
 
S_FETCHERS := curl.c data.c file.c about.c resource.c
 
S_CSS := css.c dump.c internal.c select.c utils.c
 
S_RENDER := box.c box_construct.c box_normalise.c \
font.c form.c \
html.c html_script.c html_interaction.c html_redraw.c \
html_forms.c imagemap.c layout.c list.c search.c table.c \
textinput.c textplain.c
 
S_UTILS := base64.c corestrings.c filename.c filepath.c hashtable.c \
libdom.c locale.c log.c messages.c nsurl.c talloc.c url.c \
utf8.c utils.c useragent.c
 
S_HTTP := challenge.c generics.c primitives.c parameter.c \
content-disposition.c content-type.c www-authenticate.c
 
S_DESKTOP := cookies.c history_global_core.c hotlist.c knockout.c \
mouse.c options.c plot_style.c print.c search.c searchweb.c \
scrollbar.c sslcert.c textarea.c thumbnail.c tree.c \
tree_url_node.c version.c
 
# Javascript source
include Makefile.sources.javascript
 
# S_COMMON are sources common to all builds
S_COMMON := $(addprefix content/,$(S_CONTENT)) \
$(addprefix content/fetchers/,$(S_FETCHERS)) \
$(addprefix css/,$(S_CSS)) \
$(addprefix render/,$(S_RENDER)) \
$(addprefix utils/,$(S_UTILS)) \
$(addprefix utils/http/,$(S_HTTP)) \
$(addprefix desktop/,$(S_DESKTOP)) \
$(addprefix javascript/,$(S_JAVASCRIPT)) \
$(S_JSAPI_BINDING)
 
# S_IMAGE are sources related to image management
S_IMAGE_YES := image.c image_cache.c
S_IMAGE_NO :=
S_IMAGE_$(NETSURF_USE_BMP) += bmp.c ico.c
S_IMAGE_$(NETSURF_USE_GIF) += gif.c
S_IMAGE_$(NETSURF_USE_JPEG) += jpeg.c
S_IMAGE_$(NETSURF_USE_MNG) += mng.c
S_IMAGE_$(NETSURF_USE_ROSPRITE) += nssprite.c
S_IMAGE_$(NETSURF_USE_PNG) += png.c
S_IMAGE_$(NETSURF_USE_NSSVG) += svg.c
S_IMAGE_$(NETSURF_USE_RSVG) += rsvg.c
S_IMAGE_$(NETSURF_USE_WEBP) += webp.c
S_IMAGE_$(NETSURF_USE_VIDEO) += video.c
 
S_IMAGE := $(addprefix image/,$(S_IMAGE_YES))
 
# S_PDF are sources of the pdf plotter + the ones for paged-printing
S_PDF := pdf_plotters.c font_haru.c
S_PDF := $(addprefix desktop/save_pdf/,$(S_PDF))
 
# S_BROWSER are sources related to full browsers but are common
# between RISC OS, GTK, BeOS and AmigaOS builds
S_BROWSER := browser.c download.c frames.c history_core.c netsurf.c \
save_complete.c save_text.c selection.c textinput.c
 
S_BROWSER := $(addprefix desktop/,$(S_BROWSER))
 
# The following files depend on the testament
content/fetchers/about.c: testament utils/testament.h
desktop/version.c: testament utils/testament.h
 
/programs/network/netsurf/netsurf/Makefile.sources.javascript
0,0 → 1,63
#
# NetSurf javascript source file inclusion
#
# Included by Makefile.sources
#
 
# ----------------------------------------------------------------------------
# JSAPI binding
# ----------------------------------------------------------------------------
 
S_JSAPI_BINDING:=
D_JSAPI_BINDING:=
 
JSAPI_BINDING_htmldocument := javascript/jsapi/htmldocument.bnd
JSAPI_BINDING_htmlelement := javascript/jsapi/htmlelement.bnd
JSAPI_BINDING_window := javascript/jsapi/window.bnd
JSAPI_BINDING_navigator := javascript/jsapi/navigator.bnd
JSAPI_BINDING_console := javascript/jsapi/console.bnd
JSAPI_BINDING_location := javascript/jsapi/location.bnd
JSAPI_BINDING_htmlcollection := javascript/jsapi/htmlcollection.bnd
JSAPI_BINDING_nodelist := javascript/jsapi/nodelist.bnd
JSAPI_BINDING_text := javascript/jsapi/text.bnd
JSAPI_BINDING_comment := javascript/jsapi/comment.bnd
JSAPI_BINDING_node := javascript/jsapi/node.bnd
JSAPI_BINDING_event := javascript/jsapi/event.bnd
 
# 1: input binding file
# 2: source output file
# 3: header output file
# 4: binding name
define convert_jsapi_binding
 
S_JSAPI_BINDING += $(2)
D_JSAPI_BINDING += $(patsubst %.c,%.d,$(2))
 
$(2): $(1) $(OBJROOT)/created
$$(VQ)echo " GENBIND: $(1)"
$(Q)nsgenbind -I javascript/WebIDL -d $(patsubst %.c,%.d,$(2)) -h $(3) -o $(2) $(1)
 
$(3): $(2)
 
endef
 
# Javascript sources
ifeq ($(NETSURF_USE_JS),YES)
WANT_JS_SOURCE := YES
endif
 
ifeq ($(NETSURF_USE_MOZJS),YES)
WANT_JS_SOURCE := YES
endif
 
ifeq ($(WANT_JS_SOURCE),YES)
 
S_JSAPI :=
 
S_JAVASCRIPT += content.c jsapi.c $(addprefix jsapi/,$(S_JSAPI))
 
$(eval $(foreach V,$(filter JSAPI_BINDING_%,$(.VARIABLES)),$(call convert_jsapi_binding,$($(V)),$(OBJROOT)/$(patsubst JSAPI_BINDING_%,%,$(V)).c,$(OBJROOT)/$(patsubst JSAPI_BINDING_%,%,$(V)).h,$(patsubst JSAPI_BINDING_%,%,$(V))_jsapi)))
 
else
S_JAVASCRIPT += none.c
endif
/programs/network/netsurf/netsurf/TODO
0,0 → 1,6
0) port entire project to newlib?
1) NSFB - native UI instead of SDL
2) framebuffer/gui.c -replace init "SDL" to init "kolibri"
3) fix stubs.c file
4) port libcURL
/programs/network/netsurf/netsurf/content/content.c
0,0 → 1,1375
/*
* Copyright 2005-2007 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content handling (implementation).
*
* This implementation is based on the ::handler_map array, which maps
* ::content_type to the functions which implement that type.
*/
 
#include <assert.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include "utils/config.h"
#include "content/content_protected.h"
#include "content/hlcache.h"
#include "css/css.h"
#include "image/bitmap.h"
#include "desktop/browser.h"
#include "desktop/options.h"
#include "render/html.h"
#include "render/textplain.h"
 
#include "utils/http.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
 
#define URL_FMT_SPC "%.140s"
 
const char * const content_status_name[] = {
"LOADING",
"READY",
"DONE",
"ERROR"
};
 
static nserror content_llcache_callback(llcache_handle *llcache,
const llcache_event *event, void *pw);
static void content_convert(struct content *c);
 
 
/**
* Initialise a new content structure.
*
* \param c Content to initialise
* \param handler Content handler
* \param imime_type MIME type of content
* \param params HTTP parameters
* \param llcache Source data handle
* \param fallback_charset Fallback charset
* \param quirks Quirkiness of content
* \return NSERROR_OK on success, appropriate error otherwise
*/
 
nserror content__init(struct content *c, const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks)
{
struct content_user *user_sentinel;
nserror error;
LOG(("url "URL_FMT_SPC" -> %p",
nsurl_access(llcache_handle_get_url(llcache)), c));
 
user_sentinel = calloc(1, sizeof(struct content_user));
if (user_sentinel == NULL) {
return NSERROR_NOMEM;
}
 
if (fallback_charset != NULL) {
c->fallback_charset = strdup(fallback_charset);
if (c->fallback_charset == NULL) {
return NSERROR_NOMEM;
}
}
 
c->llcache = llcache;
c->mime_type = lwc_string_ref(imime_type);
c->handler = handler;
c->status = CONTENT_STATUS_LOADING;
c->width = 0;
c->height = 0;
c->available_width = 0;
c->quirks = quirks;
c->refresh = 0;
c->time = wallclock();
c->size = 0;
c->title = NULL;
c->active = 0;
user_sentinel->callback = NULL;
user_sentinel->pw = NULL;
user_sentinel->next = NULL;
c->user_list = user_sentinel;
c->sub_status[0] = 0;
c->locked = false;
c->total_size = 0;
c->http_code = 0;
c->error_count = 0;
 
content_set_status(c, messages_get("Loading"));
 
/* Finally, claim low-level cache events */
error = llcache_handle_change_callback(llcache,
content_llcache_callback, c);
if (error != NSERROR_OK) {
lwc_string_unref(c->mime_type);
return error;
}
 
return NSERROR_OK;
}
 
/**
* Handler for low-level cache events
*
* \param llcache Low-level cache handle
* \param event Event details
* \param pw Pointer to our context
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror content_llcache_callback(llcache_handle *llcache,
const llcache_event *event, void *pw)
{
struct content *c = pw;
union content_msg_data msg_data;
nserror error = NSERROR_OK;
 
switch (event->type) {
case LLCACHE_EVENT_HAD_HEADERS:
/* Will never happen: handled in hlcache */
break;
case LLCACHE_EVENT_HAD_DATA:
if (c->handler->process_data != NULL) {
if (c->handler->process_data(c,
(const char *) event->data.data.buf,
event->data.data.len) == false) {
llcache_handle_abort(c->llcache);
c->status = CONTENT_STATUS_ERROR;
/** \todo It's not clear what error this is */
error = NSERROR_NOMEM;
}
}
break;
case LLCACHE_EVENT_DONE:
{
size_t source_size;
 
(void) llcache_handle_get_source_data(llcache, &source_size);
 
content_set_status(c, messages_get("Processing"));
msg_data.explicit_status_text = NULL;
content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
 
content_convert(c);
}
break;
case LLCACHE_EVENT_ERROR:
/** \todo Error page? */
c->status = CONTENT_STATUS_ERROR;
msg_data.error = event->data.msg;
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
break;
case LLCACHE_EVENT_PROGRESS:
content_set_status(c, event->data.msg);
msg_data.explicit_status_text = NULL;
content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
break;
}
 
return error;
}
 
/**
* Get whether a content can reformat
*
* \param h content to check
* \return whether the content can reformat
*/
bool content_can_reformat(hlcache_handle *h)
{
struct content *c = hlcache_handle_get_content(h);
 
if (c == NULL)
return false;
 
return (c->handler->reformat != NULL);
}
 
 
static void content_update_status(struct content *c)
{
if (c->status == CONTENT_STATUS_LOADING ||
c->status == CONTENT_STATUS_READY) {
/* Not done yet */
snprintf(c->status_message, sizeof (c->status_message),
"%s%s%s", messages_get("Fetching"),
c->sub_status ? ", " : " ", c->sub_status);
} else {
unsigned int time = c->time;
snprintf(c->status_message, sizeof (c->status_message),
"%s (%.1fs)", messages_get("Done"),
(float) time / 100);
}
}
 
 
/**
* Updates content with new status.
*
* The textual status contained in the content is updated with given string.
*
* \param status_message new textual status
*/
 
void content_set_status(struct content *c, const char *status_message)
{
size_t len = strlen(status_message);
 
if (len >= sizeof(c->sub_status)) {
len = sizeof(c->sub_status) - 1;
}
memcpy(c->sub_status, status_message, len);
c->sub_status[len] = '\0';
 
content_update_status(c);
}
 
 
/**
* All data has arrived, convert for display.
*
* Calls the convert function for the content.
*
* - If the conversion succeeds, but there is still some processing required
* (eg. loading images), the content gets status CONTENT_STATUS_READY, and a
* CONTENT_MSG_READY is sent to all users.
* - If the conversion succeeds and is complete, the content gets status
* CONTENT_STATUS_DONE, and CONTENT_MSG_READY then CONTENT_MSG_DONE are sent.
* - If the conversion fails, CONTENT_MSG_ERROR is sent. The content will soon
* be destroyed and must no longer be used.
*/
 
void content_convert(struct content *c)
{
assert(c);
assert(c->status == CONTENT_STATUS_LOADING ||
c->status == CONTENT_STATUS_ERROR);
 
if (c->status != CONTENT_STATUS_LOADING)
return;
 
if (c->locked == true)
return;
LOG(("content "URL_FMT_SPC" (%p)",
nsurl_access(llcache_handle_get_url(c->llcache)), c));
 
if (c->handler->data_complete != NULL) {
c->locked = true;
if (c->handler->data_complete(c) == false) {
content_set_error(c);
}
/* Conversion to the READY state will unlock the content */
} else {
content_set_ready(c);
content_set_done(c);
}
}
 
/**
* Put a content in status CONTENT_STATUS_READY and unlock the content.
*/
 
void content_set_ready(struct content *c)
{
union content_msg_data msg_data;
 
/* The content must be locked at this point, as it can only
* become READY after conversion. */
assert(c->locked);
c->locked = false;
 
c->status = CONTENT_STATUS_READY;
content_update_status(c);
content_broadcast(c, CONTENT_MSG_READY, msg_data);
}
 
/**
* Put a content in status CONTENT_STATUS_DONE.
*/
 
void content_set_done(struct content *c)
{
union content_msg_data msg_data;
 
c->status = CONTENT_STATUS_DONE;
c->time = wallclock() - c->time;
content_update_status(c);
content_broadcast(c, CONTENT_MSG_DONE, msg_data);
}
 
/**
* Put a content in status CONTENT_STATUS_ERROR and unlock the content.
*
* \note We expect the caller to broadcast an error report if needed.
*/
 
void content_set_error(struct content *c)
{
c->locked = false;
c->status = CONTENT_STATUS_ERROR;
}
 
/**
* Reformat to new size.
*
* Calls the reformat function for the content.
*/
 
void content_reformat(hlcache_handle *h, bool background,
int width, int height)
{
content__reformat(hlcache_handle_get_content(h), background,
width, height);
}
 
void content__reformat(struct content *c, bool background,
int width, int height)
{
union content_msg_data data;
assert(c != 0);
assert(c->status == CONTENT_STATUS_READY ||
c->status == CONTENT_STATUS_DONE);
assert(c->locked == false);
LOG(("%p %s", c, nsurl_access(llcache_handle_get_url(c->llcache))));
c->available_width = width;
if (c->handler->reformat != NULL) {
 
c->locked = true;
c->handler->reformat(c, width, height);
c->locked = false;
 
data.background = background;
content_broadcast(c, CONTENT_MSG_REFORMAT, data);
}
}
 
 
/**
* Destroy and free a content.
*
* Calls the destroy function for the content, and frees the structure.
*/
 
void content_destroy(struct content *c)
{
struct content_rfc5988_link *link;
 
assert(c);
LOG(("content %p %s", c,
nsurl_access(llcache_handle_get_url(c->llcache))));
assert(c->locked == false);
 
if (c->handler->destroy != NULL)
c->handler->destroy(c);
 
llcache_handle_release(c->llcache);
c->llcache = NULL;
 
lwc_string_unref(c->mime_type);
 
/* release metadata links */
link = c->links;
while (link != NULL) {
link = content__free_rfc5988_link(link);
}
 
/* free the user list */
if (c->user_list != NULL) {
free(c->user_list);
}
 
/* free the title */
if (c->title != NULL) {
free(c->title);
}
 
/* free the fallback characterset */
if (c->fallback_charset != NULL) {
free(c->fallback_charset);
}
 
free(c);
}
 
 
/**
* Handle mouse movements in a content window.
*
* \param h Content handle
* \param bw browser window
* \param mouse state of mouse buttons and modifier keys
* \param x coordinate of mouse
* \param y coordinate of mouse
*/
 
void content_mouse_track(hlcache_handle *h, struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
struct content *c = hlcache_handle_get_content(h);
assert(c != NULL);
 
if (c->handler->mouse_track != NULL) {
c->handler->mouse_track(c, bw, mouse, x, y);
} else {
union content_msg_data msg_data;
msg_data.pointer = BROWSER_POINTER_AUTO;
content_broadcast(c, CONTENT_MSG_POINTER, msg_data);
}
 
 
return;
}
 
 
/**
* Handle mouse clicks and movements in a content window.
*
* \param h Content handle
* \param bw browser window
* \param mouse state of mouse buttons and modifier keys
* \param x coordinate of mouse
* \param y coordinate of mouse
*
* This function handles both hovering and clicking. It is important that the
* code path is identical (except that hovering doesn't carry out the action),
* so that the status bar reflects exactly what will happen. Having separate
* code paths opens the possibility that an attacker will make the status bar
* show some harmless action where clicking will be harmful.
*/
 
void content_mouse_action(hlcache_handle *h, struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
struct content *c = hlcache_handle_get_content(h);
assert(c != NULL);
 
if (c->handler->mouse_action != NULL)
c->handler->mouse_action(c, bw, mouse, x, y);
 
return;
}
 
 
/**
* Request a redraw of an area of a content
*
* \param h high-level cache handle
* \param x x co-ord of left edge
* \param y y co-ord of top edge
* \param width Width of rectangle
* \param height Height of rectangle
*/
void content_request_redraw(struct hlcache_handle *h,
int x, int y, int width, int height)
{
content__request_redraw(hlcache_handle_get_content(h),
x, y, width, height);
}
 
 
/**
* Request a redraw of an area of a content
*
* \param c Content
* \param x x co-ord of left edge
* \param y y co-ord of top edge
* \param width Width of rectangle
* \param height Height of rectangle
*/
void content__request_redraw(struct content *c,
int x, int y, int width, int height)
{
union content_msg_data data;
 
if (c == NULL)
return;
 
data.redraw.x = x;
data.redraw.y = y;
data.redraw.width = width;
data.redraw.height = height;
 
data.redraw.full_redraw = true;
 
data.redraw.object = c;
data.redraw.object_x = 0;
data.redraw.object_y = 0;
data.redraw.object_width = c->width;
data.redraw.object_height = c->height;
 
content_broadcast(c, CONTENT_MSG_REDRAW, data);
}
 
/**
* Display content on screen with optional tiling.
*
* Calls the redraw_tile function for the content, or emulates it with the
* redraw function if it doesn't exist.
*/
 
bool content_redraw(hlcache_handle *h, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
struct content *c = hlcache_handle_get_content(h);
 
assert(c != NULL);
 
if (c->locked) {
/* not safe to attempt redraw */
return true;
}
 
/* ensure we have a redrawable content */
if (c->handler->redraw == NULL) {
return true;
}
 
return c->handler->redraw(c, data, clip, ctx);
}
 
 
/**
* Register a user for callbacks.
*
* \param c the content to register
* \param callback the callback function
* \param pw callback private data
* \return true on success, false otherwise on memory exhaustion
*
* The callback will be called when content_broadcast() is
* called with the content.
*/
 
bool content_add_user(struct content *c,
void (*callback)(struct content *c, content_msg msg,
union content_msg_data data, void *pw),
void *pw)
{
struct content_user *user;
 
LOG(("content "URL_FMT_SPC" (%p), user %p %p",
nsurl_access(llcache_handle_get_url(c->llcache)),
c, callback, pw));
user = malloc(sizeof(struct content_user));
if (!user)
return false;
user->callback = callback;
user->pw = pw;
user->next = c->user_list->next;
c->user_list->next = user;
 
return true;
}
 
 
/**
* Remove a callback user.
*
* The callback function and pw must be identical to those passed to
* content_add_user().
*/
 
void content_remove_user(struct content *c,
void (*callback)(struct content *c, content_msg msg,
union content_msg_data data, void *pw),
void *pw)
{
struct content_user *user, *next;
LOG(("content "URL_FMT_SPC" (%p), user %p %p",
nsurl_access(llcache_handle_get_url(c->llcache)), c,
callback, pw));
 
/* user_list starts with a sentinel */
for (user = c->user_list; user->next != 0 &&
!(user->next->callback == callback &&
user->next->pw == pw); user = user->next)
;
if (user->next == 0) {
LOG(("user not found in list"));
assert(0);
return;
}
next = user->next;
user->next = next->next;
free(next);
}
 
/**
* Count users for the content.
*/
 
uint32_t content_count_users(struct content *c)
{
struct content_user *user;
uint32_t counter = 0;
 
assert(c != NULL);
for (user = c->user_list; user != NULL; user = user->next)
counter += 1;
return counter - 1; /* Subtract 1 for the sentinel */
}
 
/**
* Determine if quirks mode matches
*
* \param c Content to consider
* \param quirks Quirks mode to match
* \return True if quirks match, false otherwise
*/
bool content_matches_quirks(struct content *c, bool quirks)
{
if (c->handler->matches_quirks == NULL)
return true;
 
return c->handler->matches_quirks(c, quirks);
}
 
/**
* Determine if a content is shareable
*
* \param c Content to consider
* \return True if content is shareable, false otherwise
*/
bool content_is_shareable(struct content *c)
{
return c->handler->no_share == false;
}
 
/**
* Send a message to all users.
*/
 
void content_broadcast(struct content *c, content_msg msg,
union content_msg_data data)
{
struct content_user *user, *next;
assert(c);
// LOG(("%p %s -> %d", c, c->url, msg));
for (user = c->user_list->next; user != 0; user = next) {
next = user->next; /* user may be destroyed during callback */
if (user->callback != 0)
user->callback(c, msg, data, user->pw);
}
}
 
/* exported interface documented in content_protected.h */
void content_broadcast_errorcode(struct content *c, nserror errorcode)
{
struct content_user *user, *next;
union content_msg_data data;
 
assert(c);
 
data.errorcode = errorcode;
 
for (user = c->user_list->next; user != 0; user = next) {
next = user->next; /* user may be destroyed during callback */
if (user->callback != 0)
user->callback(c, CONTENT_MSG_ERRORCODE, data, user->pw);
}
}
 
 
/**
* A window containing the content has been opened.
*
* \param c content that has been opened
* \param bw browser window containing the content
* \param page content of type CONTENT_HTML containing c, or 0 if not an
* object within a page
* \param params object parameters, or 0 if not an object
*
* Calls the open function for the content.
*/
 
void content_open(hlcache_handle *h, struct browser_window *bw,
struct content *page, struct object_params *params)
{
struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
LOG(("content %p %s", c,
nsurl_access(llcache_handle_get_url(c->llcache))));
if (c->handler->open != NULL)
c->handler->open(c, bw, page, params);
}
 
 
/**
* The window containing the content has been closed.
*
* Calls the close function for the content.
*/
 
void content_close(hlcache_handle *h)
{
struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
LOG(("content %p %s", c,
nsurl_access(llcache_handle_get_url(c->llcache))));
if (c->handler->close != NULL)
c->handler->close(c);
}
 
 
/**
* Find this content's selection context, if it has one.
*/
 
struct selection *content_get_selection(hlcache_handle *h)
{
struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
 
if (c->handler->get_selection != NULL)
return c->handler->get_selection(c);
else
return NULL;
}
 
 
void content_get_contextual_content(struct hlcache_handle *h,
int x, int y, struct contextual_content *data)
{
struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
 
if (c->handler->get_contextual_content != NULL) {
c->handler->get_contextual_content(c, x, y, data);
return;
} else {
data->object = h;
return;
}
}
 
 
bool content_scroll_at_point(struct hlcache_handle *h,
int x, int y, int scrx, int scry)
{
struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
 
if (c->handler->scroll_at_point != NULL)
return c->handler->scroll_at_point(c, x, y, scrx, scry);
 
return false;
}
 
 
bool content_drop_file_at_point(struct hlcache_handle *h,
int x, int y, char *file)
{
struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
 
if (c->handler->drop_file_at_point != NULL)
return c->handler->drop_file_at_point(c, x, y, file);
 
return false;
}
 
 
void content_debug_dump(struct hlcache_handle *h, FILE *f)
{
struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
 
if (c->handler->debug_dump != NULL)
c->handler->debug_dump(c, f);
}
 
 
void content_add_error(struct content *c, const char *token,
unsigned int line)
{
}
 
bool content__set_title(struct content *c, const char *title)
{
char *new_title = strdup(title);
if (new_title == NULL)
return false;
 
if (c->title != NULL)
free(c->title);
 
c->title = new_title;
 
return true;
}
 
struct content_rfc5988_link *
content_find_rfc5988_link(hlcache_handle *h, lwc_string *rel)
{
struct content *c = hlcache_handle_get_content(h);
struct content_rfc5988_link *link = c->links;
bool rel_match = false;
 
while (link != NULL) {
if (lwc_string_caseless_isequal(link->rel, rel,
&rel_match) == lwc_error_ok && rel_match) {
break;
}
link = link->next;
}
return link;
}
 
struct content_rfc5988_link *
content__free_rfc5988_link(struct content_rfc5988_link *link)
{
struct content_rfc5988_link *next;
 
next = link->next;
 
lwc_string_unref(link->rel);
nsurl_unref(link->href);
if (link->hreflang != NULL) {
lwc_string_unref(link->hreflang);
}
if (link->type != NULL) {
lwc_string_unref(link->type);
}
if (link->media != NULL) {
lwc_string_unref(link->media);
}
if (link->sizes != NULL) {
lwc_string_unref(link->sizes);
}
free(link);
 
return next;
}
 
bool content__add_rfc5988_link(struct content *c,
const struct content_rfc5988_link *link)
{
struct content_rfc5988_link *newlink;
union content_msg_data msg_data;
 
/* a link relation must be present for it to be a link */
if (link->rel == NULL) {
return false;
}
 
/* a link href must be present for it to be a link */
if (link->href == NULL) {
return false;
}
 
newlink = calloc(1, sizeof(struct content_rfc5988_link));
if (newlink == NULL) {
return false;
}
 
/* copy values */
newlink->rel = lwc_string_ref(link->rel);
newlink->href = nsurl_ref(link->href);
if (link->hreflang != NULL) {
newlink->hreflang = lwc_string_ref(link->hreflang);
}
if (link->type != NULL) {
newlink->type = lwc_string_ref(link->type);
}
if (link->media != NULL) {
newlink->media = lwc_string_ref(link->media);
}
if (link->sizes != NULL) {
newlink->sizes = lwc_string_ref(link->sizes);
}
 
/* add to metadata link to list */
newlink->next = c->links;
c->links = newlink;
 
/* broadcast the data */
msg_data.rfc5988_link = newlink;
content_broadcast(c, CONTENT_MSG_LINK, msg_data);
 
return true;
}
 
/**
* Retrieve computed type of content
*
* \param c Content to retrieve type of
* \return Computed content type
*/
content_type content_get_type(hlcache_handle *h)
{
struct content *c = hlcache_handle_get_content(h);
 
if (c == NULL)
return CONTENT_NONE;
 
return c->handler->type();
}
 
/**
* Retrieve mime-type of content
*
* \param c Content to retrieve mime-type of
* \return Pointer to referenced mime-type, or NULL if not found.
*/
lwc_string *content_get_mime_type(hlcache_handle *h)
{
return content__get_mime_type(hlcache_handle_get_content(h));
}
 
lwc_string *content__get_mime_type(struct content *c)
{
if (c == NULL)
return NULL;
 
return lwc_string_ref(c->mime_type);
}
 
/**
* Retrieve URL associated with content
*
* \param c Content to retrieve URL from
* \return Pointer to URL, or NULL if not found.
*/
nsurl *content_get_url(struct content *c)
{
if (c == NULL)
return NULL;
 
return llcache_handle_get_url(c->llcache);
}
 
/**
* Retrieve title associated with content
*
* \param c Content to retrieve title from
* \return Pointer to title, or NULL if not found.
*/
const char *content_get_title(hlcache_handle *h)
{
return content__get_title(hlcache_handle_get_content(h));
}
 
const char *content__get_title(struct content *c)
{
if (c == NULL)
return NULL;
 
return c->title != NULL ? c->title :
nsurl_access(llcache_handle_get_url(c->llcache));
}
 
/**
* Retrieve status of content
*
* \param c Content to retrieve status of
* \return Content status
*/
content_status content_get_status(hlcache_handle *h)
{
return content__get_status(hlcache_handle_get_content(h));
}
 
content_status content__get_status(struct content *c)
{
if (c == NULL)
return CONTENT_STATUS_ERROR;
 
return c->status;
}
 
/**
* Retrieve status message associated with content
*
* \param c Content to retrieve status message from
* \return Pointer to status message, or NULL if not found.
*/
const char *content_get_status_message(hlcache_handle *h)
{
return content__get_status_message(hlcache_handle_get_content(h));
}
 
const char *content__get_status_message(struct content *c)
{
if (c == NULL)
return NULL;
 
return c->status_message;
}
 
/**
* Retrieve width of content
*
* \param c Content to retrieve width of
* \return Content width
*/
int content_get_width(hlcache_handle *h)
{
return content__get_width(hlcache_handle_get_content(h));
}
 
int content__get_width(struct content *c)
{
if (c == NULL)
return 0;
 
return c->width;
}
 
/**
* Retrieve height of content
*
* \param c Content to retrieve height of
* \return Content height
*/
int content_get_height(hlcache_handle *h)
{
return content__get_height(hlcache_handle_get_content(h));
}
 
int content__get_height(struct content *c)
{
if (c == NULL)
return 0;
 
return c->height;
}
 
/**
* Retrieve available width of content
*
* \param c Content to retrieve available width of
* \return Available width of content
*/
int content_get_available_width(hlcache_handle *h)
{
return content__get_available_width(hlcache_handle_get_content(h));
}
 
int content__get_available_width(struct content *c)
{
if (c == NULL)
return 0;
 
return c->available_width;
}
 
 
/**
* Retrieve source of content
*
* \param c Content to retrieve source of
* \param size Pointer to location to receive byte size of source
* \return Pointer to source data
*/
const char *content_get_source_data(hlcache_handle *h, unsigned long *size)
{
return content__get_source_data(hlcache_handle_get_content(h), size);
}
 
const char *content__get_source_data(struct content *c, unsigned long *size)
{
const uint8_t *data;
size_t len;
 
assert(size != NULL);
 
if (c == NULL)
return NULL;
 
data = llcache_handle_get_source_data(c->llcache, &len);
 
*size = (unsigned long) len;
 
return (const char *) data;
}
 
/**
* Invalidate content reuse data: causes subsequent requests for content URL
* to query server to determine if content can be reused. This is required
* behaviour for forced reloads etc.
*
* \param c Content to invalidate
*/
void content_invalidate_reuse_data(hlcache_handle *h)
{
content__invalidate_reuse_data(hlcache_handle_get_content(h));
}
 
void content__invalidate_reuse_data(struct content *c)
{
if (c == NULL || c->llcache == NULL)
return;
 
/* Invalidate low-level cache data */
llcache_handle_invalidate_cache_data(c->llcache);
}
 
/**
* Retrieve the refresh URL for a content
*
* \param c Content to retrieve refresh URL from
* \return Pointer to URL, or NULL if none
*/
nsurl *content_get_refresh_url(hlcache_handle *h)
{
return content__get_refresh_url(hlcache_handle_get_content(h));
}
 
nsurl *content__get_refresh_url(struct content *c)
{
if (c == NULL)
return NULL;
 
return c->refresh;
}
 
 
/**
* Retrieve the bitmap contained in an image content
*
* \param c Content to retrieve bitmap from
* \return Pointer to bitmap, or NULL if none.
*/
struct bitmap *content_get_bitmap(hlcache_handle *h)
{
return content__get_bitmap(hlcache_handle_get_content(h));
}
 
struct bitmap *content__get_bitmap(struct content *c)
{
struct bitmap *bitmap = NULL;
 
if ((c != NULL) &&
(c->handler != NULL) &&
(c->handler->type != NULL) &&
(c->handler->type() == CONTENT_IMAGE) &&
(c->handler->get_internal != NULL) ) {
bitmap = c->handler->get_internal(c, NULL);
}
 
return bitmap;
}
 
 
/**
* Determine if a content is opaque from handle
*
* \param h high level cache handle to retrieve opacity from.
* \return false if the content is not opaque or information is not
* known else true.
*/
bool content_get_opaque(hlcache_handle *h)
{
return content__get_opaque(hlcache_handle_get_content(h));
}
 
/**
* Determine if a content is opaque
*
* \param c Content to retrieve opacity from
* \return false if the content is not opaque or information is not
* known else true.
*/
bool content__get_opaque(struct content *c)
{
bool opaque = false;
 
if ((c != NULL) &&
(c->handler != NULL) &&
(c->handler->type != NULL) &&
(c->handler->type() == CONTENT_IMAGE) &&
(c->handler->get_internal != NULL) ) {
struct bitmap *bitmap = NULL;
bitmap = c->handler->get_internal(c, NULL);
if (bitmap != NULL) {
opaque = bitmap_get_opaque(bitmap);
}
}
 
return opaque;
}
 
 
/**
* Retrieve quirkiness of a content
*
* \param h Content to examine
* \return True if content is quirky, false otherwise
*/
bool content_get_quirks(hlcache_handle *h)
{
struct content *c = hlcache_handle_get_content(h);
 
if (c == NULL)
return false;
 
return c->quirks;
}
 
 
/**
* Return whether a content is currently locked
*
* \param c Content to test
* \return true iff locked, else false
*/
 
bool content_is_locked(hlcache_handle *h)
{
return content__is_locked(hlcache_handle_get_content(h));
}
 
bool content__is_locked(struct content *c)
{
return c->locked;
}
 
/**
* Retrieve the low-level cache handle for a content
*
* \param h Content to retrieve from
* \return Low-level cache handle
*/
const llcache_handle *content_get_llcache_handle(struct content *c)
{
if (c == NULL)
return NULL;
 
return c->llcache;
}
 
/**
* Clone a content object in its current state.
*
* \param c Content to clone
* \return Clone of \a c
*/
struct content *content_clone(struct content *c)
{
struct content *nc;
nserror error;
 
error = c->handler->clone(c, &nc);
if (error != NSERROR_OK)
return NULL;
 
return nc;
};
 
/**
* Clone a content's data members
*
* \param c Content to clone
* \param nc Content to populate
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror content__clone(const struct content *c, struct content *nc)
{
struct content_user *user_sentinel;
nserror error;
 
user_sentinel = calloc(1, sizeof(struct content_user));
if (user_sentinel == NULL) {
return NSERROR_NOMEM;
}
 
error = llcache_handle_clone(c->llcache, &(nc->llcache));
if (error != NSERROR_OK) {
return error;
}
llcache_handle_change_callback(nc->llcache,
content_llcache_callback, nc);
 
nc->mime_type = lwc_string_ref(c->mime_type);
nc->handler = c->handler;
 
nc->status = c->status;
nc->width = c->width;
nc->height = c->height;
nc->available_width = c->available_width;
nc->quirks = c->quirks;
if (c->fallback_charset != NULL) {
nc->fallback_charset = strdup(c->fallback_charset);
if (nc->fallback_charset == NULL) {
return NSERROR_NOMEM;
}
}
if (c->refresh != NULL) {
nc->refresh = nsurl_ref(c->refresh);
if (nc->refresh == NULL) {
return NSERROR_NOMEM;
}
}
 
nc->time = c->time;
nc->reformat_time = c->reformat_time;
nc->size = c->size;
if (c->title != NULL) {
nc->title = strdup(c->title);
if (nc->title == NULL) {
return NSERROR_NOMEM;
}
}
nc->active = c->active;
 
nc->user_list = user_sentinel;
memcpy(&(nc->status_message), &(c->status_message), 120);
memcpy(&(nc->sub_status), &(c->sub_status), 80);
nc->locked = c->locked;
nc->total_size = c->total_size;
nc->http_code = c->http_code;
return NSERROR_OK;
}
 
/**
* Abort a content object
*
* \param c The content object to abort
* \return NSERROR_OK on success, otherwise appropriate error
*/
nserror content_abort(struct content *c)
{
LOG(("Aborting %p", c));
if (c->handler->stop != NULL)
c->handler->stop(c);
/* And for now, abort our llcache object */
return llcache_handle_abort(c->llcache);
}
 
/programs/network/netsurf/netsurf/content/content.h
0,0 → 1,255
/*
* Copyright 2005-2007 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Philip Pemberton <philpem@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content handling (interface).
*
* The content functions manipulate struct contents, which correspond to URLs.
*/
 
#ifndef _NETSURF_CONTENT_CONTENT_H_
#define _NETSURF_CONTENT_CONTENT_H_
 
#include <stdbool.h>
#include <stdio.h>
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/config.h"
#include "utils/errors.h"
#include "utils/http.h"
#include "utils/nsurl.h"
#include "utils/types.h"
#include "content/content_factory.h"
#include "content/content_type.h"
#include "desktop/mouse.h"
#include "desktop/plot_style.h"
 
struct browser_window;
struct content;
struct llcache_handle;
struct hlcache_handle;
struct object_params;
struct rect;
struct redraw_context;
 
 
/** Status of a content */
typedef enum {
CONTENT_STATUS_LOADING, /**< Content is being fetched or
converted and is not safe to display. */
CONTENT_STATUS_READY, /**< Some parts of content still being
loaded, but can be displayed. */
CONTENT_STATUS_DONE, /**< All finished. */
CONTENT_STATUS_ERROR /**< Error occurred, content will be
destroyed imminently. */
} content_status;
 
/** Used in callbacks to indicate what has occurred. */
typedef enum {
CONTENT_MSG_LOADING, /**< fetching or converting */
CONTENT_MSG_READY, /**< may be displayed */
CONTENT_MSG_DONE, /**< finished */
CONTENT_MSG_ERROR, /**< error occurred */
CONTENT_MSG_ERRORCODE, /**< error occurred return nserror */
CONTENT_MSG_STATUS, /**< new status string */
CONTENT_MSG_REFORMAT, /**< content_reformat done */
CONTENT_MSG_REDRAW, /**< needs redraw (eg. new animation frame) */
CONTENT_MSG_REFRESH, /**< wants refresh */
CONTENT_MSG_DOWNLOAD, /**< download, not for display */
CONTENT_MSG_LINK, /**< RFC5988 link */
CONTENT_MSG_GETCTX, /**< Javascript context */
CONTENT_MSG_SCROLL, /**< Request to scroll content */
CONTENT_MSG_DRAGSAVE, /**< Allow drag saving of content */
CONTENT_MSG_SAVELINK, /**< Allow URL to be saved */
CONTENT_MSG_POINTER /**< Wants a specific mouse pointer set */
} content_msg;
 
/** RFC5988 metadata link */
struct content_rfc5988_link {
struct content_rfc5988_link *next; /**< next rfc5988_link in list */
 
lwc_string *rel; /**< the link relationship - must be present */
nsurl *href; /**< the link href - must be present */
lwc_string *hreflang;
lwc_string *type;
lwc_string *media;
lwc_string *sizes;
};
 
/** Extra data for some content_msg messages. */
union content_msg_data {
/** CONTENT_MSG_ERROR - Error message */
const char *error;
/** CONTENT_MSG_ERRORCODE - Error code */
nserror errorcode;
/** CONTENT_MSG_REDRAW - Area of content which needs redrawing */
struct {
int x, y, width, height;
/** Redraw the area fully. If false, object must be set,
* and only the object will be redrawn. */
bool full_redraw;
/** Object to redraw if full_redraw is false. */
struct content *object;
/** Coordinates to plot object at. */
int object_x, object_y;
/** Dimensions to plot object with. */
int object_width, object_height;
} redraw;
/** CONTENT_MSG_REFRESH - Minimum delay */
int delay;
/** CONTENT_MSG_REFORMAT - Reformat should not cause a redraw */
bool background;
/** CONTENT_MSG_STATUS - Status message update. If NULL, the content's
* internal status text has been updated, and listener should use
* content_get_status_message() */
const char *explicit_status_text;
/** CONTENT_MSG_DOWNLOAD - Low-level cache handle */
struct llcache_handle *download;
/** CONTENT_MSG_RFC5988_LINK - rfc5988 link data */
struct content_rfc5988_link *rfc5988_link;
/** CONTENT_MSG_GETCTX - Javascript context */
struct jscontext **jscontext;
/** CONTENT_MSG_SCROLL - Part of content to scroll to show */
struct {
/** if true, scroll to show area given by (x0, y0) and (x1,y1).
* if false, scroll point (x0, y0) to top left of viewport */
bool area;
int x0, y0;
int x1, y1;
} scroll;
/** CONTENT_MSG_DRAGSAVE - Drag save a content */
struct {
enum {
CONTENT_SAVE_ORIG,
CONTENT_SAVE_NATIVE,
CONTENT_SAVE_COMPLETE,
CONTENT_SAVE_SOURCE
} type;
/** if NULL, save the content generating the message */
struct hlcache_handle *content;
} dragsave;
/** CONTENT_MSG_SAVELINK - Save a URL */
struct {
const char *url;
const char *title;
} savelink;
/** CONTENT_MSG_POINTER - Mouse pointer to set */
browser_pointer_shape pointer;
/** CONTENT_MSG_PASTE - Content requests that clipboard is pasted */
struct {
/* TODO: Get rid of these coords.
* browser_window_paste_text doesn't take coords, but
* RISC OS front end is doing something different. */
int x;
int y;
} paste;
};
 
/** parameters to content redraw */
struct content_redraw_data {
int x; /**< coordinate for top-left of redraw */
int y; /**< coordinate for top-left of redraw */
 
/** dimensions to render content at
* (for scaling contents with intrinsic dimensions) */
int width; /**< horizontal dimension */
int height; /**< vertical dimension */
 
/** The background colour */
colour background_colour;
 
/** Scale for redraw
* (for scaling contents without intrinsic dimensions) */
float scale; /**< Scale factor for redraw */
 
bool repeat_x; /**< whether content is tiled in x direction */
bool repeat_y; /**< whether content is tiled in y direction */
};
 
/* The following are for hlcache */
void content_destroy(struct content *c);
 
bool content_add_user(struct content *h,
void (*callback)(struct content *c, content_msg msg,
union content_msg_data data, void *pw),
void *pw);
void content_remove_user(struct content *c,
void (*callback)(struct content *c, content_msg msg,
union content_msg_data data, void *pw),
void *pw);
 
uint32_t content_count_users(struct content *c);
bool content_matches_quirks(struct content *c, bool quirks);
bool content_is_shareable(struct content *c);
content_status content__get_status(struct content *c);
 
const struct llcache_handle *content_get_llcache_handle(struct content *c);
nsurl *content_get_url(struct content *c);
 
struct content *content_clone(struct content *c);
 
nserror content_abort(struct content *c);
 
/* Client functions */
bool content_can_reformat(struct hlcache_handle *h);
void content_reformat(struct hlcache_handle *h, bool background,
int width, int height);
void content_request_redraw(struct hlcache_handle *h,
int x, int y, int width, int height);
void content_mouse_track(struct hlcache_handle *h, struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
void content_mouse_action(struct hlcache_handle *h, struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
bool content_redraw(struct hlcache_handle *h, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx);
void content_open(struct hlcache_handle *h, struct browser_window *bw,
struct content *page, struct object_params *params);
void content_close(struct hlcache_handle *h);
struct selection *content_get_selection(struct hlcache_handle *h);
void content_get_contextual_content(struct hlcache_handle *h,
int x, int y, struct contextual_content *data);
bool content_scroll_at_point(struct hlcache_handle *h,
int x, int y, int scrx, int scry);
bool content_drop_file_at_point(struct hlcache_handle *h,
int x, int y, char *file);
void content_debug_dump(struct hlcache_handle *h, FILE *f);
struct content_rfc5988_link *content_find_rfc5988_link(struct hlcache_handle *c,
lwc_string *rel);
 
/* Member accessors */
content_type content_get_type(struct hlcache_handle *c);
lwc_string *content_get_mime_type(struct hlcache_handle *c);
const char *content_get_title(struct hlcache_handle *c);
content_status content_get_status(struct hlcache_handle *c);
const char *content_get_status_message(struct hlcache_handle *c);
int content_get_width(struct hlcache_handle *c);
int content_get_height(struct hlcache_handle *c);
int content_get_available_width(struct hlcache_handle *c);
const char *content_get_source_data(struct hlcache_handle *c,
unsigned long *size);
void content_invalidate_reuse_data(struct hlcache_handle *c);
nsurl *content_get_refresh_url(struct hlcache_handle *c);
struct bitmap *content_get_bitmap(struct hlcache_handle *c);
bool content_get_opaque(struct hlcache_handle *h);
bool content_get_quirks(struct hlcache_handle *c);
 
bool content_is_locked(struct hlcache_handle *h);
 
#endif
/programs/network/netsurf/netsurf/content/content_factory.c
0,0 → 1,201
/*
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content factory (implementation)
*/
 
#include <assert.h>
#include <stdlib.h>
#include <string.h>
 
#include "content/content.h"
#include "content/content_factory.h"
#include "content/content_protected.h"
#include "content/llcache.h"
 
/**
* Entry in list of content handlers
*/
typedef struct content_handler_entry {
/** Next entry */
struct content_handler_entry *next;
 
/** MIME type handled by handler */
lwc_string *mime_type;
/** Content handler object */
const content_handler *handler;
} content_handler_entry;
 
static content_handler_entry *content_handlers;
 
/**
* Clean up after the content factory
*/
void content_factory_fini(void)
{
content_handler_entry *victim;
 
while (content_handlers != NULL) {
victim = content_handlers;
 
content_handlers = content_handlers->next;
 
if (victim->handler->fini != NULL)
victim->handler->fini();
 
lwc_string_unref(victim->mime_type);
 
free(victim);
}
}
 
/**
* Register a handler with the content factory
*
* \param mime_type MIME type to handle
* \param handler Content handler for MIME type
* \return NSERROR_OK on success, appropriate error otherwise
*
* \note Latest registration for a MIME type wins
*/
nserror content_factory_register_handler(const char *mime_type,
const content_handler *handler)
{
lwc_string *imime_type;
lwc_error lerror;
content_handler_entry *entry;
bool match;
 
lerror = lwc_intern_string(mime_type, strlen(mime_type), &imime_type);
if (lerror != lwc_error_ok)
return NSERROR_NOMEM;
 
for (entry = content_handlers; entry != NULL; entry = entry->next) {
if (lwc_string_caseless_isequal(imime_type, entry->mime_type,
&match) == lwc_error_ok && match)
break;
}
 
if (entry == NULL) {
entry = malloc(sizeof(content_handler_entry));
if (entry == NULL)
return NSERROR_NOMEM;
 
entry->next = content_handlers;
content_handlers = entry;
 
entry->mime_type = imime_type;
} else {
lwc_string_unref(imime_type);
}
 
entry->handler = handler;
 
return NSERROR_OK;
}
 
/**
* Find a handler for a MIME type.
*
* \param mime_type MIME type to search for
* \return Associated handler, or NULL if none
*/
static const content_handler *content_lookup(lwc_string *mime_type)
{
content_handler_entry *entry;
bool match;
 
for (entry = content_handlers; entry != NULL; entry = entry->next) {
if (lwc_string_caseless_isequal(mime_type, entry->mime_type,
&match) == lwc_error_ok && match)
break;
}
 
if (entry != NULL)
return entry->handler;
 
return NULL;
}
 
/**
* Compute the generic content type for a MIME type
*
* \param mime_type MIME type to consider
* \return Generic content type
*/
content_type content_factory_type_from_mime_type(lwc_string *mime_type)
{
const content_handler *handler;
content_type type = CONTENT_NONE;
 
handler = content_lookup(mime_type);
if (handler != NULL) {
type = handler->type();
}
 
return type;
}
 
/**
* Create a content object
*
* \param llcache Underlying source data handle
* \param fallback_charset Character set to fall back to if none specified
* \param quirks Quirkiness of containing document
* \param effective_type Effective MIME type of content
* \return Pointer to content object, or NULL on failure
*/
struct content *content_factory_create_content(llcache_handle *llcache,
const char *fallback_charset, bool quirks,
lwc_string *effective_type)
{
struct content *c;
const char *content_type_header;
const content_handler *handler;
http_content_type *ct = NULL;
nserror error;
 
handler = content_lookup(effective_type);
if (handler == NULL)
return NULL;
 
assert(handler->create != NULL);
 
/* Use the parameters from the declared Content-Type header */
content_type_header =
llcache_handle_get_header(llcache, "Content-Type");
if (content_type_header != NULL) {
/* We don't care if this fails */
http_parse_content_type(content_type_header, &ct);
}
 
error = handler->create(handler, effective_type,
ct != NULL ? ct->parameters : NULL,
llcache, fallback_charset, quirks,
&c);
 
if (ct != NULL)
http_content_type_destroy(ct);
 
if (error != NSERROR_OK)
return NULL;
 
return c;
}
 
/programs/network/netsurf/netsurf/content/content_factory.h
0,0 → 1,64
/*
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_CONTENT_CONTENT_FACTORY_H_
#define NETSURF_CONTENT_CONTENT_FACTORY_H_
 
#include <stdbool.h>
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "content/content_type.h"
#include "utils/errors.h"
#include "utils/utils.h"
 
#define CONTENT_FACTORY_REGISTER_TYPES(HNAME, HTYPELIST, HHANDLER) \
\
nserror HNAME##_init(void) \
{ \
uint32_t i; \
nserror error = NSERROR_OK; \
\
for (i = 0; i < NOF_ELEMENTS(HTYPELIST); i++) { \
error = content_factory_register_handler( \
HTYPELIST[i], \
&HHANDLER); \
if (error != NSERROR_OK) \
break; \
} \
\
return error; \
}
 
struct content;
struct llcache_handle;
 
typedef struct content_handler content_handler;
 
void content_factory_fini(void);
 
nserror content_factory_register_handler(const char *mime_type,
const content_handler *handler);
 
struct content *content_factory_create_content(struct llcache_handle *llcache,
const char *fallback_charset, bool quirks,
lwc_string *effective_type);
 
content_type content_factory_type_from_mime_type(lwc_string *mime_type);
 
#endif
/programs/network/netsurf/netsurf/content/content_protected.h
0,0 → 1,197
/*
* Copyright 2005-2007 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Philip Pemberton <philpem@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content handling (interface).
*
* The content functions manipulate struct contents, which correspond to URLs.
*/
 
#ifndef _NETSURF_CONTENT_CONTENT_PROTECTED_H_
#define _NETSURF_CONTENT_CONTENT_PROTECTED_H_
 
#include <stdint.h>
#include <time.h>
#include "utils/config.h"
#include "content/content.h"
#include "content/content_factory.h"
#include "content/llcache.h"
#include "utils/errors.h"
 
struct bitmap;
struct content;
struct rect;
struct redraw_context;
 
struct content_handler {
void (*fini)(void);
 
nserror (*create)(const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache,
const char *fallback_charset, bool quirks,
struct content **c);
 
bool (*process_data)(struct content *c,
const char *data, unsigned int size);
bool (*data_complete)(struct content *c);
void (*reformat)(struct content *c, int width, int height);
void (*destroy)(struct content *c);
void (*stop)(struct content *c);
void (*mouse_track)(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
void (*mouse_action)(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
bool (*redraw)(struct content *c, struct content_redraw_data *data,
const struct rect *clip,
const struct redraw_context *ctx);
void (*open)(struct content *c, struct browser_window *bw,
struct content *page, struct object_params *params);
void (*close)(struct content *c);
struct selection * (*get_selection)(struct content *c);
void (*get_contextual_content)(struct content *c, int x, int y,
struct contextual_content *data);
bool (*scroll_at_point)(struct content *c, int x, int y,
int scrx, int scry);
bool (*drop_file_at_point)(struct content *c, int x, int y,
char *file);
void (*debug_dump)(struct content *c, FILE *f);
nserror (*clone)(const struct content *old, struct content **newc);
bool (*matches_quirks)(const struct content *c, bool quirks);
content_type (*type)(void);
 
/** handler dependant content sensitive internal data interface. */
void * (*get_internal)(const struct content *c, void *context);
 
/** There must be one content per user for this type. */
bool no_share;
};
 
/** Linked list of users of a content. */
struct content_user
{
void (*callback)(struct content *c, content_msg msg,
union content_msg_data data, void *pw);
void *pw;
 
struct content_user *next;
};
 
/** Corresponds to a single URL. */
struct content {
llcache_handle *llcache; /**< Low-level cache object */
 
lwc_string *mime_type; /**< Original MIME type of data */
 
const content_handler *handler; /**< Handler for content */
 
content_status status; /**< Current status. */
 
int width, height; /**< Dimensions, if applicable. */
int available_width; /**< Available width (eg window width). */
 
bool quirks; /**< Content is in quirks mode */
char *fallback_charset; /**< Fallback charset, or NULL */
 
nsurl *refresh; /**< URL for refresh request */
 
struct content_rfc5988_link *links; /**< list of metadata links */
 
unsigned int time; /**< Creation time,
if LOADING or READY,
otherwise total time. */
 
unsigned int reformat_time; /**< Earliest time to attempt a
period reflow while fetching a
page's objects. */
 
unsigned int size; /**< Estimated size of all data
associated with this content */
char *title; /**< Title for browser window. */
unsigned int active; /**< Number of child fetches or
conversions currently in progress. */
struct content_user *user_list; /**< List of users. */
char status_message[120]; /**< Full text for status bar. */
char sub_status[80]; /**< Status of content. */
/** Content is being processed: data structures may be inconsistent
* and content must not be redrawn or modified. */
bool locked;
 
unsigned long total_size; /**< Total data size, 0 if unknown. */
long http_code; /**< HTTP status code, 0 if not HTTP. */
 
/** Array of first n rendering errors or warnings. */
struct {
const char *token;
unsigned int line; /**< Line no, 0 if not applicable. */
} error_list[40];
unsigned int error_count; /**< Number of valid error entries. */
};
 
extern const char * const content_type_name[];
extern const char * const content_status_name[];
 
nserror content__init(struct content *c, const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
struct llcache_handle *llcache, const char *fallback_charset,
bool quirks);
nserror content__clone(const struct content *c, struct content *nc);
 
void content_set_ready(struct content *c);
void content_set_done(struct content *c);
void content_set_error(struct content *c);
 
void content_set_status(struct content *c, const char *status_message);
void content_broadcast(struct content *c, content_msg msg,
union content_msg_data data);
/**
* Send an errorcode message to all users.
*/
void content_broadcast_errorcode(struct content *c, nserror errorcode);
 
void content_add_error(struct content *c, const char *token,
unsigned int line);
 
bool content__add_rfc5988_link(struct content *c,
const struct content_rfc5988_link *link);
struct content_rfc5988_link *content__free_rfc5988_link(
struct content_rfc5988_link *link);
 
void content__reformat(struct content *c, bool background,
int width, int height);
void content__request_redraw(struct content *c,
int x, int y, int width, int height);
 
bool content__set_title(struct content *c, const char *title);
 
lwc_string *content__get_mime_type(struct content *c);
const char *content__get_title(struct content *c);
const char *content__get_status_message(struct content *c);
int content__get_width(struct content *c);
int content__get_height(struct content *c);
int content__get_available_width(struct content *c);
const char *content__get_source_data(struct content *c, unsigned long *size);
void content__invalidate_reuse_data(struct content *c);
nsurl *content__get_refresh_url(struct content *c);
struct bitmap *content__get_bitmap(struct content *c);
bool content__get_opaque(struct content *c);
 
bool content__is_locked(struct content *c);
 
#endif
/programs/network/netsurf/netsurf/content/content_type.h
0,0 → 1,58
/*
* Copyright 2003 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Declaration of content_type enum.
*
* The content_type enum is defined here to prevent cyclic dependencies.
*/
 
#ifndef _NETSURF_DESKTOP_CONTENT_TYPE_H_
#define _NETSURF_DESKTOP_CONTENT_TYPE_H_
 
#include "utils/config.h"
 
 
/** The type of a content. */
typedef enum {
CONTENT_NONE = 0x00,
 
CONTENT_HTML = 0x01,
CONTENT_TEXTPLAIN = 0x02,
CONTENT_CSS = 0x04,
 
/** All images */
CONTENT_IMAGE = 0x08,
 
/** Navigator API Plugins */
CONTENT_PLUGIN = 0x10,
 
/** Themes (only GTK and RISC OS) */
CONTENT_THEME = 0x20,
 
/** Javascript */
CONTENT_JS = 0x40,
/** All script types. */
CONTENT_SCRIPT = 0x40,
 
/** Any content matches */
CONTENT_ANY = 0x7f
} content_type;
 
 
#endif
/programs/network/netsurf/netsurf/content/dirlist.c
0,0 → 1,385
/*
* Copyright 2010 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Generate HTML content for displaying directory listings (implementation).
*/
 
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "content/dirlist.h"
#include "utils/messages.h"
 
static const char footer[] = "</div>\n</body>\n</html>\n";
 
static int dirlist_filesize_calculate(unsigned long *bytesize);
static int dirlist_filesize_value(unsigned long bytesize);
static char* dirlist_filesize_unit(unsigned long bytesize);
 
 
/**
* Generates the top part of an HTML directory listing page
*
* \return Top of directory listing HTML
*
* This is part of a series of functions. To generate a complete page,
* call the following functions in order:
*
* dirlist_generate_top()
* dirlist_generate_hide_columns() -- optional
* dirlist_generate_title()
* dirlist_generate_parent_link() -- optional
* dirlist_generate_headings()
* dirlist_generate_row() -- call 'n' times for 'n' rows
* dirlist_generate_bottom()
*/
 
bool dirlist_generate_top(char *buffer, int buffer_length)
{
int error = snprintf(buffer, buffer_length,
"<html>\n"
"<head>\n"
"<link rel=\"stylesheet\" title=\"Standard\" "
"type=\"text/css\" href=\"resource:internal.css\">\n"
"<style>\n");
if (error < 0 || error >= buffer_length)
/* Error or buffer too small */
return false;
else
/* OK */
return true;
 
}
 
 
/**
* Generates the part of an HTML directory listing page that can suppress
* particular columns
*
* \param flags flags for which cols to suppress. 0 to suppress none
* \param buffer buffer to fill with generated HTML
* \param buffer_length maximum size of buffer
* \return true iff buffer filled without error
*
* This is part of a series of functions. To generate a complete page,
* call the following functions in order:
*
* dirlist_generate_top()
* dirlist_generate_hide_columns() -- optional
* dirlist_generate_title()
* dirlist_generate_parent_link() -- optional
* dirlist_generate_headings()
* dirlist_generate_row() -- call 'n' times for 'n' rows
* dirlist_generate_bottom()
*/
 
bool dirlist_generate_hide_columns(int flags, char *buffer, int buffer_length)
{
int error = snprintf(buffer, buffer_length,
"%s\n%s\n%s\n%s\n%s\n",
(flags & DIRLIST_NO_NAME_COLUMN) ?
"span.name { display: none; }\n" : "",
(flags & DIRLIST_NO_TYPE_COLUMN) ?
"span.type { display: none; }\n" : "",
(flags & DIRLIST_NO_SIZE_COLUMN) ?
"span.size { display: none; }\n" : "",
(flags & DIRLIST_NO_DATE_COLUMN) ?
"span.date { display: none; }\n" : "",
(flags & DIRLIST_NO_TIME_COLUMN) ?
"span.time { display: none; }\n" : "");
if (error < 0 || error >= buffer_length)
/* Error or buffer too small */
return false;
else
/* OK */
return true;
}
 
 
/**
* Generates the part of an HTML directory listing page that contains the title
*
* \param title title to use
* \param buffer buffer to fill with generated HTML
* \param buffer_length maximum size of buffer
* \return true iff buffer filled without error
*
* This is part of a series of functions. To generate a complete page,
* call the following functions in order:
*
* dirlist_generate_top()
* dirlist_generate_hide_columns() -- optional
* dirlist_generate_title()
* dirlist_generate_parent_link() -- optional
* dirlist_generate_headings()
* dirlist_generate_row() -- call 'n' times for 'n' rows
* dirlist_generate_bottom()
*/
 
bool dirlist_generate_title(const char *title, char *buffer, int buffer_length)
{
int error;
 
if (title == NULL)
title = "";
 
error = snprintf(buffer, buffer_length,
"</style>\n"
"<title>%s</title>\n"
"</head>\n"
"<body id=\"dirlist\">\n"
"<h1>%s</h1>\n",
title, title);
if (error < 0 || error >= buffer_length)
/* Error or buffer too small */
return false;
else
/* OK */
return true;
}
 
 
/**
* Generates the part of an HTML directory listing page that links to the parent
* directory
*
* \param parent url of parent directory
* \param buffer buffer to fill with generated HTML
* \param buffer_length maximum size of buffer
* \return true iff buffer filled without error
*
* This is part of a series of functions. To generate a complete page,
* call the following functions in order:
*
* dirlist_generate_top()
* dirlist_generate_hide_columns() -- optional
* dirlist_generate_title()
* dirlist_generate_parent_link() -- optional
* dirlist_generate_headings()
* dirlist_generate_row() -- call 'n' times for 'n' rows
* dirlist_generate_bottom()
*/
 
bool dirlist_generate_parent_link(const char *parent, char *buffer,
int buffer_length)
{
int error = snprintf(buffer, buffer_length,
"<p><a href=\"%s\">%s</a></p>",
parent, messages_get("FileParent"));
if (error < 0 || error >= buffer_length)
/* Error or buffer too small */
return false;
else
/* OK */
return true;
}
 
 
/**
* Generates the part of an HTML directory listing page that displays the column
* headings
*
* \param buffer buffer to fill with generated HTML
* \param buffer_length maximum size of buffer
* \return true iff buffer filled without error
*
* This is part of a series of functions. To generate a complete page,
* call the following functions in order:
*
* dirlist_generate_top()
* dirlist_generate_hide_columns() -- optional
* dirlist_generate_title()
* dirlist_generate_parent_link() -- optional
* dirlist_generate_headings()
* dirlist_generate_row() -- call 'n' times for 'n' rows
* dirlist_generate_bottom()
*/
 
bool dirlist_generate_headings(char *buffer, int buffer_length)
{
int error = snprintf(buffer, buffer_length,
"<div>\n"
"<strong>\n"
"\t<span class=\"name\">%s</span>\n"
"\t<span class=\"type\">%s</span>\n"
"\t<span class=\"size\">%s</span>"
"<span class=\"size\"></span>\n"
"\t<span class=\"date\">%s</span>\n"
"\t<span class=\"time\">%s</span>\n"
"</strong>\n",
messages_get("FileName"), messages_get("FileType"),
messages_get("FileSize"), messages_get("FileDate"),
messages_get("FileTime"));
if (error < 0 || error >= buffer_length)
/* Error or buffer too small */
return false;
else
/* OK */
return true;
}
 
 
/**
* Generates the part of an HTML directory listing page that displays a row
* in the directory contents table
*
* \param even evenness of row number, for alternate row colouring
* \param directory whether this row is for a directory (or a file)
* \param url url for row entry
* \param name name of row entry
* \param mimetype MIME type of row entry
* \param size size of row entry. If negative, size is left blank
* \param date date row entry was last modified
* \param time time row entry was last modified
* \param buffer buffer to fill with generated HTML
* \param buffer_length maximum size of buffer
* \return true iff buffer filled without error
*
* This is part of a series of functions. To generate a complete page,
* call the following functions in order:
*
* dirlist_generate_top()
* dirlist_generate_hide_columns() -- optional
* dirlist_generate_title()
* dirlist_generate_parent_link() -- optional
* dirlist_generate_headings()
* dirlist_generate_row() -- call 'n' times for 'n' rows
* dirlist_generate_bottom()
*/
 
bool dirlist_generate_row(bool even, bool directory, char *url, char *name,
const char *mimetype, long long size, char *date, char *time,
char *buffer, int buffer_length)
{
const char *unit;
char size_string[100];
int error;
 
if (size < 0) {
unit = "";
strncpy(size_string, "", sizeof size_string);
} else {
unit = messages_get(dirlist_filesize_unit((unsigned long)size));
snprintf(size_string, sizeof size_string, "%d",
dirlist_filesize_value((unsigned long)size));
}
 
error = snprintf(buffer, buffer_length,
"<a href=\"%s\" class=\"%s %s\">\n"
"\t<span class=\"name\">%s</span>\n"
"\t<span class=\"type\">%s</span>\n"
"\t<span class=\"size\">%s</span>"
"<span class=\"size\">%s</span>\n"
"\t<span class=\"date\">%s</span>\n"
"\t<span class=\"time\">%s</span>\n"
"</a>\n",
url, even ? "even" : "odd",
directory ? "dir" : "file",
name, mimetype, size_string, unit, date, time);
if (error < 0 || error >= buffer_length)
/* Error or buffer too small */
return false;
else
/* OK */
return true;
}
 
 
/**
* Generates the bottom part of an HTML directory listing page
*
* \return Bottom of directory listing HTML
*
* This is part of a series of functions. To generate a complete page,
* call the following functions in order:
*
* dirlist_generate_top()
* dirlist_generate_hide_columns() -- optional
* dirlist_generate_title()
* dirlist_generate_parent_link() -- optional
* dirlist_generate_headings()
* dirlist_generate_row() -- call 'n' times for 'n' rows
* dirlist_generate_bottom()
*/
 
bool dirlist_generate_bottom(char *buffer, int buffer_length)
{
int error = snprintf(buffer, buffer_length,
"</div>\n"
"</body>\n"
"</html>\n");
if (error < 0 || error >= buffer_length)
/* Error or buffer too small */
return false;
else
/* OK */
return true;
}
 
 
/**
* Obtain display value and units for filesize after conversion to B/kB/MB/GB,
* as appropriate.
*
* \param bytesize file size in bytes, updated to filesize in output units
* \return number of times bytesize has been divided by 1024
*/
 
int dirlist_filesize_calculate(unsigned long *bytesize)
{
int i = 0;
while (*bytesize > 1024 * 4) {
*bytesize /= 1024;
i++;
if (i == 3)
break;
}
return i;
}
 
 
/**
* Obtain display value for filesize after conversion to B/kB/MB/GB,
* as appropriate
*
* \param bytesize file size in bytes
* \return Value to display for file size, in units given by filesize_unit()
*/
 
int dirlist_filesize_value(unsigned long bytesize)
{
dirlist_filesize_calculate(&bytesize);
return (int)bytesize;
}
 
 
/**
* Obtain display units for filesize after conversion to B/kB/MB/GB,
* as appropriate
*
* \param bytesize file size in bytes
* \return Units to display for file size, for value given by filesize_value()
*/
 
char* dirlist_filesize_unit(unsigned long bytesize)
{
const char* units[] = { "Bytes", "kBytes", "MBytes", "GBytes" };
return (char*)units[dirlist_filesize_calculate(&bytesize)];
}
/programs/network/netsurf/netsurf/content/dirlist.h
0,0 → 1,47
/*
* Copyright 2010 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Generate HTML content for displaying directory listings (interface).
*
* These functions should in general be called via the content interface.
*/
 
#ifndef _NETSURF_CONTENT_DIRLIST_H_
#define _NETSURF_CONTENT_DIRLIST_H_
 
#include <stdbool.h>
 
#define DIRLIST_NO_NAME_COLUMN 1
#define DIRLIST_NO_TYPE_COLUMN 1 << 1
#define DIRLIST_NO_SIZE_COLUMN 1 << 2
#define DIRLIST_NO_DATE_COLUMN 1 << 3
#define DIRLIST_NO_TIME_COLUMN 1 << 4
 
bool dirlist_generate_top(char *buffer, int buffer_length);
bool dirlist_generate_hide_columns(int flags, char *buffer, int buffer_length);
bool dirlist_generate_title(const char *title, char *buffer, int buffer_length);
bool dirlist_generate_parent_link(const char *parent, char *buffer,
int buffer_length);
bool dirlist_generate_headings(char *buffer, int buffer_length);
bool dirlist_generate_row(bool even, bool directory, char *url, char *name,
const char *mimetype, long long size, char *date, char *time,
char *buffer, int buffer_length);
bool dirlist_generate_bottom(char *buffer, int buffer_length);
 
#endif
/programs/network/netsurf/netsurf/content/fetch.c
0,0 → 1,743
/*
* Copyright 2006,2007 Daniel Silverstone <dsilvers@digital-scurf.org>
* Copyright 2007 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Fetching of data from a URL (implementation).
*
* Active fetches are held in the circular linked list ::fetch_ring. There may
* be at most ::option_max_fetchers_per_host active requests per Host: header.
* There may be at most ::option_max_fetchers active requests overall. Inactive
* fetchers are stored in the ::queue_ring waiting for use.
*/
 
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include <time.h>
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/config.h"
#include "content/fetch.h"
#include "content/fetchers/resource.h"
#include "content/fetchers/about.h"
#include "content/fetchers/curl.h"
#include "content/fetchers/data.h"
#include "content/fetchers/file.h"
#include "content/urldb.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/nsurl.h"
#include "utils/utils.h"
#include "utils/ring.h"
 
/* Define this to turn on verbose fetch logging */
#undef DEBUG_FETCH_VERBOSE
 
bool fetch_active; /**< Fetches in progress, please call fetch_poll(). */
 
/** Information about a fetcher for a given scheme. */
typedef struct scheme_fetcher_s {
lwc_string *scheme_name; /**< The scheme. */
fetcher_can_fetch can_fetch; /**< Ensure an URL can be fetched. */
fetcher_setup_fetch setup_fetch; /**< Set up a fetch. */
fetcher_start_fetch start_fetch; /**< Start a fetch. */
fetcher_abort_fetch abort_fetch; /**< Abort a fetch. */
fetcher_free_fetch free_fetch; /**< Free a fetch. */
fetcher_poll_fetcher poll_fetcher; /**< Poll this fetcher. */
fetcher_finalise finaliser; /**< Clean up this fetcher. */
int refcount; /**< When zero, clean up the fetcher. */
struct scheme_fetcher_s *next_fetcher; /**< Next fetcher in the list. */
struct scheme_fetcher_s *prev_fetcher; /**< Prev fetcher in the list. */
} scheme_fetcher;
 
static scheme_fetcher *fetchers = NULL;
 
/** Information for a single fetch. */
struct fetch {
fetch_callback callback;/**< Callback function. */
nsurl *url; /**< URL. */
nsurl *referer; /**< Referer URL. */
bool send_referer; /**< Valid to send the referer */
bool verifiable; /**< Transaction is verifiable */
void *p; /**< Private data for callback. */
lwc_string *host; /**< Host part of URL, interned */
long http_code; /**< HTTP response code, or 0. */
scheme_fetcher *ops; /**< Fetcher operations for this fetch,
NULL if not set. */
void *fetcher_handle; /**< The handle for the fetcher. */
bool fetch_is_active; /**< This fetch is active. */
struct fetch *r_prev; /**< Previous active fetch in ::fetch_ring. */
struct fetch *r_next; /**< Next active fetch in ::fetch_ring. */
};
 
static struct fetch *fetch_ring = 0; /**< Ring of active fetches. */
static struct fetch *queue_ring = 0; /**< Ring of queued fetches */
 
#define fetch_ref_fetcher(F) F->refcount++
static void fetch_unref_fetcher(scheme_fetcher *fetcher);
static void fetch_dispatch_jobs(void);
static bool fetch_choose_and_dispatch(void);
static bool fetch_dispatch_job(struct fetch *fetch);
 
/* Static lwc_strings */
static lwc_string *fetch_http_lwc;
static lwc_string *fetch_https_lwc;
 
 
/**
* Initialise the fetcher.
*/
 
void fetch_init(void)
{
fetch_curl_register();
fetch_data_register();
fetch_file_register();
fetch_resource_register();
fetch_about_register();
fetch_active = false;
 
if (lwc_intern_string("http", SLEN("http"), &fetch_http_lwc) !=
lwc_error_ok) {
die("Failed to initialise the fetch module "
"(couldn't intern \"http\").");
}
 
if (lwc_intern_string("https", SLEN("https"), &fetch_https_lwc) !=
lwc_error_ok) {
die("Failed to initialise the fetch module "
"(couldn't intern \"https\").");
}
}
 
 
/**
* Clean up for quit.
*
* Must be called before exiting.
*/
 
void fetch_quit(void)
{
while (fetchers != NULL) {
if (fetchers->refcount != 1) {
LOG(("Fetcher for scheme %s still active?!",
lwc_string_data(fetchers->scheme_name)));
/* We shouldn't do this, but... */
fetchers->refcount = 1;
}
fetch_unref_fetcher(fetchers);
}
 
lwc_string_unref(fetch_http_lwc);
lwc_string_unref(fetch_https_lwc);
}
 
 
bool fetch_add_fetcher(lwc_string *scheme,
fetcher_initialise initialiser,
fetcher_can_fetch can_fetch,
fetcher_setup_fetch setup_fetch,
fetcher_start_fetch start_fetch,
fetcher_abort_fetch abort_fetch,
fetcher_free_fetch free_fetch,
fetcher_poll_fetcher poll_fetcher,
fetcher_finalise finaliser)
{
scheme_fetcher *new_fetcher;
if (!initialiser(scheme))
return false;
new_fetcher = malloc(sizeof(scheme_fetcher));
if (new_fetcher == NULL) {
finaliser(scheme);
return false;
}
new_fetcher->scheme_name = scheme;
new_fetcher->refcount = 0;
new_fetcher->can_fetch = can_fetch;
new_fetcher->setup_fetch = setup_fetch;
new_fetcher->start_fetch = start_fetch;
new_fetcher->abort_fetch = abort_fetch;
new_fetcher->free_fetch = free_fetch;
new_fetcher->poll_fetcher = poll_fetcher;
new_fetcher->finaliser = finaliser;
new_fetcher->next_fetcher = fetchers;
fetchers = new_fetcher;
fetch_ref_fetcher(new_fetcher);
return true;
}
 
 
void fetch_unref_fetcher(scheme_fetcher *fetcher)
{
if (--fetcher->refcount == 0) {
fetcher->finaliser(fetcher->scheme_name);
lwc_string_unref(fetcher->scheme_name);
if (fetcher == fetchers) {
fetchers = fetcher->next_fetcher;
if (fetchers)
fetchers->prev_fetcher = NULL;
} else {
fetcher->prev_fetcher->next_fetcher =
fetcher->next_fetcher;
if (fetcher->next_fetcher != NULL)
fetcher->next_fetcher->prev_fetcher =
fetcher->prev_fetcher;
}
free(fetcher);
}
}
 
 
/**
* Start fetching data for the given URL.
*
* The function returns immediately. The fetch may be queued for later
* processing.
*
* A pointer to an opaque struct fetch is returned, which can be passed to
* fetch_abort() to abort the fetch at any time. Returns 0 if memory is
* exhausted (or some other fatal error occurred).
*
* The caller must supply a callback function which is called when anything
* interesting happens. The callback function is first called with msg
* FETCH_HEADER, with the header in data, then one or more times
* with FETCH_DATA with some data for the url, and finally with
* FETCH_FINISHED. Alternatively, FETCH_ERROR indicates an error occurred:
* data contains an error message. FETCH_REDIRECT may replace the FETCH_HEADER,
* FETCH_DATA, FETCH_FINISHED sequence if the server sends a replacement URL.
*
*/
 
struct fetch * fetch_start(nsurl *url, nsurl *referer,
fetch_callback callback,
void *p, bool only_2xx, const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
bool verifiable, bool downgrade_tls,
const char *headers[])
{
struct fetch *fetch;
scheme_fetcher *fetcher = fetchers;
lwc_string *scheme;
bool match;
 
fetch = malloc(sizeof (*fetch));
if (fetch == NULL)
return NULL;
 
/* The URL we're fetching must have a scheme */
scheme = nsurl_get_component(url, NSURL_SCHEME);
assert(scheme != NULL);
 
#ifdef DEBUG_FETCH_VERBOSE
LOG(("fetch %p, url '%s'", fetch, nsurl_access(url)));
#endif
 
/* construct a new fetch structure */
fetch->callback = callback;
fetch->url = nsurl_ref(url);
fetch->verifiable = verifiable;
fetch->p = p;
fetch->http_code = 0;
fetch->r_prev = NULL;
fetch->r_next = NULL;
fetch->referer = NULL;
fetch->send_referer = false;
fetch->fetcher_handle = NULL;
fetch->ops = NULL;
fetch->fetch_is_active = false;
fetch->host = nsurl_get_component(url, NSURL_HOST);
if (referer != NULL) {
lwc_string *ref_scheme;
fetch->referer = nsurl_ref(referer);
 
ref_scheme = nsurl_get_component(referer, NSURL_SCHEME);
/* Not a problem if referer has no scheme */
 
/* Determine whether to send the Referer header */
if (nsoption_bool(send_referer) && ref_scheme != NULL) {
/* User permits us to send the header
* Only send it if:
* 1) The fetch and referer schemes match
* or 2) The fetch is https and the referer is http
*
* This ensures that referer information is only sent
* across schemes in the special case of an https
* request from a page served over http. The inverse
* (https -> http) should not send the referer (15.1.3)
*/
bool match1;
bool match2;
if (lwc_string_isequal(scheme, ref_scheme, &match) != lwc_error_ok) {
match = false;
}
if (lwc_string_isequal(scheme, fetch_https_lwc, &match1) != lwc_error_ok) {
match1 = false;
}
if (lwc_string_isequal(ref_scheme, fetch_http_lwc, &match2) != lwc_error_ok) {
match2= false;
}
if (match == true || (match1 == true && match2 == true))
fetch->send_referer = true;
}
if (ref_scheme != NULL)
lwc_string_unref(ref_scheme);
}
 
/* Pick the scheme ops */
while (fetcher) {
if ((lwc_string_isequal(fetcher->scheme_name, scheme,
&match) == lwc_error_ok) && (match == true)) {
fetch->ops = fetcher;
break;
}
fetcher = fetcher->next_fetcher;
}
 
if (fetch->ops == NULL)
goto failed;
 
/* Got a scheme fetcher, try and set up the fetch */
fetch->fetcher_handle = fetch->ops->setup_fetch(fetch, url,
only_2xx, downgrade_tls,
post_urlenc, post_multipart,
headers);
 
if (fetch->fetcher_handle == NULL)
goto failed;
 
/* Rah, got it, so ref the fetcher. */
fetch_ref_fetcher(fetch->ops);
 
/* these aren't needed past here */
lwc_string_unref(scheme);
 
/* Dump us in the queue and ask the queue to run. */
RING_INSERT(queue_ring, fetch);
fetch_dispatch_jobs();
 
return fetch;
 
failed:
lwc_string_unref(scheme);
 
if (fetch->host != NULL)
lwc_string_unref(fetch->host);
if (fetch->url != NULL)
nsurl_unref(fetch->url);
if (fetch->referer != NULL)
nsurl_unref(fetch->referer);
 
free(fetch);
 
return NULL;
}
 
 
/**
* Dispatch as many jobs as we have room to dispatch.
*/
void fetch_dispatch_jobs(void)
{
int all_active, all_queued;
#ifdef DEBUG_FETCH_VERBOSE
struct fetch *q;
struct fetch *f;
#endif
 
if (!queue_ring)
return; /* Nothing to do, the queue is empty */
RING_GETSIZE(struct fetch, queue_ring, all_queued);
RING_GETSIZE(struct fetch, fetch_ring, all_active);
 
#ifdef DEBUG_FETCH_VERBOSE
LOG(("queue_ring %i, fetch_ring %i", all_queued, all_active));
 
q = queue_ring;
if (q) {
do {
LOG(("queue_ring: %s", q->url));
q = q->r_next;
} while (q != queue_ring);
}
f = fetch_ring;
if (f) {
do {
LOG(("fetch_ring: %s", f->url));
f = f->r_next;
} while (f != fetch_ring);
}
#endif
 
while ( all_queued && all_active < nsoption_int(max_fetchers) ) {
/*LOG(("%d queued, %d fetching", all_queued, all_active));*/
if (fetch_choose_and_dispatch()) {
all_queued--;
all_active++;
} else {
/* Either a dispatch failed or we ran out. Just stop */
break;
}
}
fetch_active = (all_active > 0);
#ifdef DEBUG_FETCH_VERBOSE
LOG(("Fetch ring is now %d elements.", all_active));
LOG(("Queue ring is now %d elements.", all_queued));
#endif
}
 
 
/**
* Choose and dispatch a single job. Return false if we failed to dispatch
* anything.
*
* We don't check the overall dispatch size here because we're not called unless
* there is room in the fetch queue for us.
*/
bool fetch_choose_and_dispatch(void)
{
bool same_host;
struct fetch *queueitem;
queueitem = queue_ring;
do {
/* We can dispatch the selected item if there is room in the
* fetch ring
*/
int countbyhost;
RING_COUNTBYLWCHOST(struct fetch, fetch_ring, countbyhost,
queueitem->host);
if (countbyhost < nsoption_int(max_fetchers_per_host)) {
/* We can dispatch this item in theory */
return fetch_dispatch_job(queueitem);
}
/* skip over other items with the same host */
same_host = true;
while (same_host == true && queueitem->r_next != queue_ring) {
if (lwc_string_isequal(queueitem->host,
queueitem->r_next->host, &same_host) ==
lwc_error_ok && same_host == true) {
queueitem = queueitem->r_next;
}
}
queueitem = queueitem->r_next;
} while (queueitem != queue_ring);
return false;
}
 
 
/**
* Dispatch a single job
*/
bool fetch_dispatch_job(struct fetch *fetch)
{
RING_REMOVE(queue_ring, fetch);
#ifdef DEBUG_FETCH_VERBOSE
LOG(("Attempting to start fetch %p, fetcher %p, url %s", fetch,
fetch->fetcher_handle, nsurl_access(fetch->url)));
#endif
if (!fetch->ops->start_fetch(fetch->fetcher_handle)) {
RING_INSERT(queue_ring, fetch); /* Put it back on the end of the queue */
return false;
} else {
RING_INSERT(fetch_ring, fetch);
fetch->fetch_is_active = true;
return true;
}
}
 
 
/**
* Abort a fetch.
*/
 
void fetch_abort(struct fetch *f)
{
assert(f);
#ifdef DEBUG_FETCH_VERBOSE
LOG(("fetch %p, fetcher %p, url '%s'", f, f->fetcher_handle,
nsurl_access(f->url)));
#endif
f->ops->abort_fetch(f->fetcher_handle);
}
 
 
/**
* Free a fetch structure and associated resources.
*/
 
void fetch_free(struct fetch *f)
{
#ifdef DEBUG_FETCH_VERBOSE
LOG(("Freeing fetch %p, fetcher %p", f, f->fetcher_handle));
#endif
f->ops->free_fetch(f->fetcher_handle);
fetch_unref_fetcher(f->ops);
nsurl_unref(f->url);
if (f->referer != NULL)
nsurl_unref(f->referer);
if (f->host != NULL)
lwc_string_unref(f->host);
free(f);
}
 
 
/**
* Do some work on current fetches.
*
* Must be called regularly to make progress on fetches.
*/
 
void fetch_poll(void)
{
scheme_fetcher *fetcher = fetchers;
scheme_fetcher *next_fetcher;
 
fetch_dispatch_jobs();
 
if (!fetch_active)
return; /* No point polling, there's no fetch active. */
while (fetcher != NULL) {
next_fetcher = fetcher->next_fetcher;
if (fetcher->poll_fetcher != NULL) {
/* LOG(("Polling fetcher for %s",
lwc_string_data(fetcher->scheme_name))); */
fetcher->poll_fetcher(fetcher->scheme_name);
}
fetcher = next_fetcher;
}
}
 
 
/**
* Check if a URL's scheme can be fetched.
*
* \param url URL to check
* \return true if the scheme is supported
*/
 
bool fetch_can_fetch(const nsurl *url)
{
scheme_fetcher *fetcher = fetchers;
bool match;
lwc_string *scheme = nsurl_get_component(url, NSURL_SCHEME);
 
while (fetcher != NULL) {
if (lwc_string_isequal(fetcher->scheme_name, scheme, &match) == lwc_error_ok && match == true) {
break;
}
 
fetcher = fetcher->next_fetcher;
}
 
lwc_string_unref(scheme);
 
return fetcher == NULL ? false : fetcher->can_fetch(url);
}
 
 
/**
* Change the callback function for a fetch.
*/
 
void fetch_change_callback(struct fetch *fetch,
fetch_callback callback,
void *p)
{
assert(fetch);
fetch->callback = callback;
fetch->p = p;
}
 
 
/**
* Get the HTTP response code.
*/
 
long fetch_http_code(struct fetch *fetch)
{
return fetch->http_code;
}
 
/**
* Determine if a fetch was verifiable
*
* \param fetch Fetch to consider
* \return Verifiable status of fetch
*/
bool fetch_get_verifiable(struct fetch *fetch)
{
assert(fetch);
 
return fetch->verifiable;
}
 
/**
* Clone a linked list of fetch_multipart_data.
*
* \param list List to clone
* \return Pointer to head of cloned list, or NULL on failure
*/
struct fetch_multipart_data *fetch_multipart_data_clone(
const struct fetch_multipart_data *list)
{
struct fetch_multipart_data *clone, *last = NULL;
struct fetch_multipart_data *result = NULL;
 
for (; list != NULL; list = list->next) {
clone = malloc(sizeof(struct fetch_multipart_data));
if (clone == NULL) {
if (result != NULL)
fetch_multipart_data_destroy(result);
 
return NULL;
}
 
clone->file = list->file;
 
clone->name = strdup(list->name);
if (clone->name == NULL) {
free(clone);
if (result != NULL)
fetch_multipart_data_destroy(result);
 
return NULL;
}
 
clone->value = strdup(list->value);
if (clone->value == NULL) {
free(clone->name);
free(clone);
if (result != NULL)
fetch_multipart_data_destroy(result);
 
return NULL;
}
 
clone->next = NULL;
 
if (result == NULL)
result = clone;
else
last->next = clone;
 
last = clone;
}
 
return result;
}
 
/**
* Free a linked list of fetch_multipart_data.
*
* \param list Pointer to head of list to free
*/
void fetch_multipart_data_destroy(struct fetch_multipart_data *list)
{
struct fetch_multipart_data *next;
 
for (; list != NULL; list = next) {
next = list->next;
free(list->name);
free(list->value);
free(list);
}
}
 
void
fetch_send_callback(const fetch_msg *msg, struct fetch *fetch)
{
fetch->callback(msg, fetch->p);
}
 
 
void fetch_remove_from_queues(struct fetch *fetch)
{
int all_active, all_queued;
 
/* Go ahead and free the fetch properly now */
#ifdef DEBUG_FETCH_VERBOSE
LOG(("Fetch %p, fetcher %p can be freed", fetch, fetch->fetcher_handle));
#endif
 
if (fetch->fetch_is_active) {
RING_REMOVE(fetch_ring, fetch);
} else {
RING_REMOVE(queue_ring, fetch);
}
 
RING_GETSIZE(struct fetch, fetch_ring, all_active);
RING_GETSIZE(struct fetch, queue_ring, all_queued);
 
fetch_active = (all_active > 0);
 
#ifdef DEBUG_FETCH_VERBOSE
LOG(("Fetch ring is now %d elements.", all_active));
LOG(("Queue ring is now %d elements.", all_queued));
#endif
}
 
 
void
fetch_set_http_code(struct fetch *fetch, long http_code)
{
#ifdef DEBUG_FETCH_VERBOSE
LOG(("Setting HTTP code to %ld", http_code));
#endif
fetch->http_code = http_code;
}
 
const char *fetch_get_referer_to_send(struct fetch *fetch)
{
if (fetch->send_referer)
return nsurl_access(fetch->referer);
return NULL;
}
 
void
fetch_set_cookie(struct fetch *fetch, const char *data)
{
assert(fetch && data);
 
/* If the fetch is unverifiable err on the side of caution and
* do not set the cookie */
 
if (fetch->verifiable) {
/* If the transaction's verifiable, we don't require
* that the request uri and the parent domain match,
* so don't pass in any referer/parent in this case. */
urldb_set_cookie(data, fetch->url, NULL);
} else if (fetch->referer != NULL) {
/* Permit the cookie to be set if the fetch is unverifiable
* and the fetch URI domain matches the referer. */
/** \todo Long-term, this needs to be replaced with a
* comparison against the origin fetch URI. In the case
* where a nested object requests a fetch, the origin URI
* is the nested object's parent URI, whereas the referer
* for the fetch will be the nested object's URI. */
urldb_set_cookie(data, fetch->url, fetch->referer);
}
}
 
/programs/network/netsurf/netsurf/content/fetch.h
0,0 → 1,169
/*
* Copyright 2003 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Fetching of data from a URL (interface).
*/
 
#ifndef _NETSURF_DESKTOP_FETCH_H_
#define _NETSURF_DESKTOP_FETCH_H_
 
#include <stdbool.h>
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/config.h"
#include "utils/nsurl.h"
 
struct content;
struct fetch;
struct ssl_cert_info;
 
typedef enum {
FETCH_PROGRESS,
FETCH_HEADER,
FETCH_DATA,
FETCH_FINISHED,
FETCH_ERROR,
FETCH_REDIRECT,
FETCH_NOTMODIFIED,
FETCH_AUTH,
FETCH_CERT_ERR,
FETCH_SSL_ERR
} fetch_msg_type;
 
typedef struct fetch_msg {
fetch_msg_type type;
 
union {
const char *progress;
 
struct {
const uint8_t *buf;
size_t len;
} header_or_data;
 
const char *error;
 
/** \todo Use nsurl */
const char *redirect;
 
struct {
const char *realm;
} auth;
 
struct {
const struct ssl_cert_info *certs;
size_t num_certs;
} cert_err;
} data;
} fetch_msg;
 
/** Fetch POST multipart data */
struct fetch_multipart_data {
bool file; /**< Item is a file */
char *name; /**< Name of item */
char *value; /**< Item value */
 
struct fetch_multipart_data *next; /**< Next in linked list */
};
 
struct ssl_cert_info {
long version; /**< Certificate version */
char not_before[32]; /**< Valid from date */
char not_after[32]; /**< Valid to date */
int sig_type; /**< Signature type */
long serial; /**< Serial number */
char issuer[256]; /**< Issuer details */
char subject[256]; /**< Subject details */
int cert_type; /**< Certificate type */
};
 
extern bool fetch_active;
 
typedef void (*fetch_callback)(const fetch_msg *msg, void *p);
 
 
void fetch_init(void);
struct fetch * fetch_start(nsurl *url, nsurl *referer,
fetch_callback callback,
void *p, bool only_2xx, const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
bool verifiable, bool downgrade_tls,
const char *headers[]);
void fetch_abort(struct fetch *f);
void fetch_poll(void);
void fetch_quit(void);
const char *fetch_filetype(const char *unix_path);
char *fetch_mimetype(const char *ro_path);
bool fetch_can_fetch(const nsurl *url);
void fetch_change_callback(struct fetch *fetch,
fetch_callback callback,
void *p);
long fetch_http_code(struct fetch *fetch);
bool fetch_get_verifiable(struct fetch *fetch);
 
void fetch_multipart_data_destroy(struct fetch_multipart_data *list);
struct fetch_multipart_data *fetch_multipart_data_clone(
const struct fetch_multipart_data *list);
 
/* API for fetchers themselves */
 
typedef bool (*fetcher_initialise)(lwc_string *scheme);
typedef bool (*fetcher_can_fetch)(const nsurl *url);
typedef void *(*fetcher_setup_fetch)(struct fetch *parent_fetch, nsurl *url,
bool only_2xx, bool downgrade_tls, const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
const char **headers);
typedef bool (*fetcher_start_fetch)(void *fetch);
typedef void (*fetcher_abort_fetch)(void *fetch);
typedef void (*fetcher_free_fetch)(void *fetch);
typedef void (*fetcher_poll_fetcher)(lwc_string *scheme);
typedef void (*fetcher_finalise)(lwc_string *scheme);
 
/** Register a fetcher for a scheme
*
* \param scheme scheme fetcher is for (caller relinquishes ownership)
* \param initialiser fetcher initialiser
* \param can_fetch fetcher can fetch function
* \param setup_fetch fetcher fetch setup function
* \param start_fetch fetcher fetch start function
* \param abort_fetch fetcher fetch abort function
* \param free_fetch fetcher fetch free function
* \param poll_fetcher fetcher poll function
* \param finaliser fetcher finaliser
* \return true iff success
*/
bool fetch_add_fetcher(lwc_string *scheme,
fetcher_initialise initialiser,
fetcher_can_fetch can_fetch,
fetcher_setup_fetch setup_fetch,
fetcher_start_fetch start_fetch,
fetcher_abort_fetch abort_fetch,
fetcher_free_fetch free_fetch,
fetcher_poll_fetcher poll_fetcher,
fetcher_finalise finaliser);
 
void fetch_send_callback(const fetch_msg *msg, struct fetch *fetch);
void fetch_remove_from_queues(struct fetch *fetch);
void fetch_free(struct fetch *f);
void fetch_set_http_code(struct fetch *fetch, long http_code);
const char *fetch_get_referer_to_send(struct fetch *fetch);
void fetch_set_cookie(struct fetch *fetch, const char *data);
 
#endif
/programs/network/netsurf/netsurf/content/fetchers/about.c
0,0 → 1,858
/*
* Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/* about: URL handling.
*
* Based on the data fetcher by Rob Kendrick
* This fetcher provides a simple scheme for the user to access
* information from the browser from a known, fixed URL.
*/
 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <inttypes.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <stdio.h>
#include <dirent.h>
#include <limits.h>
#include <stdarg.h>
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/config.h"
#include "content/dirlist.h"
#include "content/fetch.h"
#include "content/fetchers/about.h"
#include "content/urldb.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/utils.h"
#include "utils/ring.h"
#include "utils/testament.h"
#include "image/image_cache.h"
 
struct fetch_about_context;
 
typedef bool (*fetch_about_handler)(struct fetch_about_context *);
 
/** Context for an about fetch */
struct fetch_about_context {
struct fetch_about_context *r_next, *r_prev;
 
struct fetch *fetchh; /**< Handle for this fetch */
 
bool aborted; /**< Flag indicating fetch has been aborted */
bool locked; /**< Flag indicating entry is already entered */
 
nsurl *url; /**< The full url the fetch refers to */
 
fetch_about_handler handler;
};
 
static struct fetch_about_context *ring = NULL;
 
/** issue fetch callbacks with locking */
static inline bool fetch_about_send_callback(const fetch_msg *msg,
struct fetch_about_context *ctx)
{
ctx->locked = true;
fetch_send_callback(msg, ctx->fetchh);
ctx->locked = false;
 
return ctx->aborted;
}
 
static bool fetch_about_send_header(struct fetch_about_context *ctx,
const char *fmt, ...)
{
char header[64];
fetch_msg msg;
va_list ap;
 
va_start(ap, fmt);
 
vsnprintf(header, sizeof header, fmt, ap);
 
va_end(ap);
 
msg.type = FETCH_HEADER;
msg.data.header_or_data.buf = (const uint8_t *) header;
msg.data.header_or_data.len = strlen(header);
 
fetch_about_send_callback(&msg, ctx);
 
return ctx->aborted;
}
 
 
 
 
static bool fetch_about_blank_handler(struct fetch_about_context *ctx)
{
fetch_msg msg;
const char buffer[2] = { ' ', '\0' };
 
/* content is going to return ok */
fetch_set_http_code(ctx->fetchh, 200);
 
/* content type */
if (fetch_about_send_header(ctx, "Content-Type: text/html"))
goto fetch_about_blank_handler_aborted;
 
msg.type = FETCH_DATA;
msg.data.header_or_data.buf = (const uint8_t *) buffer;
msg.data.header_or_data.len = strlen(buffer);
 
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_blank_handler_aborted;
 
msg.type = FETCH_FINISHED;
 
fetch_about_send_callback(&msg, ctx);
 
return true;
 
fetch_about_blank_handler_aborted:
return false;
}
 
 
static bool fetch_about_credits_handler(struct fetch_about_context *ctx)
{
fetch_msg msg;
 
/* content is going to return redirect */
fetch_set_http_code(ctx->fetchh, 302);
 
msg.type = FETCH_REDIRECT;
msg.data.redirect = "resource:credits.html";
 
fetch_about_send_callback(&msg, ctx);
 
return true;
}
 
 
static bool fetch_about_licence_handler(struct fetch_about_context *ctx)
{
fetch_msg msg;
 
/* content is going to return redirect */
fetch_set_http_code(ctx->fetchh, 302);
 
msg.type = FETCH_REDIRECT;
msg.data.redirect = "resource:licence.html";
 
fetch_about_send_callback(&msg, ctx);
 
return true;
}
 
/** Handler to generate about:cache page.
*
* Shows details of current iamge cache
*
*/
static bool fetch_about_imagecache_handler(struct fetch_about_context *ctx)
{
fetch_msg msg;
char buffer[2048]; /* output buffer */
int code = 200;
int slen;
unsigned int cent_loop = 0;
int res = 0;
 
/* content is going to return ok */
fetch_set_http_code(ctx->fetchh, code);
 
/* content type */
if (fetch_about_send_header(ctx, "Content-Type: text/html"))
goto fetch_about_imagecache_handler_aborted;
 
msg.type = FETCH_DATA;
msg.data.header_or_data.buf = (const uint8_t *) buffer;
 
/* page head */
slen = snprintf(buffer, sizeof buffer,
"<html>\n<head>\n"
"<title>NetSurf Browser Image Cache Status</title>\n"
"<link rel=\"stylesheet\" type=\"text/css\" "
"href=\"resource:internal.css\">\n"
"</head>\n"
"<body id =\"cachelist\">\n"
"<p class=\"banner\">"
"<a href=\"http://www.netsurf-browser.org/\">"
"<img src=\"resource:netsurf.png\" alt=\"NetSurf\"></a>"
"</p>\n"
"<h1>NetSurf Browser Image Cache Status</h1>\n" );
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_imagecache_handler_aborted;
 
/* image cache summary */
slen = image_cache_snsummaryf(buffer, sizeof(buffer),
"<p>Configured limit of %a hysteresis of %b</p>\n"
"<p>Total bitmap size in use %c (in %d)</p>\n"
"<p>Age %es</p>\n"
"<p>Peak size %f (in %g)</p>\n"
"<p>Peak image count %h (size %i)</p>\n"
"<p>Cache total/hit/miss/fail (counts) %j/%k/%l/%m "
"(%pj%%/%pk%%/%pl%%/%pm%%)</p>\n"
"<p>Cache total/hit/miss/fail (size) %n/%o/%q/%r "
"(%pn%%/%po%%/%pq%%/%pr%%)</p>\n"
"<p>Total images never rendered: %s "
"(includes %t that were converted)</p>\n"
"<p>Total number of excessive conversions: %u "
"(from %v images converted more than once)"
"</p>\n"
"<p>Bitmap of size %w had most (%x) conversions</p>\n"
"<h2>Current image cache contents</h2>\n");
if (slen >= (int) (sizeof(buffer)))
goto fetch_about_imagecache_handler_aborted; /* overflow */
 
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_imagecache_handler_aborted;
 
 
/* image cache entry table */
slen = snprintf(buffer, sizeof buffer,
"<p class=\"imagecachelist\">\n"
"<strong>"
"<span>Entry</span>"
"<span>Content Key</span>"
"<span>Redraw Count</span>"
"<span>Conversion Count</span>"
"<span>Last Redraw</span>"
"<span>Bitmap Age</span>"
"<span>Bitmap Size</span>"
"<span>Source</span>"
"</strong>\n");
do {
res = image_cache_snentryf(buffer + slen, sizeof buffer - slen,
cent_loop,
"<a href=\"%U\">"
"<span>%e</span>"
"<span>%k</span>"
"<span>%r</span>"
"<span>%c</span>"
"<span>%a</span>"
"<span>%g</span>"
"<span>%s</span>"
"<span>%o</span>"
"</a>\n");
if (res <= 0)
break; /* last option */
 
if (res >= (int) (sizeof buffer - slen)) {
/* last entry would not fit in buffer, submit buffer */
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_imagecache_handler_aborted;
slen = 0;
} else {
/* normal addition */
slen += res;
cent_loop++;
}
} while (res > 0);
 
slen += snprintf(buffer + slen, sizeof buffer - slen,
"</p>\n</body>\n</html>\n");
 
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_imagecache_handler_aborted;
 
msg.type = FETCH_FINISHED;
fetch_about_send_callback(&msg, ctx);
 
return true;
 
fetch_about_imagecache_handler_aborted:
return false;
}
 
/** Handler to generate about:config page */
static bool fetch_about_config_handler(struct fetch_about_context *ctx)
{
fetch_msg msg;
char buffer[1024];
int code = 200;
int slen;
unsigned int opt_loop = 0;
int res = 0;
 
/* content is going to return ok */
fetch_set_http_code(ctx->fetchh, code);
 
/* content type */
if (fetch_about_send_header(ctx, "Content-Type: text/html"))
goto fetch_about_config_handler_aborted;
 
msg.type = FETCH_DATA;
msg.data.header_or_data.buf = (const uint8_t *) buffer;
 
slen = snprintf(buffer, sizeof buffer,
"<html>\n<head>\n"
"<title>NetSurf Browser Config</title>\n"
"<link rel=\"stylesheet\" type=\"text/css\" "
"href=\"resource:internal.css\">\n"
"</head>\n"
"<body id =\"configlist\">\n"
"<p class=\"banner\">"
"<a href=\"http://www.netsurf-browser.org/\">"
"<img src=\"resource:netsurf.png\" alt=\"NetSurf\"></a>"
"</p>\n"
"<h1>NetSurf Browser Config</h1>\n"
"<table class=\"config\">\n"
"<tr><th></th><th></th><th></th></tr>\n");
 
do {
res = nsoption_snoptionf(buffer + slen, sizeof buffer - slen,
opt_loop,
"<tr><th>%k</th><td>%t</td><td>%V</td></tr>\n");
if (res <= 0)
break; /* last option */
 
if (res >= (int) (sizeof buffer - slen)) {
/* last entry would not fit in buffer, submit buffer */
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_config_handler_aborted;
slen = 0;
} else {
/* normal addition */
slen += res;
opt_loop++;
}
} while (res > 0);
 
slen += snprintf(buffer + slen, sizeof buffer - slen,
"</table>\n</body>\n</html>\n");
 
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_config_handler_aborted;
 
msg.type = FETCH_FINISHED;
fetch_about_send_callback(&msg, ctx);
 
return true;
 
fetch_about_config_handler_aborted:
return false;
}
 
 
/** Generate the text of a Choices file which represents the current
* in use options.
*/
static bool fetch_about_choices_handler(struct fetch_about_context *ctx)
{
fetch_msg msg;
char buffer[1024];
int code = 200;
int slen;
unsigned int opt_loop = 0;
int res = 0;
 
/* content is going to return ok */
fetch_set_http_code(ctx->fetchh, code);
 
/* content type */
if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
goto fetch_about_choices_handler_aborted;
 
msg.type = FETCH_DATA;
msg.data.header_or_data.buf = (const uint8_t *) buffer;
 
slen = snprintf(buffer, sizeof buffer,
"# Automatically generated current NetSurf browser Choices\n");
 
do {
res = nsoption_snoptionf(buffer + slen,
sizeof buffer - slen,
opt_loop,
"%k:%v\n");
if (res <= 0)
break; /* last option */
 
if (res >= (int) (sizeof buffer - slen)) {
/* last entry would not fit in buffer, submit buffer */
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_choices_handler_aborted;
slen = 0;
} else {
/* normal addition */
slen += res;
opt_loop++;
}
} while (res > 0);
 
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_choices_handler_aborted;
 
msg.type = FETCH_FINISHED;
fetch_about_send_callback(&msg, ctx);
 
return true;
 
fetch_about_choices_handler_aborted:
return false;
}
 
/** Generate the text of an svn testament which represents the current
* build-tree status
*/
typedef struct { const char *leaf; const char *modtype; } modification_t;
static bool fetch_about_testament_handler(struct fetch_about_context *ctx)
{
static modification_t modifications[] = WT_MODIFICATIONS;
fetch_msg msg;
char buffer[1024];
int code = 200;
int slen;
int i;
 
/* content is going to return ok */
fetch_set_http_code(ctx->fetchh, code);
 
/* content type */
if (fetch_about_send_header(ctx, "Content-Type: text/plain"))
goto fetch_about_testament_handler_aborted;
 
msg.type = FETCH_DATA;
msg.data.header_or_data.buf = (const uint8_t *) buffer;
 
slen = snprintf(buffer, sizeof buffer,
"# Automatically generated by NetSurf build system\n\n");
 
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_testament_handler_aborted;
slen = snprintf(buffer, sizeof buffer,
#if defined(WT_BRANCHISTRUNK) || defined(WT_BRANCHISMASTER)
"# This is a *DEVELOPMENT* build from the main line.\n\n"
#elif defined(WT_BRANCHISTAG) && (WT_MODIFIED == 0)
"# This is a tagged build of NetSurf\n"
#ifdef WT_TAGIS
"# The tag used was '" WT_TAGIS "'\n\n"
#else
"\n"
#endif
#elif defined(WT_NO_SVN) || defined(WT_NO_GIT)
"# This NetSurf was built outside of our revision "
"control environment.\n"
"# This testament is therefore very useful.\n\n"
#else
"# This NetSurf was built from a branch (" WT_BRANCHPATH ").\n\n"
#endif
#if defined(CI_BUILD)
"# This build carries the CI build number '" CI_BUILD "'\n\n"
#endif
);
 
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_testament_handler_aborted;
 
slen = snprintf(buffer, sizeof buffer,
"Built by %s (%s) from %s at revision %s\n\n",
GECOS, USERNAME, WT_BRANCHPATH, WT_REVID);
 
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_testament_handler_aborted;
slen = snprintf(buffer, sizeof buffer,
"Built on %s in %s\n\n",
WT_HOSTNAME, WT_ROOT);
 
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_testament_handler_aborted;
if (WT_MODIFIED > 0) {
slen = snprintf(buffer, sizeof buffer,
"Working tree has %d modification%s\n\n",
WT_MODIFIED, WT_MODIFIED == 1 ? "" : "s");
} else {
slen = snprintf(buffer, sizeof buffer,
"Working tree is not modified.\n");
}
 
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_testament_handler_aborted;
for (i = 0; i < WT_MODIFIED; ++i) {
slen = snprintf(buffer, sizeof buffer,
" %s %s\n",
modifications[i].modtype,
modifications[i].leaf);
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_testament_handler_aborted;
}
 
msg.type = FETCH_FINISHED;
fetch_about_send_callback(&msg, ctx);
 
return true;
 
fetch_about_testament_handler_aborted:
return false;
}
 
static bool fetch_about_logo_handler(struct fetch_about_context *ctx)
{
fetch_msg msg;
 
/* content is going to return redirect */
fetch_set_http_code(ctx->fetchh, 302);
 
msg.type = FETCH_REDIRECT;
msg.data.redirect = "resource:netsurf.png";
 
fetch_about_send_callback(&msg, ctx);
 
return true;
}
 
static bool fetch_about_welcome_handler(struct fetch_about_context *ctx)
{
fetch_msg msg;
 
/* content is going to return redirect */
fetch_set_http_code(ctx->fetchh, 302);
 
msg.type = FETCH_REDIRECT;
msg.data.redirect = "resource:welcome.html";
 
fetch_about_send_callback(&msg, ctx);
 
return true;
}
 
/* Forward declaration because this handler requires the handler table. */
static bool fetch_about_about_handler(struct fetch_about_context *ctx);
 
struct about_handlers {
const char *name; /**< name to match in url */
int name_len;
lwc_string *lname; /**< Interned name */
fetch_about_handler handler; /* handler for the url */
bool hidden; /* Flag indicating if entry should show in listing */
};
 
/** List of about paths and their handlers */
struct about_handlers about_handler_list[] = {
{ "credits", SLEN("credits"), NULL,
fetch_about_credits_handler, false },
{ "licence", SLEN("licence"), NULL,
fetch_about_licence_handler, false },
{ "license", SLEN("license"), NULL,
fetch_about_licence_handler, true },
{ "welcome", SLEN("welcome"), NULL,
fetch_about_welcome_handler, false },
{ "config", SLEN("config"), NULL,
fetch_about_config_handler, false },
{ "Choices", SLEN("Choices"), NULL,
fetch_about_choices_handler, false },
{ "testament", SLEN("testament"), NULL,
fetch_about_testament_handler, false },
{ "about", SLEN("about"), NULL,
fetch_about_about_handler, true },
{ "logo", SLEN("logo"), NULL,
fetch_about_logo_handler, true },
/* details about the image cache */
{ "imagecache", SLEN("imagecache"), NULL,
fetch_about_imagecache_handler, true },
/* The default blank page */
{ "blank", SLEN("blank"), NULL,
fetch_about_blank_handler, true }
};
 
#define about_handler_list_len (sizeof(about_handler_list) / \
sizeof(struct about_handlers))
 
/**
* List all the valid about: paths available
*
* \param ctx The fetch context.
* \return true for sucess or false to generate an error.
*/
static bool fetch_about_about_handler(struct fetch_about_context *ctx)
{
fetch_msg msg;
char buffer[1024];
int code = 200;
int slen;
unsigned int abt_loop = 0;
int res = 0;
 
/* content is going to return ok */
fetch_set_http_code(ctx->fetchh, code);
 
/* content type */
if (fetch_about_send_header(ctx, "Content-Type: text/html"))
goto fetch_about_config_handler_aborted;
 
msg.type = FETCH_DATA;
msg.data.header_or_data.buf = (const uint8_t *) buffer;
 
slen = snprintf(buffer, sizeof buffer,
"<html>\n<head>\n"
"<title>NetSurf List of About pages</title>\n"
"<link rel=\"stylesheet\" type=\"text/css\" "
"href=\"resource:internal.css\">\n"
"</head>\n"
"<body id =\"aboutlist\">\n"
"<p class=\"banner\">"
"<a href=\"http://www.netsurf-browser.org/\">"
"<img src=\"resource:netsurf.png\" alt=\"NetSurf\"></a>"
"</p>\n"
"<h1>NetSurf List of About pages</h1>\n"
"<ul>\n");
 
for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
 
/* Skip over hidden entries */
if (about_handler_list[abt_loop].hidden)
continue;
 
res = snprintf(buffer + slen, sizeof buffer - slen,
"<li><a href=\"about:%s\">about:%s</a></li>\n",
about_handler_list[abt_loop].name,
about_handler_list[abt_loop].name);
if (res <= 0)
break; /* last option */
 
if (res >= (int)(sizeof buffer - slen)) {
/* last entry would not fit in buffer, submit buffer */
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_config_handler_aborted;
slen = 0;
} else {
/* normal addition */
slen += res;
}
}
 
slen += snprintf(buffer + slen, sizeof buffer - slen,
"</ul>\n</body>\n</html>\n");
 
msg.data.header_or_data.len = slen;
if (fetch_about_send_callback(&msg, ctx))
goto fetch_about_config_handler_aborted;
 
msg.type = FETCH_FINISHED;
fetch_about_send_callback(&msg, ctx);
 
return true;
 
fetch_about_config_handler_aborted:
return false;
}
 
 
/** callback to initialise the about fetcher. */
static bool fetch_about_initialise(lwc_string *scheme)
{
unsigned int abt_loop = 0;
lwc_error error;
 
for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
error = lwc_intern_string(about_handler_list[abt_loop].name,
about_handler_list[abt_loop].name_len,
&about_handler_list[abt_loop].lname);
if (error != lwc_error_ok) {
while (abt_loop-- != 0) {
lwc_string_unref(about_handler_list[abt_loop].lname);
}
return false;
}
}
 
return true;
}
 
/** callback to finalise the about fetcher. */
static void fetch_about_finalise(lwc_string *scheme)
{
unsigned int abt_loop = 0;
for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) {
lwc_string_unref(about_handler_list[abt_loop].lname);
}
}
 
static bool fetch_about_can_fetch(const nsurl *url)
{
return true;
}
 
/** callback to set up a about fetch context. */
static void *
fetch_about_setup(struct fetch *fetchh,
nsurl *url,
bool only_2xx,
bool downgrade_tls,
const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
const char **headers)
{
struct fetch_about_context *ctx;
unsigned int handler_loop;
lwc_string *path;
bool match;
 
ctx = calloc(1, sizeof(*ctx));
if (ctx == NULL)
return NULL;
 
path = nsurl_get_component(url, NSURL_PATH);
 
for (handler_loop = 0;
handler_loop < about_handler_list_len;
handler_loop++) {
ctx->handler = about_handler_list[handler_loop].handler;
if (lwc_string_isequal(path,
about_handler_list[handler_loop].lname,
&match) == lwc_error_ok && match) {
break;
}
}
 
if (path != NULL)
lwc_string_unref(path);
 
ctx->fetchh = fetchh;
ctx->url = nsurl_ref(url);
 
RING_INSERT(ring, ctx);
 
return ctx;
}
 
/** callback to free a about fetch */
static void fetch_about_free(void *ctx)
{
struct fetch_about_context *c = ctx;
nsurl_unref(c->url);
RING_REMOVE(ring, c);
free(ctx);
}
 
/** callback to start a about fetch */
static bool fetch_about_start(void *ctx)
{
return true;
}
 
/** callback to abort a about fetch */
static void fetch_about_abort(void *ctx)
{
struct fetch_about_context *c = ctx;
 
/* To avoid the poll loop having to deal with the fetch context
* disappearing from under it, we simply flag the abort here.
* The poll loop itself will perform the appropriate cleanup.
*/
c->aborted = true;
}
 
 
/** callback to poll for additional about fetch contents */
static void fetch_about_poll(lwc_string *scheme)
{
struct fetch_about_context *c, *next;
 
if (ring == NULL) return;
 
/* Iterate over ring, processing each pending fetch */
c = ring;
do {
/* Ignore fetches that have been flagged as locked.
* This allows safe re-entrant calls to this function.
* Re-entrancy can occur if, as a result of a callback,
* the interested party causes fetch_poll() to be called
* again.
*/
if (c->locked == true) {
next = c->r_next;
continue;
}
 
/* Only process non-aborted fetches */
if (c->aborted == false) {
/* about fetches can be processed in one go */
c->handler(c);
}
 
/* Compute next fetch item at the last possible moment
* as processing this item may have added to the ring
*/
next = c->r_next;
 
fetch_remove_from_queues(c->fetchh);
fetch_free(c->fetchh);
 
/* Advance to next ring entry, exiting if we've reached
* the start of the ring or the ring has become empty
*/
} while ( (c = next) != ring && ring != NULL);
}
 
void fetch_about_register(void)
{
lwc_string *scheme;
 
if (lwc_intern_string("about", SLEN("about"),
&scheme) != lwc_error_ok) {
die("Failed to initialise the fetch module "
"(couldn't intern \"about\").");
}
 
fetch_add_fetcher(scheme,
fetch_about_initialise,
fetch_about_can_fetch,
fetch_about_setup,
fetch_about_start,
fetch_about_abort,
fetch_about_free,
fetch_about_poll,
fetch_about_finalise);
}
/programs/network/netsurf/netsurf/content/fetchers/about.h
0,0 → 1,28
/*
* Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* about: URL method handler
*/
 
#ifndef NETSURF_CONTENT_FETCHERS_FETCH_ABOUT_H
#define NETSURF_CONTENT_FETCHERS_FETCH_ABOUT_H
 
void fetch_about_register(void);
 
#endif
/programs/network/netsurf/netsurf/content/fetchers/curl.c
0,0 → 1,509
/*
* Copyright 2006 Daniel Silverstone <dsilvers@digital-scurf.org>
* Copyright 2007 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
*
* This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Fetching of data from a URL (implementation).
*
* This implementation uses libcurl's 'multi' interface.
*
*
* The CURL handles are cached in the curl_handle_ring. There are at most
* ::max_cached_fetch_handles in this ring.
*/
 
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <sys/stat.h>
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/config.h"
//#include <openssl/ssl.h>
#include "content/fetch.h"
#include "content/fetchers/curl.h"
#include "content/urldb.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/schedule.h"
#include "utils/utils.h"
#include "utils/ring.h"
#include "utils/useragent.h"
 
/* BIG FAT WARNING: This is here because curl doesn't give you an FD to
* poll on, until it has processed a bit of the handle. So we need schedules
* in order to make this work.
*/
#include <desktop/browser.h>
 
/* uncomment this to use scheduler based calling
#define FETCHER_CURLL_SCHEDULED 1
*/
 
typedef int X509_STORE_CTX;
typedef int X509;
#define CURL_ERROR_SIZE 0
typedef int CURLcode;
typedef int curl_infotype;
/** SSL certificate info */
struct cert_info {
X509 *cert; /**< Pointer to certificate */
long err; /**< OpenSSL error code */
};
 
/** Information for a single fetch. */
struct curl_fetch_info {
struct fetch *fetch_handle; /**< The fetch handle we're parented by. */
CURL * curl_handle; /**< cURL handle if being fetched, or 0. */
bool had_headers; /**< Headers have been processed. */
bool abort; /**< Abort requested. */
bool stopped; /**< Download stopped on purpose. */
bool only_2xx; /**< Only HTTP 2xx responses acceptable. */
bool downgrade_tls; /**< Downgrade to TLS <= 1.0 */
nsurl *url; /**< URL of this fetch. */
lwc_string *host; /**< The hostname of this fetch. */
struct curl_slist *headers; /**< List of request headers. */
char *location; /**< Response Location header, or 0. */
unsigned long content_length; /**< Response Content-Length, or 0. */
char *cookie_string; /**< Cookie string for this fetch */
char *realm; /**< HTTP Auth Realm */
char *post_urlenc; /**< Url encoded POST string, or 0. */
long http_code; /**< HTTP result code from cURL. */
struct curl_httppost *post_multipart; /**< Multipart post data, or 0. */
#define MAX_CERTS 10
struct cert_info cert_data[MAX_CERTS]; /**< HTTPS certificate data */
unsigned int last_progress_update; /**< Time of last progress update */
};
 
struct cache_handle {
CURL *handle; /**< The cached cURL handle */
lwc_string *host; /**< The host for which this handle is cached */
 
struct cache_handle *r_prev; /**< Previous cached handle in ring. */
struct cache_handle *r_next; /**< Next cached handle in ring. */
};
 
CURLM *fetch_curl_multi; /**< Global cURL multi handle. */
/** Curl handle with default options set; not used for transfers. */
static CURL *fetch_blank_curl;
static struct cache_handle *curl_handle_ring = 0; /**< Ring of cached handles */
static int curl_fetchers_registered = 0;
static bool curl_with_openssl;
 
static char fetch_error_buffer[CURL_ERROR_SIZE]; /**< Error buffer for cURL. */
static char fetch_proxy_userpwd[100]; /**< Proxy authentication details. */
 
static bool fetch_curl_initialise(lwc_string *scheme);
static void fetch_curl_finalise(lwc_string *scheme);
static bool fetch_curl_can_fetch(const nsurl *url);
static void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url,
bool only_2xx, bool downgrade_tls, const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
const char **headers);
static bool fetch_curl_start(void *vfetch);
static bool fetch_curl_initiate_fetch(struct curl_fetch_info *fetch,
CURL *handle);
static CURL *fetch_curl_get_handle(lwc_string *host);
static void fetch_curl_cache_handle(CURL *handle, lwc_string *host);
static CURLcode fetch_curl_set_options(struct curl_fetch_info *f);
static CURLcode fetch_curl_sslctxfun(CURL *curl_handle, void *_sslctx,
void *p);
static void fetch_curl_abort(void *vf);
static void fetch_curl_stop(struct curl_fetch_info *f);
static void fetch_curl_free(void *f);
static void fetch_curl_poll(lwc_string *scheme_ignored);
static void fetch_curl_done(CURL *curl_handle, CURLcode result);
static int fetch_curl_progress(void *clientp, double dltotal, double dlnow,
double ultotal, double ulnow);
static int fetch_curl_ignore_debug(CURL *handle,
curl_infotype type,
char *data,
size_t size,
void *userptr);
static size_t fetch_curl_data(char *data, size_t size, size_t nmemb,
void *_f);
static size_t fetch_curl_header(char *data, size_t size, size_t nmemb,
void *_f);
static bool fetch_curl_process_headers(struct curl_fetch_info *f);
static struct curl_httppost *fetch_curl_post_convert(
const struct fetch_multipart_data *control);
static int fetch_curl_verify_callback(int preverify_ok,
X509_STORE_CTX *x509_ctx);
static int fetch_curl_cert_verify_callback(X509_STORE_CTX *x509_ctx,
void *parm);
 
 
/**
* Initialise the fetcher.
*
* Must be called once before any other function.
*/
 
void fetch_curl_register(void)
{
 
lwc_string *scheme;
 
 
LOG(("curl register\n"));
 
lwc_intern_string("http", SLEN("http"), &scheme);
 
if (!fetch_add_fetcher(scheme,
fetch_curl_initialise,
fetch_curl_can_fetch,
fetch_curl_setup,
fetch_curl_start,
fetch_curl_abort,
fetch_curl_free,
#ifdef FETCHER_CURLL_SCHEDULED
NULL,
#else
fetch_curl_poll,
#endif
fetch_curl_finalise)) {
LOG(("Unable to register cURL fetcher for HTTP"));
}
lwc_intern_string("https", SLEN("https"), &scheme);
 
if (!fetch_add_fetcher(scheme,
fetch_curl_initialise,
fetch_curl_can_fetch,
fetch_curl_setup,
fetch_curl_start,
fetch_curl_abort,
fetch_curl_free,
#ifdef FETCHER_CURLL_SCHEDULED
NULL,
#else
fetch_curl_poll,
#endif
fetch_curl_finalise)) {
LOG(("Unable to register cURL fetcher for HTTPS"));
}
 
}
 
 
/**
* Initialise a cURL fetcher.
*/
 
bool fetch_curl_initialise(lwc_string *scheme)
{
 
LOG(("curl initi lwc\n"));
return true; /* Always succeeds */
}
 
 
/**
* Finalise a cURL fetcher
*/
 
void fetch_curl_finalise(lwc_string *scheme)
{
LOG(("curl finali\n"));
}
 
bool fetch_curl_can_fetch(const nsurl *url)
{
LOG(("curl can fetch\n"));
return false;
}
 
/**
* Start fetching data for the given URL.
*
* The function returns immediately. The fetch may be queued for later
* processing.
*
* A pointer to an opaque struct curl_fetch_info is returned, which can be
* passed to fetch_abort() to abort the fetch at any time. Returns 0 if memory
* is exhausted (or some other fatal error occurred).
*
* The caller must supply a callback function which is called when anything
* interesting happens. The callback function is first called with msg
* FETCH_HEADER, with the header in data, then one or more times
* with FETCH_DATA with some data for the url, and finally with
* FETCH_FINISHED. Alternatively, FETCH_ERROR indicates an error occurred:
* data contains an error message. FETCH_REDIRECT may replace the FETCH_HEADER,
* FETCH_DATA, FETCH_FINISHED sequence if the server sends a replacement URL.
*
* Some private data can be passed as the last parameter to fetch_start, and
* callbacks will contain this.
*/
 
void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url,
bool only_2xx, bool downgrade_tls, const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
const char **headers)
{
LOG(("curl setup\n"));
 
return;
}
 
 
/**
* Dispatch a single job
*/
bool fetch_curl_start(void *vfetch)
{
LOG(("curl start\n"));
return 0;
}
 
 
/**
* Initiate a fetch from the queue.
*
* Called with a fetch structure and a CURL handle to be used to fetch the
* content.
*
* This will return whether or not the fetch was successfully initiated.
*/
 
bool fetch_curl_initiate_fetch(struct curl_fetch_info *fetch, CURL *handle)
{
LOG(("curl initi fetch\n"));
return 0;
}
 
 
/**
* Find a CURL handle to use to dispatch a job
*/
 
CURL *fetch_curl_get_handle(lwc_string *host)
{
LOG(("curl get handle\n"));
return 0;
}
 
 
/**
* Cache a CURL handle for the provided host (if wanted)
*/
 
void fetch_curl_cache_handle(CURL *handle, lwc_string *host)
{
LOG(("curl cache handle\n"));
}
 
 
/**
* Set options specific for a fetch.
*/
 
typedef int CURLcode;
 
CURLcode
fetch_curl_set_options(struct curl_fetch_info *f)
{
LOG(("curl set options\n"));
return -1;
}
 
 
/**
* cURL SSL setup callback
*/
 
CURLcode
fetch_curl_sslctxfun(CURL *curl_handle, void *_sslctx, void *parm)
{
LOG(("curlcodessl\n"));
return -1;
}
 
 
/**
* Abort a fetch.
*/
 
void fetch_curl_abort(void *vf)
{
LOG(("curl abort\n"));
}
 
 
/**
* Clean up the provided fetch object and free it.
*
* Will prod the queue afterwards to allow pending requests to be initiated.
*/
 
void fetch_curl_stop(struct curl_fetch_info *f)
{
LOG(("curl stop\n"));
}
 
 
/**
* Free a fetch structure and associated resources.
*/
 
void fetch_curl_free(void *vf)
{
LOG(("curl free\n"));
}
 
 
/**
* Do some work on current fetches.
*
* Must be called regularly to make progress on fetches.
*/
 
void fetch_curl_poll(lwc_string *scheme_ignored)
{
LOG(("curl poll\n"));
}
 
 
/**
* Handle a completed fetch (CURLMSG_DONE from curl_multi_info_read()).
*
* \param curl_handle curl easy handle of fetch
*/
 
void fetch_curl_done(CURL *curl_handle, CURLcode result)
{
LOG(("curl done\n"));
}
 
 
/**
* Callback function for fetch progress.
*/
 
int fetch_curl_progress(void *clientp, double dltotal, double dlnow,
double ultotal, double ulnow)
{
LOG(("curl progress\n"));
return 0;
}
 
 
 
/**
* Ignore everything given to it.
*
* Used to ignore cURL debug.
*/
 
int fetch_curl_ignore_debug(CURL *handle,
curl_infotype type,
char *data,
size_t size,
void *userptr)
{
LOG(("curl igdebug\n"));
return 0;
}
 
 
/**
* Callback function for cURL.
*/
 
size_t fetch_curl_data(char *data, size_t size, size_t nmemb,
void *_f)
{
LOG(("curl callback\n"));
return 0;
}
 
 
/**
* Callback function for headers.
*
* See RFC 2616 4.2.
*/
 
size_t fetch_curl_header(char *data, size_t size, size_t nmemb,
void *_f)
{
LOG(("curl header\n"));
return 0;
}
 
/**
* Find the status code and content type and inform the caller.
*
* Return true if the fetch is being aborted.
*/
 
bool fetch_curl_process_headers(struct curl_fetch_info *f)
{
LOG(("curl proc head\n"));
return false;
}
 
 
/**
* Convert a list of struct ::fetch_multipart_data to a list of
* struct curl_httppost for libcurl.
*/
struct curl_httppost *
fetch_curl_post_convert(const struct fetch_multipart_data *control)
{
struct curl_httppost *post = 0;
LOG(("curl post - FAIL\n"));
return post;
}
 
 
/**
* OpenSSL Certificate verification callback
* Stores certificate details in fetch struct.
*/
 
int fetch_curl_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
LOG(("curl verify\n"));
return 0;
}
 
 
/**
* OpenSSL certificate chain verification callback
* Verifies certificate chain, setting up context for fetch_curl_verify_callback
*/
 
int fetch_curl_cert_verify_callback(X509_STORE_CTX *x509_ctx, void *parm)
{
 
LOG(("curl cert verify\n"));
return 0;
}
/programs/network/netsurf/netsurf/content/fetchers/curl.h
0,0 → 1,33
/*
* Copyright 2007 Daniel Silverstone <dsilvers@digital-scurf.org>
*
* This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Fetching of data from a URL (Registration).
*/
 
#ifndef NETSURF_CONTENT_FETCHERS_FETCH_CURL_H
#define NETSURF_CONTENT_FETCHERS_FETCH_CURL_H
 
#include <curl/curl.h>
 
void fetch_curl_register(void);
 
/** Global cURL multi handle. */
extern CURLM *fetch_curl_multi;
 
#endif
/programs/network/netsurf/netsurf/content/fetchers/data.c
0,0 → 1,345
/*
* Copyright 2008 Rob Kendrick <rjek@netsurf-browser.org>
*
* This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/* data: URL handling. See http://tools.ietf.org/html/rfc2397 */
 
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include <time.h>
 
#include <curl/curl.h> /* for URL unescaping functions */
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/config.h"
#include "content/fetch.h"
#include "content/fetchers/data.h"
#include "content/urldb.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/utils.h"
#include "utils/ring.h"
#include "utils/base64.h"
 
struct fetch_data_context {
struct fetch *parent_fetch;
char *url;
char *mimetype;
char *data;
size_t datalen;
bool base64;
 
bool aborted;
bool locked;
struct fetch_data_context *r_next, *r_prev;
};
 
static struct fetch_data_context *ring = NULL;
 
static CURL *curl;
 
static bool fetch_data_initialise(lwc_string *scheme)
{
LOG(("fetch_data_initialise called for %s", lwc_string_data(scheme)));
if ( (curl = curl_easy_init()) == NULL)
return false;
else
return true;
}
 
static void fetch_data_finalise(lwc_string *scheme)
{
LOG(("fetch_data_finalise called for %s", lwc_string_data(scheme)));
curl_easy_cleanup(curl);
}
 
static bool fetch_data_can_fetch(const nsurl *url)
{
return true;
}
 
static void *fetch_data_setup(struct fetch *parent_fetch, nsurl *url,
bool only_2xx, bool downgrade_tls, const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
const char **headers)
{
struct fetch_data_context *ctx = calloc(1, sizeof(*ctx));
if (ctx == NULL)
return NULL;
ctx->parent_fetch = parent_fetch;
 
/* TODO: keep as nsurl to avoid copy */
ctx->url = malloc(nsurl_length(url) + 1);
if (ctx->url == NULL) {
free(ctx);
return NULL;
}
memcpy(ctx->url, nsurl_access(url), nsurl_length(url) + 1);
 
RING_INSERT(ring, ctx);
return ctx;
}
 
static bool fetch_data_start(void *ctx)
{
return true;
}
 
static void fetch_data_free(void *ctx)
{
struct fetch_data_context *c = ctx;
 
free(c->url);
free(c->data);
free(c->mimetype);
RING_REMOVE(ring, c);
free(ctx);
}
 
static void fetch_data_abort(void *ctx)
{
struct fetch_data_context *c = ctx;
 
/* To avoid the poll loop having to deal with the fetch context
* disappearing from under it, we simply flag the abort here.
* The poll loop itself will perform the appropriate cleanup.
*/
c->aborted = true;
}
 
static void fetch_data_send_callback(const fetch_msg *msg,
struct fetch_data_context *c)
{
c->locked = true;
fetch_send_callback(msg, c->parent_fetch);
c->locked = false;
}
 
static bool fetch_data_process(struct fetch_data_context *c)
{
fetch_msg msg;
char *params;
char *comma;
char *unescaped;
int templen;
/* format of a data: URL is:
* data:[<mimetype>][;base64],<data>
* The mimetype is optional. If it is missing, the , before the
* data must still be there.
*/
LOG(("url: %.140s", c->url));
if (strlen(c->url) < 6) {
/* 6 is the minimum possible length (data:,) */
msg.type = FETCH_ERROR;
msg.data.error = "Malformed data: URL";
fetch_data_send_callback(&msg, c);
return false;
}
/* skip the data: part */
params = c->url + SLEN("data:");
/* find the comma */
if ( (comma = strchr(params, ',')) == NULL) {
msg.type = FETCH_ERROR;
msg.data.error = "Malformed data: URL";
fetch_data_send_callback(&msg, c);
return false;
}
if (params[0] == ',') {
/* there is no mimetype here, assume text/plain */
c->mimetype = strdup("text/plain;charset=US-ASCII");
} else {
/* make a copy of everything between data: and the comma */
c->mimetype = strndup(params, comma - params);
}
if (c->mimetype == NULL) {
msg.type = FETCH_ERROR;
msg.data.error =
"Unable to allocate memory for mimetype in data: URL";
fetch_data_send_callback(&msg, c);
return false;
}
if (strcmp(c->mimetype + strlen(c->mimetype) - 7, ";base64") == 0) {
c->base64 = true;
c->mimetype[strlen(c->mimetype) - 7] = '\0';
} else {
c->base64 = false;
}
/* we URL unescape the data first, just incase some insane page
* decides to nest URL and base64 encoding. Like, say, Acid2.
*/
templen = c->datalen;
unescaped = curl_easy_unescape(curl, comma + 1, 0, &templen);
c->datalen = templen;
if (unescaped == NULL) {
msg.type = FETCH_ERROR;
msg.data.error = "Unable to URL decode data: URL";
fetch_data_send_callback(&msg, c);
return false;
}
if (c->base64) {
c->data = malloc(c->datalen); /* safe: always gets smaller */
if (base64_decode(unescaped, c->datalen, c->data,
&(c->datalen)) == false) {
msg.type = FETCH_ERROR;
msg.data.error = "Unable to Base64 decode data: URL";
fetch_data_send_callback(&msg, c);
curl_free(unescaped);
return false;
}
} else {
c->data = malloc(c->datalen);
if (c->data == NULL) {
msg.type = FETCH_ERROR;
msg.data.error =
"Unable to allocate memory for data: URL";
fetch_data_send_callback(&msg, c);
curl_free(unescaped);
return false;
}
memcpy(c->data, unescaped, c->datalen);
}
curl_free(unescaped);
return true;
}
 
static void fetch_data_poll(lwc_string *scheme)
{
fetch_msg msg;
struct fetch_data_context *c, *next;
if (ring == NULL) return;
/* Iterate over ring, processing each pending fetch */
c = ring;
do {
/* Ignore fetches that have been flagged as locked.
* This allows safe re-entrant calls to this function.
* Re-entrancy can occur if, as a result of a callback,
* the interested party causes fetch_poll() to be called
* again.
*/
if (c->locked == true) {
next = c->r_next;
continue;
}
 
/* Only process non-aborted fetches */
if (c->aborted == false && fetch_data_process(c) == true) {
char header[64];
 
fetch_set_http_code(c->parent_fetch, 200);
LOG(("setting data: MIME type to %s, length to %zd",
c->mimetype, c->datalen));
/* Any callback can result in the fetch being aborted.
* Therefore, we _must_ check for this after _every_
* call to fetch_data_send_callback().
*/
snprintf(header, sizeof header, "Content-Type: %s",
c->mimetype);
msg.type = FETCH_HEADER;
msg.data.header_or_data.buf = (const uint8_t *) header;
msg.data.header_or_data.len = strlen(header);
fetch_data_send_callback(&msg, c);
 
if (c->aborted == false) {
snprintf(header, sizeof header,
"Content-Length: %"SSIZET_FMT,
c->datalen);
msg.type = FETCH_HEADER;
msg.data.header_or_data.buf =
(const uint8_t *) header;
msg.data.header_or_data.len = strlen(header);
fetch_data_send_callback(&msg, c);
}
 
if (c->aborted == false) {
msg.type = FETCH_DATA;
msg.data.header_or_data.buf =
(const uint8_t *) c->data;
msg.data.header_or_data.len = c->datalen;
fetch_data_send_callback(&msg, c);
}
 
if (c->aborted == false) {
msg.type = FETCH_FINISHED;
fetch_data_send_callback(&msg, c);
}
} else {
LOG(("Processing of %s failed!", c->url));
 
/* Ensure that we're unlocked here. If we aren't,
* then fetch_data_process() is broken.
*/
assert(c->locked == false);
}
 
/* Compute next fetch item at the last possible moment as
* processing this item may have added to the ring.
*/
next = c->r_next;
 
fetch_remove_from_queues(c->parent_fetch);
fetch_free(c->parent_fetch);
 
/* Advance to next ring entry, exiting if we've reached
* the start of the ring or the ring has become empty
*/
} while ( (c = next) != ring && ring != NULL);
}
 
void fetch_data_register(void)
{
lwc_string *scheme;
 
if (lwc_intern_string("data", SLEN("data"), &scheme) != lwc_error_ok) {
die("Failed to initialise the fetch module "
"(couldn't intern \"data\").");
}
 
fetch_add_fetcher(scheme,
fetch_data_initialise,
fetch_data_can_fetch,
fetch_data_setup,
fetch_data_start,
fetch_data_abort,
fetch_data_free,
fetch_data_poll,
fetch_data_finalise);
}
/programs/network/netsurf/netsurf/content/fetchers/data.h
0,0 → 1,28
/*
* Copyright 2008 Rob Kendrick <rjek@netsurf-browser.org>
*
* This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* data: URL method handler
*/
 
#ifndef NETSURF_CONTENT_FETCHERS_FETCH_DATA_H
#define NETSURF_CONTENT_FETCHERS_FETCH_DATA_H
 
void fetch_data_register(void);
 
#endif
/programs/network/netsurf/netsurf/content/fetchers/file.c
0,0 → 1,744
/*
* Copyright 2010 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/* file: URL handling. Based on the data fetcher by Rob Kendrick */
 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <inttypes.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <stdio.h>
#include <dirent.h>
#include <limits.h>
#include <stdarg.h>
 
#include "utils/config.h"
 
#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "content/dirlist.h"
#include "content/fetch.h"
#include "content/fetchers/file.h"
#include "content/urldb.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
#include "utils/errors.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/utils.h"
#include "utils/ring.h"
 
/* Maximum size of read buffer */
#define FETCH_FILE_MAX_BUF_SIZE (1024 * 1024)
 
/** Context for a fetch */
struct fetch_file_context {
struct fetch_file_context *r_next, *r_prev;
 
struct fetch *fetchh; /**< Handle for this fetch */
 
bool aborted; /**< Flag indicating fetch has been aborted */
bool locked; /**< Flag indicating entry is already entered */
 
nsurl *url; /**< The full url the fetch refers to */
char *path; /**< The actual path to be used with open() */
 
time_t file_etag; /**< Request etag for file (previous st.m_time) */
};
 
static struct fetch_file_context *ring = NULL;
 
/** issue fetch callbacks with locking */
static inline bool fetch_file_send_callback(const fetch_msg *msg,
struct fetch_file_context *ctx)
{
ctx->locked = true;
fetch_send_callback(msg, ctx->fetchh);
ctx->locked = false;
 
return ctx->aborted;
}
 
static bool fetch_file_send_header(struct fetch_file_context *ctx,
const char *fmt, ...)
{
fetch_msg msg;
char header[64];
va_list ap;
 
va_start(ap, fmt);
 
vsnprintf(header, sizeof header, fmt, ap);
 
va_end(ap);
 
msg.type = FETCH_HEADER;
msg.data.header_or_data.buf = (const uint8_t *) header;
msg.data.header_or_data.len = strlen(header);
fetch_file_send_callback(&msg, ctx);
 
return ctx->aborted;
}
 
/** callback to initialise the file fetcher. */
static bool fetch_file_initialise(lwc_string *scheme)
{
return true;
}
 
/** callback to initialise the file fetcher. */
static void fetch_file_finalise(lwc_string *scheme)
{
}
 
static bool fetch_file_can_fetch(const nsurl *url)
{
return true;
}
 
/** callback to set up a file fetch context. */
static void *
fetch_file_setup(struct fetch *fetchh,
nsurl *url,
bool only_2xx,
bool downgrade_tls,
const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
const char **headers)
{
struct fetch_file_context *ctx;
int i;
 
ctx = calloc(1, sizeof(*ctx));
if (ctx == NULL)
return NULL;
 
ctx->path = url_to_path(nsurl_access(url));
if (ctx->path == NULL) {
free(ctx);
return NULL;
}
 
ctx->url = nsurl_ref(url);
 
/* Scan request headers looking for If-None-Match */
for (i = 0; headers[i] != NULL; i++) {
if (strncasecmp(headers[i], "If-None-Match:",
SLEN("If-None-Match:")) == 0) {
/* If-None-Match: "12345678" */
const char *d = headers[i] + SLEN("If-None-Match:");
 
/* Scan to first digit, if any */
while (*d != '\0' && (*d < '0' || '9' < *d))
d++;
 
/* Convert to time_t */
if (*d != '\0')
ctx->file_etag = atoi(d);
}
}
 
ctx->fetchh = fetchh;
 
RING_INSERT(ring, ctx);
 
return ctx;
}
 
/** callback to free a file fetch */
static void fetch_file_free(void *ctx)
{
struct fetch_file_context *c = ctx;
nsurl_unref(c->url);
free(c->path);
RING_REMOVE(ring, c);
free(ctx);
}
 
/** callback to start a file fetch */
static bool fetch_file_start(void *ctx)
{
return true;
}
 
/** callback to abort a file fetch */
static void fetch_file_abort(void *ctx)
{
struct fetch_file_context *c = ctx;
 
/* To avoid the poll loop having to deal with the fetch context
* disappearing from under it, we simply flag the abort here.
* The poll loop itself will perform the appropriate cleanup.
*/
c->aborted = true;
}
 
static int fetch_file_errno_to_http_code(int error_no)
{
switch (error_no) {
case ENAMETOOLONG:
return 400;
case EACCES:
return 403;
case ENOENT:
return 404;
default:
break;
}
 
return 500;
}
 
static void fetch_file_process_error(struct fetch_file_context *ctx, int code)
{
fetch_msg msg;
char buffer[1024];
const char *title;
char key[8];
 
/* content is going to return error code */
fetch_set_http_code(ctx->fetchh, code);
 
/* content type */
if (fetch_file_send_header(ctx, "Content-Type: text/html"))
goto fetch_file_process_error_aborted;
 
snprintf(key, sizeof key, "HTTP%03d", code);
title = messages_get(key);
 
snprintf(buffer, sizeof buffer, "<html><head><title>%s</title></head>"
"<body><h1>%s</h1>"
"<p>Error %d while fetching file %s</p></body></html>",
title, title, code, nsurl_access(ctx->url));
 
msg.type = FETCH_DATA;
msg.data.header_or_data.buf = (const uint8_t *) buffer;
msg.data.header_or_data.len = strlen(buffer);
if (fetch_file_send_callback(&msg, ctx))
goto fetch_file_process_error_aborted;
 
msg.type = FETCH_FINISHED;
fetch_file_send_callback(&msg, ctx);
 
fetch_file_process_error_aborted:
return;
}
 
 
/** Process object as a regular file */
static void fetch_file_process_plain(struct fetch_file_context *ctx,
struct stat *fdstat)
{
#ifdef HAVE_MMAP
fetch_msg msg;
char *buf = NULL;
size_t buf_size;
 
int fd; /**< The file descriptor of the object */
 
/* Check if we can just return not modified */
if (ctx->file_etag != 0 && ctx->file_etag == fdstat->st_mtime) {
fetch_set_http_code(ctx->fetchh, 304);
msg.type = FETCH_NOTMODIFIED;
fetch_file_send_callback(&msg, ctx);
return;
}
 
fd = open(ctx->path, O_RDONLY);
if (fd < 0) {
/* process errors as appropriate */
fetch_file_process_error(ctx,
fetch_file_errno_to_http_code(errno));
return;
}
 
/* set buffer size */
buf_size = fdstat->st_size;
 
/* allocate the buffer storage */
if (buf_size > 0) {
buf = mmap(NULL, buf_size, PROT_READ, MAP_SHARED, fd, 0);
if (buf == MAP_FAILED) {
msg.type = FETCH_ERROR;
msg.data.error = "Unable to map memory for file data buffer";
fetch_file_send_callback(&msg, ctx);
close(fd);
return;
}
}
 
/* fetch is going to be successful */
fetch_set_http_code(ctx->fetchh, 200);
 
/* Any callback can result in the fetch being aborted.
* Therefore, we _must_ check for this after _every_ call to
* fetch_file_send_callback().
*/
 
/* content type */
if (fetch_file_send_header(ctx, "Content-Type: %s",
fetch_filetype(ctx->path)))
goto fetch_file_process_aborted;
 
/* content length */
if (fetch_file_send_header(ctx, "Content-Length: %"SSIZET_FMT, fdstat->st_size))
goto fetch_file_process_aborted;
 
/* create etag */
if (fetch_file_send_header(ctx, "ETag: \"%10" PRId64 "\"",
(int64_t) fdstat->st_mtime))
goto fetch_file_process_aborted;
 
 
msg.type = FETCH_DATA;
msg.data.header_or_data.buf = (const uint8_t *) buf;
msg.data.header_or_data.len = buf_size;
fetch_file_send_callback(&msg, ctx);
 
if (ctx->aborted == false) {
msg.type = FETCH_FINISHED;
fetch_file_send_callback(&msg, ctx);
}
 
fetch_file_process_aborted:
 
if (buf != NULL)
munmap(buf, buf_size);
close(fd);
#else
fetch_msg msg;
char *buf;
size_t buf_size;
 
ssize_t tot_read = 0;
ssize_t res;
 
FILE *infile;
 
/* Check if we can just return not modified */
if (ctx->file_etag != 0 && ctx->file_etag == fdstat->st_mtime) {
fetch_set_http_code(ctx->fetchh, 304);
msg.type = FETCH_NOTMODIFIED;
fetch_file_send_callback(&msg, ctx);
return;
}
 
infile = fopen(ctx->path, "rb");
if (infile == NULL) {
/* process errors as appropriate */
fetch_file_process_error(ctx,
fetch_file_errno_to_http_code(errno));
return;
}
 
/* set buffer size */
buf_size = fdstat->st_size;
if (buf_size > FETCH_FILE_MAX_BUF_SIZE)
buf_size = FETCH_FILE_MAX_BUF_SIZE;
 
/* allocate the buffer storage */
buf = malloc(buf_size);
if (buf == NULL) {
msg.type = FETCH_ERROR;
msg.data.error =
"Unable to allocate memory for file data buffer";
fetch_file_send_callback(&msg, ctx);
fclose(infile);
return;
}
 
/* fetch is going to be successful */
fetch_set_http_code(ctx->fetchh, 200);
 
/* Any callback can result in the fetch being aborted.
* Therefore, we _must_ check for this after _every_ call to
* fetch_file_send_callback().
*/
 
/* content type */
if (fetch_file_send_header(ctx, "Content-Type: %s",
fetch_filetype(ctx->path)))
goto fetch_file_process_aborted;
 
/* content length */
if (fetch_file_send_header(ctx, "Content-Length: %"SSIZET_FMT, fdstat->st_size))
goto fetch_file_process_aborted;
 
/* create etag */
if (fetch_file_send_header(ctx, "ETag: \"%10" PRId64 "\"",
(int64_t) fdstat->st_mtime))
goto fetch_file_process_aborted;
 
/* main data loop */
while (tot_read < fdstat->st_size) {
res = fread(buf, 1, buf_size, infile);
if (res == 0) {
if (feof(infile)) {
msg.type = FETCH_ERROR;
msg.data.error = "Unexpected EOF reading file";
fetch_file_send_callback(&msg, ctx);
goto fetch_file_process_aborted;
} else {
msg.type = FETCH_ERROR;
msg.data.error = "Error reading file";
fetch_file_send_callback(&msg, ctx);
goto fetch_file_process_aborted;
}
}
tot_read += res;
 
msg.type = FETCH_DATA;
msg.data.header_or_data.buf = (const uint8_t *) buf;
msg.data.header_or_data.len = res;
if (fetch_file_send_callback(&msg, ctx))
break;
}
 
if (ctx->aborted == false) {
msg.type = FETCH_FINISHED;
fetch_file_send_callback(&msg, ctx);
}
 
fetch_file_process_aborted:
 
fclose(infile);
free(buf);
#endif
return;
}
 
static char *gen_nice_title(char *path)
{
char *nice_path, *cnv, *tmp;
char *title;
int title_length;
 
/* Convert path for display */
nice_path = malloc(strlen(path) * SLEN("&amp;") + 1);
if (nice_path == NULL) {
return NULL;
}
 
/* Escape special HTML characters */
for (cnv = nice_path, tmp = path; *tmp != '\0'; tmp++) {
if (*tmp == '<') {
*cnv++ = '&';
*cnv++ = 'l';
*cnv++ = 't';
*cnv++ = ';';
} else if (*tmp == '>') {
*cnv++ = '&';
*cnv++ = 'g';
*cnv++ = 't';
*cnv++ = ';';
} else if (*tmp == '&') {
*cnv++ = '&';
*cnv++ = 'a';
*cnv++ = 'm';
*cnv++ = 'p';
*cnv++ = ';';
} else {
*cnv++ = *tmp;
}
}
*cnv = '\0';
 
/* Construct a localised title string */
title_length = (cnv - nice_path) + strlen(messages_get("FileIndex"));
title = malloc(title_length + 1);
 
if (title == NULL) {
free(nice_path);
return NULL;
}
 
/* Set title to localised "Index of <nice_path>" */
snprintf(title, title_length, messages_get("FileIndex"), nice_path);
 
free(nice_path);
 
return title;
}
 
 
static void fetch_file_process_dir(struct fetch_file_context *ctx,
struct stat *fdstat)
{
fetch_msg msg;
char buffer[1024]; /* Output buffer */
bool even = false; /* formatting flag */
char *title; /* pretty printed title */
nserror err; /* result from url routines */
nsurl *up; /* url of parent */
char *path; /* url for list entries */
 
DIR *scandir; /* handle for enumerating the directory */
struct dirent* ent; /* leaf directory entry */
struct stat ent_stat; /* stat result of leaf entry */
char datebuf[64]; /* buffer for date text */
char timebuf[64]; /* buffer for time text */
char urlpath[PATH_MAX]; /* buffer for leaf entry path */
 
scandir = opendir(ctx->path);
if (scandir == NULL) {
fetch_file_process_error(ctx,
fetch_file_errno_to_http_code(errno));
return;
}
 
/* fetch is going to be successful */
fetch_set_http_code(ctx->fetchh, 200);
 
/* force no-cache */
if (fetch_file_send_header(ctx, "Cache-Control: no-cache"))
goto fetch_file_process_dir_aborted;
 
/* content type */
if (fetch_file_send_header(ctx, "Content-Type: text/html"))
goto fetch_file_process_dir_aborted;
 
msg.type = FETCH_DATA;
msg.data.header_or_data.buf = (const uint8_t *) buffer;
 
/* directory listing top */
dirlist_generate_top(buffer, sizeof buffer);
msg.data.header_or_data.len = strlen(buffer);
if (fetch_file_send_callback(&msg, ctx))
goto fetch_file_process_dir_aborted;
 
/* directory listing title */
title = gen_nice_title(ctx->path);
dirlist_generate_title(title, buffer, sizeof buffer);
free(title);
msg.data.header_or_data.len = strlen(buffer);
if (fetch_file_send_callback(&msg, ctx))
goto fetch_file_process_dir_aborted;
 
/* Print parent directory link */
err = nsurl_parent(ctx->url, &up);
if (err == NSERROR_OK) {
if (nsurl_compare(ctx->url, up, NSURL_COMPLETE) == false) {
/* different URL; have parent */
dirlist_generate_parent_link(nsurl_access(up),
buffer, sizeof buffer);
 
msg.data.header_or_data.len = strlen(buffer);
fetch_file_send_callback(&msg, ctx);
}
nsurl_unref(up);
 
if (ctx->aborted)
goto fetch_file_process_dir_aborted;
 
}
 
/* directory list headings */
dirlist_generate_headings(buffer, sizeof buffer);
msg.data.header_or_data.len = strlen(buffer);
if (fetch_file_send_callback(&msg, ctx))
goto fetch_file_process_dir_aborted;
 
while ((ent = readdir(scandir)) != NULL) {
 
if (ent->d_name[0] == '.')
continue;
 
strncpy(urlpath, ctx->path, sizeof urlpath);
if (path_add_part(urlpath, sizeof urlpath,
ent->d_name) == false)
continue;
 
if (stat(urlpath, &ent_stat) != 0) {
ent_stat.st_mode = 0;
datebuf[0] = 0;
timebuf[0] = 0;
} else {
/* Get date in output format */
if (strftime((char *)&datebuf, sizeof datebuf,
"%a %d %b %Y",
localtime(&ent_stat.st_mtime)) == 0) {
strncpy(datebuf, "-", sizeof datebuf);
}
 
/* Get time in output format */
if (strftime((char *)&timebuf, sizeof timebuf,
"%H:%M",
localtime(&ent_stat.st_mtime)) == 0) {
strncpy(timebuf, "-", sizeof timebuf);
}
}
 
if((path = path_to_url(urlpath)) == NULL)
continue;
 
if (S_ISREG(ent_stat.st_mode)) {
/* regular file */
dirlist_generate_row(even,
false,
path,
ent->d_name,
fetch_filetype(urlpath),
ent_stat.st_size,
datebuf, timebuf,
buffer, sizeof(buffer));
} else if (S_ISDIR(ent_stat.st_mode)) {
/* directory */
dirlist_generate_row(even,
true,
path,
ent->d_name,
messages_get("FileDirectory"),
-1,
datebuf, timebuf,
buffer, sizeof(buffer));
} else {
/* something else */
dirlist_generate_row(even,
false,
path,
ent->d_name,
"",
-1,
datebuf, timebuf,
buffer, sizeof(buffer));
}
 
free(path);
 
msg.data.header_or_data.len = strlen(buffer);
if (fetch_file_send_callback(&msg, ctx))
goto fetch_file_process_dir_aborted;
 
even = !even;
}
 
/* directory listing bottom */
dirlist_generate_bottom(buffer, sizeof buffer);
msg.data.header_or_data.len = strlen(buffer);
if (fetch_file_send_callback(&msg, ctx))
goto fetch_file_process_dir_aborted;
 
msg.type = FETCH_FINISHED;
fetch_file_send_callback(&msg, ctx);
 
fetch_file_process_dir_aborted:
 
closedir(scandir);
}
 
 
/* process a file fetch */
static void fetch_file_process(struct fetch_file_context *ctx)
{
struct stat fdstat; /**< The objects stat */
 
if (stat(ctx->path, &fdstat) != 0) {
/* process errors as appropriate */
fetch_file_process_error(ctx,
fetch_file_errno_to_http_code(errno));
return;
}
 
if (S_ISDIR(fdstat.st_mode)) {
/* directory listing */
fetch_file_process_dir(ctx, &fdstat);
return;
} else if (S_ISREG(fdstat.st_mode)) {
/* regular file */
fetch_file_process_plain(ctx, &fdstat);
return;
} else {
/* unhandled type of file */
fetch_file_process_error(ctx, 501);
}
 
return;
}
 
/** callback to poll for additional file fetch contents */
static void fetch_file_poll(lwc_string *scheme)
{
struct fetch_file_context *c, *next;
 
if (ring == NULL) return;
 
/* Iterate over ring, processing each pending fetch */
c = ring;
do {
/* Ignore fetches that have been flagged as locked.
* This allows safe re-entrant calls to this function.
* Re-entrancy can occur if, as a result of a callback,
* the interested party causes fetch_poll() to be called
* again.
*/
if (c->locked == true) {
next = c->r_next;
continue;
}
 
/* Only process non-aborted fetches */
if (c->aborted == false) {
/* file fetches can be processed in one go */
fetch_file_process(c);
}
 
/* Compute next fetch item at the last possible moment as
* processing this item may have added to the ring.
*/
next = c->r_next;
 
fetch_remove_from_queues(c->fetchh);
fetch_free(c->fetchh);
 
/* Advance to next ring entry, exiting if we've reached
* the start of the ring or the ring has become empty
*/
} while ( (c = next) != ring && ring != NULL);
}
 
void fetch_file_register(void)
{
lwc_string *scheme;
 
if (lwc_intern_string("file", SLEN("file"), &scheme) != lwc_error_ok) {
die("Failed to initialise the fetch module "
"(couldn't intern \"file\").");
}
 
fetch_add_fetcher(scheme,
fetch_file_initialise,
fetch_file_can_fetch,
fetch_file_setup,
fetch_file_start,
fetch_file_abort,
fetch_file_free,
fetch_file_poll,
fetch_file_finalise);
}
/programs/network/netsurf/netsurf/content/fetchers/file.h
0,0 → 1,28
/*
* Copyright 2010 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* file: URL method handler
*/
 
#ifndef NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
#define NETSURF_CONTENT_FETCHERS_FETCH_FILE_H
 
void fetch_file_register(void);
 
#endif
/programs/network/netsurf/netsurf/content/fetchers/make.fetch
0,0 → 1,21
CFLAGS += -O2
NETSURF_FB_FRONTEND := sdl
NETSURF_FB_FONTLIB := internal
 
NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
 
# Default resource install path
NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
 
# Default framebuffer search path
NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
 
# freetype compiled in font serch path
NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
OBJS := curl.o data.o file.o about.o resource.o
 
 
OUTFILE = TEST.o
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include
include $(MENUETDEV)/makefiles/Makefile_for_o_lib
/programs/network/netsurf/netsurf/content/fetchers/resource.c
0,0 → 1,369
/*
* Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/* resource: URL handling. Based on the data fetcher by Rob Kendrick */
 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <inttypes.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <stdio.h>
#include <dirent.h>
#include <limits.h>
#include <stdarg.h>
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/config.h"
#include "content/dirlist.h"
#include "content/fetch.h"
#include "content/fetchers/resource.h"
#include "content/urldb.h"
#include "desktop/gui.h"
#include "desktop/options.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/utils.h"
#include "utils/ring.h"
 
struct fetch_resource_context;
 
typedef bool (*fetch_resource_handler)(struct fetch_resource_context *);
 
/** Context for an resource fetch */
struct fetch_resource_context {
struct fetch_resource_context *r_next, *r_prev;
 
struct fetch *fetchh; /**< Handle for this fetch */
 
bool aborted; /**< Flag indicating fetch has been aborted */
bool locked; /**< Flag indicating entry is already entered */
 
nsurl *url;
nsurl *redirect_url; /**< The url the fetch redirects to */
 
fetch_resource_handler handler;
};
 
static struct fetch_resource_context *ring = NULL;
 
/** Valid resource paths */
static const char *fetch_resource_paths[] = {
"adblock.css",
"default.css",
"internal.css",
"quirks.css",
"user.css",
"credits.html",
"licence.html",
"welcome.html",
"favicon.ico",
"netsurf.png"
};
static struct fetch_resource_map_entry {
lwc_string *path;
nsurl *url;
} fetch_resource_map[NOF_ELEMENTS(fetch_resource_paths)];
 
static uint32_t fetch_resource_path_count;
 
/** issue fetch callbacks with locking */
static inline bool fetch_resource_send_callback(const fetch_msg *msg,
struct fetch_resource_context *ctx)
{
ctx->locked = true;
fetch_send_callback(msg, ctx->fetchh);
ctx->locked = false;
 
return ctx->aborted;
}
 
static bool fetch_resource_send_header(struct fetch_resource_context *ctx,
const char *fmt, ...)
{
fetch_msg msg;
char header[64];
va_list ap;
 
va_start(ap, fmt);
 
vsnprintf(header, sizeof header, fmt, ap);
 
va_end(ap);
 
msg.type = FETCH_HEADER;
msg.data.header_or_data.buf = (const uint8_t *) header;
msg.data.header_or_data.len = strlen(header);
fetch_resource_send_callback(&msg, ctx);
 
return ctx->aborted;
}
 
 
 
 
static bool fetch_resource_redirect_handler(struct fetch_resource_context *ctx)
{
fetch_msg msg;
 
/* content is going to return redirect */
fetch_set_http_code(ctx->fetchh, 302);
 
msg.type = FETCH_REDIRECT;
msg.data.redirect = nsurl_access(ctx->redirect_url);
fetch_resource_send_callback(&msg, ctx);
 
return true;
}
 
 
static bool fetch_resource_notfound_handler(struct fetch_resource_context *ctx)
{
fetch_msg msg;
int code = 404;
char buffer[1024];
const char *title;
char key[8];
 
/* content is going to return error code */
fetch_set_http_code(ctx->fetchh, code);
 
/* content type */
if (fetch_resource_send_header(ctx, "Content-Type: text/html"))
goto fetch_resource_notfound_handler_aborted;
 
snprintf(key, sizeof key, "HTTP%03d", code);
title = messages_get(key);
 
snprintf(buffer, sizeof buffer, "<html><head><title>%s</title></head>"
"<body><h1>%s</h1>"
"<p>Error %d while fetching file %s</p></body></html>",
title, title, code, nsurl_access(ctx->url));
 
msg.type = FETCH_DATA;
msg.data.header_or_data.buf = (const uint8_t *) buffer;
msg.data.header_or_data.len = strlen(buffer);
if (fetch_resource_send_callback(&msg, ctx))
goto fetch_resource_notfound_handler_aborted;
 
msg.type = FETCH_FINISHED;
fetch_resource_send_callback(&msg, ctx);
 
fetch_resource_notfound_handler_aborted:
return false;
}
 
 
 
/** callback to initialise the resource fetcher. */
static bool fetch_resource_initialise(lwc_string *scheme)
{
struct fetch_resource_map_entry *e;
uint32_t i;
 
fetch_resource_path_count = 0;
 
for (i = 0; i < NOF_ELEMENTS(fetch_resource_paths); i++) {
e = &fetch_resource_map[fetch_resource_path_count];
 
if (lwc_intern_string(fetch_resource_paths[i],
strlen(fetch_resource_paths[i]),
&e->path) != lwc_error_ok) {
while (i > 0) {
i--;
lwc_string_unref(fetch_resource_map[i].path);
nsurl_unref(fetch_resource_map[i].url);
}
}
 
e->url = gui_get_resource_url(fetch_resource_paths[i]);
LOG(("URL is %s " ,lwc_string_data(e->path)));
if (e->url == NULL) {
lwc_string_unref(e->path);
} else {
fetch_resource_path_count++;
}
}
 
return true;
}
 
/** callback to finalise the resource fetcher. */
static void fetch_resource_finalise(lwc_string *scheme)
{
uint32_t i;
 
for (i = 0; i < fetch_resource_path_count; i++) {
lwc_string_unref(fetch_resource_map[i].path);
nsurl_unref(fetch_resource_map[i].url);
}
}
 
static bool fetch_resource_can_fetch(const nsurl *url)
{
return true;
}
 
/** callback to set up a resource fetch context. */
static void *
fetch_resource_setup(struct fetch *fetchh,
nsurl *url,
bool only_2xx,
bool downgrade_tls,
const char *post_urlenc,
const struct fetch_multipart_data *post_multipart,
const char **headers)
{
struct fetch_resource_context *ctx;
lwc_string *path;
 
ctx = calloc(1, sizeof(*ctx));
if (ctx == NULL)
return NULL;
 
ctx->handler = fetch_resource_notfound_handler;
 
if ((path = nsurl_get_component(url, NSURL_PATH)) != NULL) {
uint32_t i;
bool match;
 
/* Ensure requested path is valid */
for (i = 0; i < fetch_resource_path_count; i++) {
if (lwc_string_isequal(path,
fetch_resource_map[i].path,
&match) == lwc_error_ok && match) {
ctx->redirect_url =
nsurl_ref(fetch_resource_map[i].url);
ctx->handler =
fetch_resource_redirect_handler;
break;
}
}
 
lwc_string_unref(path);
}
 
ctx->url = nsurl_ref(url);
 
ctx->fetchh = fetchh;
 
RING_INSERT(ring, ctx);
 
return ctx;
}
 
/** callback to free a resource fetch */
static void fetch_resource_free(void *ctx)
{
struct fetch_resource_context *c = ctx;
if (c->redirect_url != NULL)
nsurl_unref(c->redirect_url);
if (c->url != NULL)
nsurl_unref(c->url);
RING_REMOVE(ring, c);
free(ctx);
}
 
/** callback to start a resource fetch */
static bool fetch_resource_start(void *ctx)
{
return true;
}
 
/** callback to abort a resource fetch */
static void fetch_resource_abort(void *ctx)
{
struct fetch_resource_context *c = ctx;
 
/* To avoid the poll loop having to deal with the fetch context
* disappearing from under it, we simply flag the abort here.
* The poll loop itself will perform the appropriate cleanup.
*/
c->aborted = true;
}
 
 
/** callback to poll for additional resource fetch contents */
static void fetch_resource_poll(lwc_string *scheme)
{
struct fetch_resource_context *c, *next;
 
if (ring == NULL) return;
 
/* Iterate over ring, processing each pending fetch */
c = ring;
do {
/* Ignore fetches that have been flagged as locked.
* This allows safe re-entrant calls to this function.
* Re-entrancy can occur if, as a result of a callback,
* the interested party causes fetch_poll() to be called
* again.
*/
if (c->locked == true) {
next = c->r_next;
continue;
}
 
/* Only process non-aborted fetches */
if (c->aborted == false) {
/* resource fetches can be processed in one go */
c->handler(c);
}
 
/* Compute next fetch item at the last possible moment
* as processing this item may have added to the ring
*/
next = c->r_next;
 
fetch_remove_from_queues(c->fetchh);
fetch_free(c->fetchh);
 
/* Advance to next ring entry, exiting if we've reached
* the start of the ring or the ring has become empty
*/
} while ( (c = next) != ring && ring != NULL);
}
 
void fetch_resource_register(void)
{
lwc_string *scheme;
 
if (lwc_intern_string("resource", SLEN("resource"),
&scheme) != lwc_error_ok) {
die("Failed to initialise the fetch module "
"(couldn't intern \"resource\").");
}
 
fetch_add_fetcher(scheme,
fetch_resource_initialise,
fetch_resource_can_fetch,
fetch_resource_setup,
fetch_resource_start,
fetch_resource_abort,
fetch_resource_free,
fetch_resource_poll,
fetch_resource_finalise);
}
/programs/network/netsurf/netsurf/content/fetchers/resource.h
0,0 → 1,40
/*
* Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf.
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* resource: URL method handler.
*
* The resource fetcher is intended to provide a flat uniform URL
* space for browser local resources referenced by URL. Using this
* scheme each frontend is only required to provide a single entry
* point to locate resources which can be accessed by the standard URL
* type scheme.
*
*/
 
#ifndef NETSURF_CONTENT_FETCHERS_FETCH_RESOURCE_H
#define NETSURF_CONTENT_FETCHERS_FETCH_RESOURCE_H
 
/**
* Register the resource scheme.
*
* should only be called from the fetch initialise
*/
void fetch_resource_register(void);
 
#endif
/programs/network/netsurf/netsurf/content/hlcache.c
0,0 → 1,850
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* High-level resource cache (implementation)
*/
 
#include <assert.h>
#include <stdlib.h>
#include <string.h>
 
#include "content/content.h"
#include "content/hlcache.h"
#include "content/mimesniff.h"
#include "utils/http.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/ring.h"
#include "utils/schedule.h"
#include "utils/url.h"
#include "utils/utils.h"
 
typedef struct hlcache_entry hlcache_entry;
typedef struct hlcache_retrieval_ctx hlcache_retrieval_ctx;
 
/** High-level cache retrieval context */
struct hlcache_retrieval_ctx {
struct hlcache_retrieval_ctx *r_prev; /**< Previous retrieval context in the ring */
struct hlcache_retrieval_ctx *r_next; /**< Next retrieval context in the ring */
 
llcache_handle *llcache; /**< Low-level cache handle */
 
hlcache_handle *handle; /**< High-level handle for object */
 
uint32_t flags; /**< Retrieval flags */
 
content_type accepted_types; /**< Accepted types */
 
hlcache_child_context child; /**< Child context */
 
bool migrate_target; /**< Whether this context is the migration target */
};
 
/** High-level cache handle */
struct hlcache_handle {
hlcache_entry *entry; /**< Pointer to cache entry */
 
hlcache_handle_callback cb; /**< Client callback */
void *pw; /**< Client data */
};
 
/** Entry in high-level cache */
struct hlcache_entry {
struct content *content; /**< Pointer to associated content */
 
hlcache_entry *next; /**< Next sibling */
hlcache_entry *prev; /**< Previous sibling */
};
 
/** Current state of the cache.
*
* Global state of the cache.
*/
struct hlcache_s {
struct hlcache_parameters params;
 
/** List of cached content objects */
hlcache_entry *content_list;
 
/** Ring of retrieval contexts */
hlcache_retrieval_ctx *retrieval_ctx_ring;
 
/* statsistics */
unsigned int hit_count;
unsigned int miss_count;
};
 
/** high level cache state */
static struct hlcache_s *hlcache = NULL;
 
 
static void hlcache_clean(void *ignored);
 
static nserror hlcache_llcache_callback(llcache_handle *handle,
const llcache_event *event, void *pw);
static nserror hlcache_migrate_ctx(hlcache_retrieval_ctx *ctx,
lwc_string *effective_type);
static bool hlcache_type_is_acceptable(lwc_string *mime_type,
content_type accepted_types, content_type *computed_type);
static nserror hlcache_find_content(hlcache_retrieval_ctx *ctx,
lwc_string *effective_type);
static void hlcache_content_callback(struct content *c,
content_msg msg, union content_msg_data data, void *pw);
 
/******************************************************************************
* Public API *
******************************************************************************/
 
nserror
hlcache_initialise(const struct hlcache_parameters *hlcache_parameters)
{
nserror ret;
 
hlcache = calloc(1, sizeof(struct hlcache_s));
if (hlcache == NULL) {
return NSERROR_NOMEM;
}
 
ret = llcache_initialise(hlcache_parameters->cb,
hlcache_parameters->cb_ctx,
hlcache_parameters->limit);
if (ret != NSERROR_OK) {
free(hlcache);
hlcache = NULL;
return ret;
}
 
hlcache->params = *hlcache_parameters;
 
/* Schedule the cache cleanup */
schedule(hlcache->params.bg_clean_time / 10, hlcache_clean, NULL);
 
return NSERROR_OK;
}
 
/* See hlcache.h for documentation */
void hlcache_stop(void)
{
/* Remove the hlcache_clean schedule */
schedule_remove(hlcache_clean, NULL);
}
 
/* See hlcache.h for documentation */
void hlcache_finalise(void)
{
uint32_t num_contents, prev_contents;
hlcache_entry *entry;
hlcache_retrieval_ctx *ctx, *next;
 
/* Obtain initial count of contents remaining */
for (num_contents = 0, entry = hlcache->content_list;
entry != NULL; entry = entry->next) {
num_contents++;
}
 
LOG(("%d contents remain before cache drain", num_contents));
 
/* Drain cache */
do {
prev_contents = num_contents;
 
hlcache_clean(NULL);
 
for (num_contents = 0, entry = hlcache->content_list;
entry != NULL; entry = entry->next) {
num_contents++;
}
} while (num_contents > 0 && num_contents != prev_contents);
 
LOG(("%d contents remaining:", num_contents));
for (entry = hlcache->content_list; entry != NULL; entry = entry->next) {
hlcache_handle entry_handle = { entry, NULL, NULL };
 
if (entry->content != NULL) {
LOG((" %p : %s (%d users)", entry,
nsurl_access(hlcache_handle_get_url(&entry_handle)), content_count_users(entry->content)));
} else {
LOG((" %p", entry));
}
}
 
/* Clean up retrieval contexts */
if (hlcache->retrieval_ctx_ring != NULL) {
ctx = hlcache->retrieval_ctx_ring;
 
do {
next = ctx->r_next;
 
if (ctx->llcache != NULL)
llcache_handle_release(ctx->llcache);
 
if (ctx->handle != NULL)
free(ctx->handle);
 
if (ctx->child.charset != NULL)
free((char *) ctx->child.charset);
 
free(ctx);
 
ctx = next;
} while (ctx != hlcache->retrieval_ctx_ring);
 
hlcache->retrieval_ctx_ring = NULL;
}
 
LOG(("hit/miss %d/%d", hlcache->hit_count, hlcache->miss_count));
 
free(hlcache);
hlcache = NULL;
 
LOG(("Finalising low-level cache"));
llcache_finalise();
}
 
/* See hlcache.h for documentation */
nserror hlcache_poll(void)
{
 
llcache_poll();
 
return NSERROR_OK;
}
 
/* See hlcache.h for documentation */
nserror hlcache_handle_retrieve(nsurl *url, uint32_t flags,
nsurl *referer, llcache_post_data *post,
hlcache_handle_callback cb, void *pw,
hlcache_child_context *child,
content_type accepted_types, hlcache_handle **result)
{
hlcache_retrieval_ctx *ctx;
nserror error;
 
assert(cb != NULL);
 
ctx = calloc(1, sizeof(hlcache_retrieval_ctx));
if (ctx == NULL)
return NSERROR_NOMEM;
 
ctx->handle = calloc(1, sizeof(hlcache_handle));
if (ctx->handle == NULL) {
free(ctx);
return NSERROR_NOMEM;
}
 
if (child != NULL) {
if (child->charset != NULL) {
ctx->child.charset = strdup(child->charset);
if (ctx->child.charset == NULL) {
free(ctx->handle);
free(ctx);
return NSERROR_NOMEM;
}
}
ctx->child.quirks = child->quirks;
}
 
ctx->flags = flags;
ctx->accepted_types = accepted_types;
 
ctx->handle->cb = cb;
ctx->handle->pw = pw;
 
error = llcache_handle_retrieve(url, flags, referer, post,
hlcache_llcache_callback, ctx,
&ctx->llcache);
if (error != NSERROR_OK) {
free((char *) ctx->child.charset);
free(ctx->handle);
free(ctx);
return error;
}
 
RING_INSERT(hlcache->retrieval_ctx_ring, ctx);
 
*result = ctx->handle;
 
return NSERROR_OK;
}
 
/* See hlcache.h for documentation */
nserror hlcache_handle_release(hlcache_handle *handle)
{
if (handle->entry != NULL) {
content_remove_user(handle->entry->content,
hlcache_content_callback, handle);
} else {
RING_ITERATE_START(struct hlcache_retrieval_ctx,
hlcache->retrieval_ctx_ring,
ictx) {
if (ictx->handle == handle &&
ictx->migrate_target == false) {
/* This is the nascent context for us,
* so abort the fetch */
llcache_handle_abort(ictx->llcache);
llcache_handle_release(ictx->llcache);
/* Remove us from the ring */
RING_REMOVE(hlcache->retrieval_ctx_ring, ictx);
/* Throw us away */
free((char *) ictx->child.charset);
free(ictx);
/* And stop */
RING_ITERATE_STOP(hlcache->retrieval_ctx_ring,
ictx);
}
} RING_ITERATE_END(hlcache->retrieval_ctx_ring, ictx);
}
 
handle->cb = NULL;
handle->pw = NULL;
 
free(handle);
 
return NSERROR_OK;
}
 
/* See hlcache.h for documentation */
struct content *hlcache_handle_get_content(const hlcache_handle *handle)
{
assert(handle != NULL);
 
if (handle->entry != NULL)
return handle->entry->content;
 
return NULL;
}
 
/* See hlcache.h for documentation */
nserror hlcache_handle_abort(hlcache_handle *handle)
{
struct hlcache_entry *entry = handle->entry;
struct content *c;
 
if (entry == NULL) {
/* This handle is not yet associated with a cache entry.
* The implication is that the fetch for the handle has
* not progressed to the point where the entry can be
* created. */
 
RING_ITERATE_START(struct hlcache_retrieval_ctx,
hlcache->retrieval_ctx_ring,
ictx) {
if (ictx->handle == handle &&
ictx->migrate_target == false) {
/* This is the nascent context for us,
* so abort the fetch */
llcache_handle_abort(ictx->llcache);
llcache_handle_release(ictx->llcache);
/* Remove us from the ring */
RING_REMOVE(hlcache->retrieval_ctx_ring, ictx);
/* Throw us away */
free((char *) ictx->child.charset);
free(ictx);
/* And stop */
RING_ITERATE_STOP(hlcache->retrieval_ctx_ring,
ictx);
}
} RING_ITERATE_END(hlcache->retrieval_ctx_ring, ictx);
 
return NSERROR_OK;
}
 
c = entry->content;
 
if (content_count_users(c) > 1) {
/* We are not the only user of 'c' so clone it. */
struct content *clone = content_clone(c);
 
if (clone == NULL)
return NSERROR_NOMEM;
 
entry = calloc(sizeof(struct hlcache_entry), 1);
 
if (entry == NULL) {
content_destroy(clone);
return NSERROR_NOMEM;
}
 
if (content_add_user(clone,
hlcache_content_callback, handle) == false) {
content_destroy(clone);
free(entry);
return NSERROR_NOMEM;
}
 
content_remove_user(c, hlcache_content_callback, handle);
 
entry->content = clone;
handle->entry = entry;
entry->prev = NULL;
entry->next = hlcache->content_list;
if (hlcache->content_list != NULL)
hlcache->content_list->prev = entry;
hlcache->content_list = entry;
 
c = clone;
}
 
return content_abort(c);
}
 
/* See hlcache.h for documentation */
nserror hlcache_handle_replace_callback(hlcache_handle *handle,
hlcache_handle_callback cb, void *pw)
{
handle->cb = cb;
handle->pw = pw;
 
return NSERROR_OK;
}
 
nserror hlcache_handle_clone(hlcache_handle *handle, hlcache_handle **result)
{
*result = NULL;
return NSERROR_CLONE_FAILED;
}
 
/* See hlcache.h for documentation */
nsurl *hlcache_handle_get_url(const hlcache_handle *handle)
{
nsurl *result = NULL;
 
assert(handle != NULL);
 
if (handle->entry != NULL) {
result = content_get_url(handle->entry->content);
} else {
RING_ITERATE_START(struct hlcache_retrieval_ctx,
hlcache->retrieval_ctx_ring,
ictx) {
if (ictx->handle == handle) {
/* This is the nascent context for us */
result = llcache_handle_get_url(ictx->llcache);
 
/* And stop */
RING_ITERATE_STOP(hlcache->retrieval_ctx_ring,
ictx);
}
} RING_ITERATE_END(hlcache->retrieval_ctx_ring, ictx);
}
 
return result;
}
 
/******************************************************************************
* High-level cache internals *
******************************************************************************/
 
/**
* Attempt to clean the cache
*/
void hlcache_clean(void *ignored)
{
hlcache_entry *entry, *next;
 
for (entry = hlcache->content_list; entry != NULL; entry = next) {
next = entry->next;
 
if (entry->content == NULL)
continue;
 
if (content__get_status(entry->content) ==
CONTENT_STATUS_LOADING)
continue;
 
if (content_count_users(entry->content) != 0)
continue;
 
/** \todo This is over-zealous: all unused contents
* will be immediately destroyed. Ideally, we want to
* purge all unused contents that are using stale
* source data, and enough fresh contents such that
* the cache fits in the configured cache size limit.
*/
 
/* Remove entry from cache */
if (entry->prev == NULL)
hlcache->content_list = entry->next;
else
entry->prev->next = entry->next;
 
if (entry->next != NULL)
entry->next->prev = entry->prev;
 
/* Destroy content */
content_destroy(entry->content);
 
/* Destroy entry */
free(entry);
}
 
/* Attempt to clean the llcache */
llcache_clean();
 
/* Re-schedule ourselves */
schedule(hlcache->params.bg_clean_time / 10, hlcache_clean, NULL);
}
 
/**
* Handler for low-level cache events
*
* \param handle Handle for which event is issued
* \param event Event data
* \param pw Pointer to client-specific data
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror hlcache_llcache_callback(llcache_handle *handle,
const llcache_event *event, void *pw)
{
hlcache_retrieval_ctx *ctx = pw;
lwc_string *effective_type = NULL;
nserror error;
 
assert(ctx->llcache == handle);
 
switch (event->type) {
case LLCACHE_EVENT_HAD_HEADERS:
error = mimesniff_compute_effective_type(handle, NULL, 0,
ctx->flags & HLCACHE_RETRIEVE_SNIFF_TYPE,
ctx->accepted_types == CONTENT_IMAGE,
&effective_type);
if (error == NSERROR_OK || error == NSERROR_NOT_FOUND) {
/* If the sniffer was successful or failed to find
* a Content-Type header when sniffing was
* prohibited, we must migrate the retrieval context. */
error = hlcache_migrate_ctx(ctx, effective_type);
 
if (effective_type != NULL)
lwc_string_unref(effective_type);
}
 
/* No need to report that we need data:
* we'll get some anyway if there is any */
if (error == NSERROR_NEED_DATA)
error = NSERROR_OK;
 
return error;
 
break;
case LLCACHE_EVENT_HAD_DATA:
error = mimesniff_compute_effective_type(handle,
event->data.data.buf, event->data.data.len,
ctx->flags & HLCACHE_RETRIEVE_SNIFF_TYPE,
ctx->accepted_types == CONTENT_IMAGE,
&effective_type);
if (error != NSERROR_OK) {
assert(0 && "MIME sniff failed with data");
}
 
error = hlcache_migrate_ctx(ctx, effective_type);
 
lwc_string_unref(effective_type);
 
return error;
 
break;
case LLCACHE_EVENT_DONE:
/* DONE event before we could determine the effective MIME type.
*/
error = mimesniff_compute_effective_type(handle,
NULL, 0, false, false, &effective_type);
if (error == NSERROR_OK) {
error = hlcache_migrate_ctx(ctx, effective_type);
 
lwc_string_unref(effective_type);
 
return error;
}
 
if (ctx->handle->cb != NULL) {
hlcache_event hlevent;
 
hlevent.type = CONTENT_MSG_ERROR;
hlevent.data.error = messages_get("BadType");
 
ctx->handle->cb(ctx->handle, &hlevent, ctx->handle->pw);
}
break;
case LLCACHE_EVENT_ERROR:
if (ctx->handle->cb != NULL) {
hlcache_event hlevent;
 
hlevent.type = CONTENT_MSG_ERROR;
hlevent.data.error = event->data.msg;
 
ctx->handle->cb(ctx->handle, &hlevent, ctx->handle->pw);
}
break;
case LLCACHE_EVENT_PROGRESS:
break;
}
 
return NSERROR_OK;
}
 
/**
* Migrate a retrieval context into its final destination content
*
* \param ctx Context to migrate
* \param effective_type The effective MIME type of the content, or NULL
* \return NSERROR_OK on success,
* NSERROR_NEED_DATA on success where data is needed,
* appropriate error otherwise
*/
nserror hlcache_migrate_ctx(hlcache_retrieval_ctx *ctx,
lwc_string *effective_type)
{
content_type type = CONTENT_NONE;
nserror error = NSERROR_OK;
 
ctx->migrate_target = true;
 
if (effective_type != NULL &&
hlcache_type_is_acceptable(effective_type,
ctx->accepted_types, &type)) {
error = hlcache_find_content(ctx, effective_type);
if (error != NSERROR_OK && error != NSERROR_NEED_DATA) {
if (ctx->handle->cb != NULL) {
hlcache_event hlevent;
 
hlevent.type = CONTENT_MSG_ERROR;
hlevent.data.error = messages_get("MiscError");
 
ctx->handle->cb(ctx->handle, &hlevent,
ctx->handle->pw);
}
 
llcache_handle_abort(ctx->llcache);
llcache_handle_release(ctx->llcache);
}
} else if (type == CONTENT_NONE &&
(ctx->flags & HLCACHE_RETRIEVE_MAY_DOWNLOAD)) {
/* Unknown type, and we can download, so convert */
llcache_handle_force_stream(ctx->llcache);
 
if (ctx->handle->cb != NULL) {
hlcache_event hlevent;
 
hlevent.type = CONTENT_MSG_DOWNLOAD;
hlevent.data.download = ctx->llcache;
 
ctx->handle->cb(ctx->handle, &hlevent,
ctx->handle->pw);
}
 
/* Ensure caller knows we need data */
error = NSERROR_NEED_DATA;
} else {
/* Unacceptable type: report error */
if (ctx->handle->cb != NULL) {
hlcache_event hlevent;
 
hlevent.type = CONTENT_MSG_ERROR;
hlevent.data.error = messages_get("UnacceptableType");
 
ctx->handle->cb(ctx->handle, &hlevent,
ctx->handle->pw);
}
 
llcache_handle_abort(ctx->llcache);
llcache_handle_release(ctx->llcache);
}
 
ctx->migrate_target = false;
 
/* No longer require retrieval context */
RING_REMOVE(hlcache->retrieval_ctx_ring, ctx);
free((char *) ctx->child.charset);
free(ctx);
 
return error;
}
 
/**
* Determine if the specified MIME type is acceptable
*
* \param mime_type MIME type to consider
* \param accepted_types Array of acceptable types, or NULL for any
* \param computed_type Pointer to location to receive computed type of object
* \return True if the type is acceptable, false otherwise
*/
bool hlcache_type_is_acceptable(lwc_string *mime_type,
content_type accepted_types, content_type *computed_type)
{
content_type type;
 
type = content_factory_type_from_mime_type(mime_type);
 
*computed_type = type;
 
return ((accepted_types & type) != 0);
}
 
/**
* Find a content for the high-level cache handle
*
* \param ctx High-level cache retrieval context
* \param effective_type Effective MIME type of content
* \return NSERROR_OK on success,
* NSERROR_NEED_DATA on success where data is needed,
* appropriate error otherwise
*
* \pre handle::state == HLCACHE_HANDLE_NEW
* \pre Headers must have been received for associated low-level handle
* \post Low-level handle is either released, or associated with new content
* \post High-level handle is registered with content
*/
nserror hlcache_find_content(hlcache_retrieval_ctx *ctx,
lwc_string *effective_type)
{
hlcache_entry *entry;
hlcache_event event;
nserror error = NSERROR_OK;
 
/* Search list of cached contents for a suitable one */
for (entry = hlcache->content_list; entry != NULL; entry = entry->next) {
hlcache_handle entry_handle = { entry, NULL, NULL };
const llcache_handle *entry_llcache;
 
if (entry->content == NULL)
continue;
 
/* Ignore contents in the error state */
if (content_get_status(&entry_handle) == CONTENT_STATUS_ERROR)
continue;
 
/* Ensure that content is shareable */
if (content_is_shareable(entry->content) == false)
continue;
 
/* Ensure that quirks mode is acceptable */
if (content_matches_quirks(entry->content,
ctx->child.quirks) == false)
continue;
 
/* Ensure that content uses same low-level object as
* low-level handle */
entry_llcache = content_get_llcache_handle(entry->content);
 
if (llcache_handle_references_same_object(entry_llcache,
ctx->llcache))
break;
}
 
if (entry == NULL) {
/* No existing entry, so need to create one */
entry = malloc(sizeof(hlcache_entry));
if (entry == NULL)
return NSERROR_NOMEM;
 
/* Create content using llhandle */
entry->content = content_factory_create_content(ctx->llcache,
ctx->child.charset, ctx->child.quirks,
effective_type);
if (entry->content == NULL) {
free(entry);
return NSERROR_NOMEM;
}
 
/* Insert into cache */
entry->prev = NULL;
entry->next = hlcache->content_list;
if (hlcache->content_list != NULL)
hlcache->content_list->prev = entry;
hlcache->content_list = entry;
 
/* Signal to caller that we created a content */
error = NSERROR_NEED_DATA;
 
hlcache->miss_count++;
} else {
/* Found a suitable content: no longer need low-level handle */
llcache_handle_release(ctx->llcache);
hlcache->hit_count++;
}
 
/* Associate handle with content */
if (content_add_user(entry->content,
hlcache_content_callback, ctx->handle) == false)
return NSERROR_NOMEM;
 
/* Associate cache entry with handle */
ctx->handle->entry = entry;
 
/* Catch handle up with state of content */
if (ctx->handle->cb != NULL) {
content_status status = content_get_status(ctx->handle);
 
if (status == CONTENT_STATUS_LOADING) {
event.type = CONTENT_MSG_LOADING;
ctx->handle->cb(ctx->handle, &event, ctx->handle->pw);
} else if (status == CONTENT_STATUS_READY) {
event.type = CONTENT_MSG_LOADING;
ctx->handle->cb(ctx->handle, &event, ctx->handle->pw);
 
if (ctx->handle->cb != NULL) {
event.type = CONTENT_MSG_READY;
ctx->handle->cb(ctx->handle, &event,
ctx->handle->pw);
}
} else if (status == CONTENT_STATUS_DONE) {
event.type = CONTENT_MSG_LOADING;
ctx->handle->cb(ctx->handle, &event, ctx->handle->pw);
 
if (ctx->handle->cb != NULL) {
event.type = CONTENT_MSG_READY;
ctx->handle->cb(ctx->handle, &event,
ctx->handle->pw);
}
 
if (ctx->handle->cb != NULL) {
event.type = CONTENT_MSG_DONE;
ctx->handle->cb(ctx->handle, &event,
ctx->handle->pw);
}
}
}
 
return error;
}
 
/**
* Veneer between content callback API and hlcache callback API
*
* \param c Content to emit message for
* \param msg Message to emit
* \param data Data for message
* \param pw Pointer to private data (hlcache_handle)
*/
void hlcache_content_callback(struct content *c, content_msg msg,
union content_msg_data data, void *pw)
{
hlcache_handle *handle = pw;
hlcache_event event;
nserror error = NSERROR_OK;
 
event.type = msg;
event.data = data;
 
if (handle->cb != NULL)
error = handle->cb(handle, &event, handle->pw);
 
if (error != NSERROR_OK)
LOG(("Error in callback: %d", error));
}
/programs/network/netsurf/netsurf/content/hlcache.h
0,0 → 1,201
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* High-level resource cache (interface)
*/
 
#ifndef NETSURF_CONTENT_HLCACHE_H_
#define NETSURF_CONTENT_HLCACHE_H_
 
#include "content/content.h"
#include "content/llcache.h"
#include "utils/errors.h"
#include "utils/nsurl.h"
 
/** High-level cache handle */
typedef struct hlcache_handle hlcache_handle;
 
/** Context for retrieving a child object */
typedef struct hlcache_child_context {
const char *charset; /**< Charset of parent */
bool quirks; /**< Whether parent is quirky */
} hlcache_child_context;
 
/** High-level cache event */
typedef struct {
content_msg type; /**< Event type */
union content_msg_data data; /**< Event data */
} hlcache_event;
 
struct hlcache_parameters {
llcache_query_callback cb; /**< Query handler for llcache */
void *cb_ctx; /**< Pointer to llcache query handler data */
 
/** How frequently the background cache clean process is run (ms) */
unsigned int bg_clean_time;
 
/** The target upper bound for the cache size */
size_t limit;
 
/** The hysteresis allowed round the target size */
size_t hysteresis;
 
};
 
/**
* Client callback for high-level cache events
*
* \param handle Handle to object generating event
* \param event Event data
* \param pw Pointer to client-specific data
* \return NSERROR_OK on success, appropriate error otherwise.
*/
typedef nserror (*hlcache_handle_callback)(hlcache_handle *handle,
const hlcache_event *event, void *pw);
 
/** Flags for high-level cache object retrieval */
enum hlcache_retrieve_flag {
/* Note: low-level cache retrieval flags occupy the bottom 16 bits of
* the flags word. High-level cache flags occupy the top 16 bits.
* To avoid confusion, high-level flags are allocated from bit 31 down.
*/
/** It's permitted to convert this request into a download */
HLCACHE_RETRIEVE_MAY_DOWNLOAD = (1 << 31),
/* Permit content-type sniffing */
HLCACHE_RETRIEVE_SNIFF_TYPE = (1 << 30)
};
 
/**
* Initialise the high-level cache, preparing the llcache also.
*
* \param hlcache_parameters Settings to initialise cache with
* \return NSERROR_OK on success, appropriate error otherwise.
*/
nserror hlcache_initialise(const struct hlcache_parameters *hlcache_parameters);
 
/**
* Stop the high-level cache periodic functionality so that the
* exit sequence can run.
*/
void hlcache_stop(void);
 
/**
* Finalise the high-level cache, destroying any remaining contents
*/
void hlcache_finalise(void);
 
/**
* Drive the low-level cache poll loop, and attempt to clean the cache.
* No guarantee is made about what, if any, cache cleaning will occur.
*
* \return NSERROR_OK
*/
nserror hlcache_poll(void);
 
/**
* Retrieve a high-level cache handle for an object
*
* \param url URL of the object to retrieve handle for
* \param flags Object retrieval flags
* \param referer Referring URL, or NULL if none
* \param post POST data, or NULL for a GET request
* \param cb Callback to handle object events
* \param pw Pointer to client-specific data for callback
* \param child Child retrieval context, or NULL for top-level content
* \param accepted_types Bitmap of acceptable content types
* \param result Pointer to location to recieve cache handle
* \return NSERROR_OK on success, appropriate error otherwise
*
* Child contents are keyed on the tuple < URL, quirks >.
* The quirks field is ignored for child contents whose behaviour is not
* affected by quirks mode.
*
* \todo The above rules should be encoded in the handler_map.
*
* \todo Is there any way to sensibly reduce the number of parameters here?
*/
nserror hlcache_handle_retrieve(nsurl *url, uint32_t flags,
nsurl *referer, llcache_post_data *post,
hlcache_handle_callback cb, void *pw,
hlcache_child_context *child,
content_type accepted_types, hlcache_handle **result);
 
/**
* Release a high-level cache handle
*
* \param handle Handle to release
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror hlcache_handle_release(hlcache_handle *handle);
 
/**
* Abort a high-level cache fetch
*
* \param handle Handle to abort
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror hlcache_handle_abort(hlcache_handle *handle);
 
/**
* Replace a high-level cache handle's callback
*
* \param handle Handle to replace callback of
* \param cb New callback routine
* \param pw Private data for callback
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror hlcache_handle_replace_callback(hlcache_handle *handle,
hlcache_handle_callback cb, void *pw);
 
/**
* Retrieve a content object from a cache handle
*
* \param handle Cache handle to dereference
* \return Pointer to content object, or NULL if there is none
*
* \todo This may not be correct. Ideally, the client should never need to
* directly access a content object. It may, therefore, be better to provide a
* bunch of veneers here that take a hlcache_handle and invoke the
* corresponding content_ API. If there's no content object associated with the
* hlcache_handle (e.g. because the source data is still being fetched, so it
* doesn't exist yet), then these veneers would behave as a NOP. The important
* thing being that the client need not care about this possibility and can
* just call the functions with impugnity.
*/
struct content *hlcache_handle_get_content(const hlcache_handle *handle);
 
/**
* Clone a high level cache handle.
*
* \param handle The handle to clone.
* \param result The cloned handle.
* \return NSERROR_OK on success, appropriate error otherwise
*
*/
nserror hlcache_handle_clone(hlcache_handle *handle, hlcache_handle **result);
 
/**
* Retrieve the URL associated with a high level cache handle
*
* \param handle The handle to inspect
* \return Pointer to URL.
*/
nsurl *hlcache_handle_get_url(const hlcache_handle *handle);
 
#endif
/programs/network/netsurf/netsurf/content/llcache.c
0,0 → 1,2590
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Low-level resource cache (implementation)
*/
 
#include <stdlib.h>
#include <string.h>
#include <time.h>
 
#include <curl/curl.h>
 
#include "content/fetch.h"
#include "content/llcache.h"
#include "content/urldb.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/nsurl.h"
#include "utils/utils.h"
 
/** Define to enable tracing of llcache operations. */
#undef LLCACHE_TRACE
 
/** State of a low-level cache object fetch */
typedef enum {
LLCACHE_FETCH_INIT, /**< Initial state, before fetch */
LLCACHE_FETCH_HEADERS, /**< Fetching headers */
LLCACHE_FETCH_DATA, /**< Fetching object data */
LLCACHE_FETCH_COMPLETE /**< Fetch completed */
} llcache_fetch_state;
 
/** Type of low-level cache object */
typedef struct llcache_object llcache_object;
 
/** Handle to low-level cache object */
struct llcache_handle {
llcache_object *object; /**< Pointer to associated object */
 
llcache_handle_callback cb; /**< Client callback */
void *pw; /**< Client data */
 
llcache_fetch_state state; /**< Last known state of object fetch */
size_t bytes; /**< Last reported byte count */
};
 
/** Low-level cache object user record */
typedef struct llcache_object_user {
llcache_handle *handle; /**< Handle data for client */
 
bool iterator_target; /**< This is the an iterator target */
bool queued_for_delete; /**< This user is queued for deletion */
 
struct llcache_object_user *prev; /**< Previous in list */
struct llcache_object_user *next; /**< Next in list */
} llcache_object_user;
 
/** Low-level cache object fetch context */
typedef struct {
uint32_t flags; /**< Fetch flags */
nsurl *referer; /**< Referring URL, or NULL if none */
llcache_post_data *post; /**< POST data, or NULL for GET */
 
struct fetch *fetch; /**< Fetch handle for this object */
 
llcache_fetch_state state; /**< Current state of object fetch */
 
uint32_t redirect_count; /**< Count of redirects followed */
 
bool tried_with_auth; /**< Whether we've tried with auth */
 
bool tried_with_tls_downgrade; /**< Whether we've tried TLS <= 1.0 */
 
bool outstanding_query; /**< Waiting for a query response */
} llcache_fetch_ctx;
 
typedef enum {
LLCACHE_VALIDATE_FRESH, /**< Only revalidate if not fresh */
LLCACHE_VALIDATE_ALWAYS, /**< Always revalidate */
LLCACHE_VALIDATE_ONCE /**< Revalidate once only */
} llcache_validate;
 
/** Cache control data */
typedef struct {
time_t req_time; /**< Time of request */
time_t res_time; /**< Time of response */
time_t date; /**< Date: response header */
time_t expires; /**< Expires: response header */
#define INVALID_AGE -1
int age; /**< Age: response header */
int max_age; /**< Max-Age Cache-control parameter */
llcache_validate no_cache; /**< No-Cache Cache-control parameter */
char *etag; /**< Etag: response header */
time_t last_modified; /**< Last-Modified: response header */
} llcache_cache_control;
 
/** Representation of a fetch header */
typedef struct {
char *name; /**< Header name */
char *value; /**< Header value */
} llcache_header;
 
/** Low-level cache object */
/** \todo Consider whether a list is a sane container */
struct llcache_object {
llcache_object *prev; /**< Previous in list */
llcache_object *next; /**< Next in list */
 
nsurl *url; /**< Post-redirect URL for object */
bool has_query; /**< URL has a query segment */
/** \todo We need a generic dynamic buffer object */
uint8_t *source_data; /**< Source data for object */
size_t source_len; /**< Byte length of source data */
size_t source_alloc; /**< Allocated size of source buffer */
 
llcache_object_user *users; /**< List of users */
 
llcache_fetch_ctx fetch; /**< Fetch context for object */
 
llcache_cache_control cache; /**< Cache control data for object */
llcache_object *candidate; /**< Object to use, if fetch determines
* that it is still fresh */
uint32_t candidate_count; /**< Count of objects this is a
* candidate for */
 
llcache_header *headers; /**< Fetch headers */
size_t num_headers; /**< Number of fetch headers */
};
 
struct llcache_s {
/** Handler for fetch-related queries */
llcache_query_callback query_cb;
 
/** Data for fetch-related query handler */
void *query_cb_pw;
 
/** Head of the low-level cached object list */
llcache_object *cached_objects;
 
/** Head of the low-level uncached object list */
llcache_object *uncached_objects;
 
uint32_t limit;
};
 
/** low level cache state */
static struct llcache_s *llcache = NULL;
 
/* Static lwc_strings */
static lwc_string *llcache_file_lwc;
static lwc_string *llcache_about_lwc;
static lwc_string *llcache_resource_lwc;
 
/* forward referenced callback function */
static void llcache_fetch_callback(const fetch_msg *msg, void *p);
 
 
/******************************************************************************
* Low-level cache internals *
******************************************************************************/
 
/**
* Create a new object user
*
* \param cb Callback routine
* \param pw Private data for callback
* \param user Pointer to location to receive result
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_object_user_new(llcache_handle_callback cb, void *pw,
llcache_object_user **user)
{
llcache_handle *h;
llcache_object_user *u;
 
h = calloc(1, sizeof(llcache_handle));
if (h == NULL)
return NSERROR_NOMEM;
 
u = calloc(1, sizeof(llcache_object_user));
if (u == NULL) {
free(h);
return NSERROR_NOMEM;
}
 
h->cb = cb;
h->pw = pw;
 
u->handle = h;
 
#ifdef LLCACHE_TRACE
LOG(("Created user %p (%p, %p, %p)", u, h, (void *) cb, pw));
#endif
 
*user = u;
 
return NSERROR_OK;
}
 
/**
* Destroy an object user
*
* \param user User to destroy
* \return NSERROR_OK on success, appropriate error otherwise
*
* \pre User is not attached to an object
*/
static nserror llcache_object_user_destroy(llcache_object_user *user)
{
#ifdef LLCACHE_TRACE
LOG(("Destroyed user %p", user));
#endif
assert(user->next == NULL);
assert(user->prev == NULL);
if (user->handle != NULL)
free(user->handle);
 
free(user);
 
return NSERROR_OK;
}
 
/**
* Remove a user from a low-level cache object
*
* \param object Object to remove user from
* \param user User to remove
* \return NSERROR_OK.
*/
static nserror llcache_object_remove_user(llcache_object *object,
llcache_object_user *user)
{
assert(user != NULL);
assert(object != NULL);
assert(object->users != NULL);
assert(user->handle == NULL || user->handle->object == object);
assert((user->prev != NULL) || (object->users == user));
if (user == object->users)
object->users = user->next;
else
user->prev->next = user->next;
 
if (user->next != NULL)
user->next->prev = user->prev;
user->next = user->prev = NULL;
#ifdef LLCACHE_TRACE
LOG(("Removing user %p from %p", user, object));
#endif
 
return NSERROR_OK;
}
 
/**
* Iterate the users of an object, calling their callbacks.
*
* \param object The object to iterate
* \param event The event to pass to the callback.
* \return NSERROR_OK on success, appropriate error otherwise.
*/
static nserror llcache_send_event_to_users(llcache_object *object,
llcache_event *event)
{
nserror error = NSERROR_OK;
llcache_object_user *user, *next_user;
user = object->users;
while (user != NULL) {
user->iterator_target = true;
 
error = user->handle->cb(user->handle, event,
user->handle->pw);
 
next_user = user->next;
 
user->iterator_target = false;
 
if (user->queued_for_delete) {
llcache_object_remove_user(object, user);
llcache_object_user_destroy(user);
}
 
if (error != NSERROR_OK)
break;
 
user = next_user;
}
return error;
}
 
/**
* Create a new low-level cache object
*
* \param url URL of object to create
* \param result Pointer to location to receive result
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_object_new(nsurl *url, llcache_object **result)
{
llcache_object *obj = calloc(1, sizeof(llcache_object));
if (obj == NULL)
return NSERROR_NOMEM;
 
#ifdef LLCACHE_TRACE
LOG(("Created object %p (%s)", obj, nsurl_access(url)));
#endif
 
obj->url = nsurl_ref(url);
 
*result = obj;
 
return NSERROR_OK;
}
 
/**
* Clone a POST data object
*
* \param orig Object to clone
* \param clone Pointer to location to receive clone
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_post_data_clone(const llcache_post_data *orig,
llcache_post_data **clone)
{
llcache_post_data *post_clone;
 
post_clone = calloc(1, sizeof(llcache_post_data));
if (post_clone == NULL)
return NSERROR_NOMEM;
 
post_clone->type = orig->type;
 
/* Deep-copy the type-specific data */
if (orig->type == LLCACHE_POST_URL_ENCODED) {
post_clone->data.urlenc = strdup(orig->data.urlenc);
if (post_clone->data.urlenc == NULL) {
free(post_clone);
 
return NSERROR_NOMEM;
}
} else {
post_clone->data.multipart = fetch_multipart_data_clone(
orig->data.multipart);
if (post_clone->data.multipart == NULL) {
free(post_clone);
 
return NSERROR_NOMEM;
}
}
 
*clone = post_clone;
 
return NSERROR_OK;
}
 
/**
* Split a fetch header into name and value
*
* \param data Header string
* \param len Byte length of header
* \param name Pointer to location to receive header name
* \param value Pointer to location to receive header value
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_fetch_split_header(const uint8_t *data, size_t len,
char **name, char **value)
{
char *n, *v;
const uint8_t *colon;
 
/* Find colon */
colon = (const uint8_t *) strchr((const char *) data, ':');
if (colon == NULL) {
/* Failed, assume a key with no value */
n = strdup((const char *) data);
if (n == NULL)
return NSERROR_NOMEM;
 
v = strdup("");
if (v == NULL) {
free(n);
return NSERROR_NOMEM;
}
} else {
/* Split header into name & value */
 
/* Strip leading whitespace from name */
while (data[0] == ' ' || data[0] == '\t' ||
data[0] == '\r' || data[0] == '\n') {
data++;
}
 
/* Strip trailing whitespace from name */
while (colon > data && (colon[-1] == ' ' ||
colon[-1] == '\t' || colon[-1] == '\r' ||
colon[-1] == '\n'))
colon--;
 
n = strndup((const char *) data, colon - data);
if (n == NULL)
return NSERROR_NOMEM;
 
/* Find colon again */
while (*colon != ':') {
colon++;
}
 
/* Skip over colon and any subsequent whitespace */
do {
colon++;
} while (*colon == ' ' || *colon == '\t' ||
*colon == '\r' || *colon == '\n');
 
/* Strip trailing whitespace from value */
while (len > 0 && (data[len - 1] == ' ' ||
data[len - 1] == '\t' ||
data[len - 1] == '\r' ||
data[len - 1] == '\n')) {
len--;
}
 
v = strndup((const char *) colon, len - (colon - data));
if (v == NULL) {
free(n);
return NSERROR_NOMEM;
}
}
 
*name = n;
*value = v;
 
return NSERROR_OK;
}
 
/**
* Parse a fetch header
*
* \param object Object to parse header for
* \param data Header string
* \param len Byte length of header
* \param name Pointer to location to receive header name
* \param value Pointer to location to receive header value
* \return NSERROR_OK on success, appropriate error otherwise
*
* \note This function also has the side-effect of updating
* the cache control data for the object if an interesting
* header is encountered
*/
static nserror llcache_fetch_parse_header(llcache_object *object,
const uint8_t *data, size_t len, char **name, char **value)
{
nserror error;
 
/* Set fetch response time if not already set */
if (object->cache.res_time == 0)
object->cache.res_time = time(NULL);
 
/* Decompose header into name-value pair */
error = llcache_fetch_split_header(data, len, name, value);
if (error != NSERROR_OK)
return error;
 
/* Parse cache headers to populate cache control data */
#define SKIP_ST(p) while (*p != '\0' && (*p == ' ' || *p == '\t')) p++
 
if (5 < len && strcasecmp(*name, "Date") == 0) {
/* extract Date header */
object->cache.date = curl_getdate(*value, NULL);
} else if (4 < len && strcasecmp(*name, "Age") == 0) {
/* extract Age header */
if ('0' <= **value && **value <= '9')
object->cache.age = atoi(*value);
} else if (8 < len && strcasecmp(*name, "Expires") == 0) {
/* extract Expires header */
object->cache.expires = curl_getdate(*value, NULL);
} else if (14 < len && strcasecmp(*name, "Cache-Control") == 0) {
/* extract and parse Cache-Control header */
const char *start = *value;
const char *comma = *value;
 
while (*comma != '\0') {
while (*comma != '\0' && *comma != ',')
comma++;
 
if (8 < comma - start && (strncasecmp(start,
"no-cache", 8) == 0 ||
strncasecmp(start, "no-store", 8) == 0))
/* When we get a disk cache we should
* distinguish between these two */
object->cache.no_cache = LLCACHE_VALIDATE_ALWAYS;
else if (7 < comma - start &&
strncasecmp(start, "max-age", 7) == 0) {
/* Find '=' */
while (start < comma && *start != '=')
start++;
 
/* Skip over it */
start++;
 
/* Skip whitespace */
SKIP_ST(start);
 
if (start < comma)
object->cache.max_age = atoi(start);
}
 
if (*comma != '\0') {
/* Skip past comma */
comma++;
/* Skip whitespace */
SKIP_ST(comma);
}
 
/* Set start for next token */
start = comma;
}
} else if (5 < len && strcasecmp(*name, "ETag") == 0) {
/* extract ETag header */
free(object->cache.etag);
object->cache.etag = strdup(*value);
if (object->cache.etag == NULL)
return NSERROR_NOMEM;
} else if (14 < len && strcasecmp(*name, "Last-Modified") == 0) {
/* extract Last-Modified header */
object->cache.last_modified = curl_getdate(*value, NULL);
}
 
#undef SKIP_ST
 
return NSERROR_OK;
}
 
/* Destroy headers */
static inline void llcache_destroy_headers(llcache_object *object)
{
while (object->num_headers > 0) {
object->num_headers--;
 
free(object->headers[object->num_headers].name);
free(object->headers[object->num_headers].value);
}
free(object->headers);
object->headers = NULL;
}
 
/* Invalidate cache control data */
static inline void llcache_invalidate_cache_control_data(llcache_object *object)
{
free(object->cache.etag);
memset(&(object->cache), 0, sizeof(llcache_cache_control));
 
object->cache.age = INVALID_AGE;
object->cache.max_age = INVALID_AGE;
}
 
/**
* Process a fetch header
*
* \param object Object being fetched
* \param data Header string
* \param len Byte length of header
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_fetch_process_header(llcache_object *object,
const uint8_t *data, size_t len)
{
nserror error;
char *name, *value;
llcache_header *temp;
 
/* The headers for multiple HTTP responses may be delivered to us if
* the fetch layer receives a 401 response for which it has
* authentication credentials. This will result in a silent re-request
* after which we'll receive the actual response headers for the
* object we want to fetch (assuming that the credentials were correct
* of course)
*
* Therefore, if the header is an HTTP response start marker, then we
* must discard any headers we've read so far, reset the cache data
* that we might have computed, and start again.
*/
/** \todo Properly parse the response line */
if (strncmp((const char *) data, "HTTP/", SLEN("HTTP/")) == 0) {
time_t req_time = object->cache.req_time;
 
llcache_invalidate_cache_control_data(object);
 
/* Restore request time, so we compute object's age correctly */
object->cache.req_time = req_time;
 
llcache_destroy_headers(object);
}
 
error = llcache_fetch_parse_header(object, data, len, &name, &value);
if (error != NSERROR_OK)
return error;
 
/* Append header data to the object's headers array */
temp = realloc(object->headers, (object->num_headers + 1) *
sizeof(llcache_header));
if (temp == NULL) {
free(name);
free(value);
return NSERROR_NOMEM;
}
 
object->headers = temp;
 
object->headers[object->num_headers].name = name;
object->headers[object->num_headers].value = value;
 
object->num_headers++;
 
return NSERROR_OK;
}
 
/**
* (Re)fetch an object
*
* \param object Object to refetch
* \return NSERROR_OK on success, appropriate error otherwise
*
* \pre The fetch parameters in object->fetch must be populated
*/
static nserror llcache_object_refetch(llcache_object *object)
{
const char *urlenc = NULL;
struct fetch_multipart_data *multipart = NULL;
char **headers = NULL;
int header_idx = 0;
 
if (object->fetch.post != NULL) {
if (object->fetch.post->type == LLCACHE_POST_URL_ENCODED)
urlenc = object->fetch.post->data.urlenc;
else
multipart = object->fetch.post->data.multipart;
}
 
/* Generate cache-control headers */
headers = malloc(3 * sizeof(char *));
if (headers == NULL)
return NSERROR_NOMEM;
 
if (object->cache.etag != NULL) {
const size_t len = SLEN("If-None-Match: ") +
strlen(object->cache.etag) + 1;
 
headers[header_idx] = malloc(len);
if (headers[header_idx] == NULL) {
free(headers);
return NSERROR_NOMEM;
}
 
snprintf(headers[header_idx], len, "If-None-Match: %s",
object->cache.etag);
 
header_idx++;
}
if (object->cache.date != 0) {
/* Maximum length of an RFC 1123 date is 29 bytes */
const size_t len = SLEN("If-Modified-Since: ") + 29 + 1;
 
headers[header_idx] = malloc(len);
if (headers[header_idx] == NULL) {
while (--header_idx >= 0)
free(headers[header_idx]);
free(headers);
return NSERROR_NOMEM;
}
 
snprintf(headers[header_idx], len, "If-Modified-Since: %s",
rfc1123_date(object->cache.date));
 
header_idx++;
}
headers[header_idx] = NULL;
 
/* Reset cache control data */
llcache_invalidate_cache_control_data(object);
object->cache.req_time = time(NULL);
 
/* Reset fetch state */
object->fetch.state = LLCACHE_FETCH_INIT;
 
#ifdef LLCACHE_TRACE
LOG(("Refetching %p", object));
#endif
 
/* Kick off fetch */
object->fetch.fetch = fetch_start(object->url, object->fetch.referer,
llcache_fetch_callback, object,
object->fetch.flags & LLCACHE_RETRIEVE_NO_ERROR_PAGES,
urlenc, multipart,
object->fetch.flags & LLCACHE_RETRIEVE_VERIFIABLE,
object->fetch.tried_with_tls_downgrade,
(const char **) headers);
 
/* Clean up cache-control headers */
while (--header_idx >= 0)
free(headers[header_idx]);
free(headers);
 
/* Did we succeed in creating a fetch? */
if (object->fetch.fetch == NULL)
return NSERROR_NOMEM;
 
return NSERROR_OK;
}
 
/**
* Kick-off a fetch for an object
*
* \param object Object to fetch
* \param flags Fetch flags
* \param referer Referring URL, or NULL for none
* \param post POST data, or NULL for GET
* \param redirect_count Number of redirects followed so far
* \return NSERROR_OK on success, appropriate error otherwise
*
* \pre object::url must contain the URL to fetch
* \pre If there is a freshness validation candidate,
* object::candidate and object::cache must be filled in
* \pre There must not be a fetch in progress for \a object
*/
static nserror llcache_object_fetch(llcache_object *object, uint32_t flags,
nsurl *referer, const llcache_post_data *post,
uint32_t redirect_count)
{
nserror error;
nsurl *referer_clone = NULL;
llcache_post_data *post_clone = NULL;
 
#ifdef LLCACHE_TRACE
LOG(("Starting fetch for %p", object));
#endif
 
if (post != NULL) {
error = llcache_post_data_clone(post, &post_clone);
if (error != NSERROR_OK)
return error;
}
 
if (referer != NULL)
referer_clone = nsurl_ref(referer);
 
object->fetch.flags = flags;
object->fetch.referer = referer_clone;
object->fetch.post = post_clone;
object->fetch.redirect_count = redirect_count;
 
return llcache_object_refetch(object);
}
 
/**
* Destroy a low-level cache object
*
* \param object Object to destroy
* \return NSERROR_OK on success, appropriate error otherwise
*
* \pre Object is detached from cache list
* \pre Object has no users
* \pre Object is not a candidate (i.e. object::candidate_count == 0)
*/
static nserror llcache_object_destroy(llcache_object *object)
{
size_t i;
 
#ifdef LLCACHE_TRACE
LOG(("Destroying object %p", object));
#endif
 
nsurl_unref(object->url);
free(object->source_data);
 
if (object->fetch.fetch != NULL) {
fetch_abort(object->fetch.fetch);
object->fetch.fetch = NULL;
}
 
if (object->fetch.referer != NULL)
nsurl_unref(object->fetch.referer);
 
if (object->fetch.post != NULL) {
if (object->fetch.post->type == LLCACHE_POST_URL_ENCODED) {
free(object->fetch.post->data.urlenc);
} else {
fetch_multipart_data_destroy(
object->fetch.post->data.multipart);
}
 
free(object->fetch.post);
}
 
free(object->cache.etag);
 
for (i = 0; i < object->num_headers; i++) {
free(object->headers[i].name);
free(object->headers[i].value);
}
free(object->headers);
 
free(object);
 
return NSERROR_OK;
}
 
/**
* Add a low-level cache object to a cache list
*
* \param object Object to add
* \param list List to add to
* \return NSERROR_OK
*/
static nserror llcache_object_add_to_list(llcache_object *object,
llcache_object **list)
{
object->prev = NULL;
object->next = *list;
 
if (*list != NULL)
(*list)->prev = object;
*list = object;
 
return NSERROR_OK;
}
 
/**
* Determine the remaining lifetime of a cache object using the
*
* \param object Object to consider
* \return True if object is still fresh, false otherwise
*/
static int
llcache_object_rfc2616_remaining_lifetime(const llcache_cache_control *cd)
{
int current_age, freshness_lifetime;
time_t now = time(NULL);
 
/* Calculate staleness of cached object as per RFC 2616 13.2.3/13.2.4 */
current_age = max(0, (cd->res_time - cd->date));
current_age = max(current_age, (cd->age == INVALID_AGE) ? 0 : cd->age);
current_age += cd->res_time - cd->req_time + now - cd->res_time;
 
/* Determine freshness lifetime of this object */
if (cd->max_age != INVALID_AGE)
freshness_lifetime = cd->max_age;
else if (cd->expires != 0)
freshness_lifetime = cd->expires - cd->date;
else if (cd->last_modified != 0)
freshness_lifetime = (now - cd->last_modified) / 10;
else
freshness_lifetime = 0;
 
#ifdef LLCACHE_TRACE
LOG(("%d:%d", freshness_lifetime, current_age));
#endif
 
if ((cd->no_cache == LLCACHE_VALIDATE_FRESH) &&
(freshness_lifetime > current_age)) {
/* object was not forbidden from being returned from
* the cache unvalidated (i.e. the response contained
* a no-cache directive)
*
* The object current age is within the freshness lifetime.
*/
return freshness_lifetime - current_age;
}
 
return 0; /* object has no remaining lifetime */
}
 
/**
* Determine if an object is still fresh
*
* \param object Object to consider
* \return True if object is still fresh, false otherwise
*/
static bool llcache_object_is_fresh(const llcache_object *object)
{
int remaining_lifetime;
const llcache_cache_control *cd = &object->cache;
 
remaining_lifetime = llcache_object_rfc2616_remaining_lifetime(cd);
 
#ifdef LLCACHE_TRACE
LOG(("%p: (%d > 0 || %d != %d)", object,
remaining_lifetime,
object->fetch.state, LLCACHE_FETCH_COMPLETE));
#endif
 
/* The object is fresh if:
* - it was not forbidden from being returned from the cache
* unvalidated.
*
* - it has remaining lifetime or still being fetched.
*/
return ((cd->no_cache == LLCACHE_VALIDATE_FRESH) &&
((remaining_lifetime > 0) ||
(object->fetch.state != LLCACHE_FETCH_COMPLETE)));
}
 
/**
* Clone an object's cache data
*
* \param source Source object containing cache data to clone
* \param destination Destination object to clone cache data into
* \param deep Whether to deep-copy the data or not
* \return NSERROR_OK on success, appropriate error otherwise
*
* \post If \a deep is false, then any pointers in \a source will be set to NULL
*/
static nserror llcache_object_clone_cache_data(llcache_object *source,
llcache_object *destination, bool deep)
{
/* ETag must be first, as it can fail when deep cloning */
if (source->cache.etag != NULL) {
char *etag = source->cache.etag;
 
if (deep) {
/* Copy the etag */
etag = strdup(source->cache.etag);
if (etag == NULL)
return NSERROR_NOMEM;
} else {
/* Destination takes ownership */
source->cache.etag = NULL;
}
 
if (destination->cache.etag != NULL)
free(destination->cache.etag);
 
destination->cache.etag = etag;
}
 
destination->cache.req_time = source->cache.req_time;
destination->cache.res_time = source->cache.res_time;
 
if (source->cache.date != 0)
destination->cache.date = source->cache.date;
 
if (source->cache.expires != 0)
destination->cache.expires = source->cache.expires;
 
if (source->cache.age != INVALID_AGE)
destination->cache.age = source->cache.age;
 
if (source->cache.max_age != INVALID_AGE)
destination->cache.max_age = source->cache.max_age;
 
if (source->cache.no_cache != LLCACHE_VALIDATE_FRESH)
destination->cache.no_cache = source->cache.no_cache;
if (source->cache.last_modified != 0)
destination->cache.last_modified = source->cache.last_modified;
 
return NSERROR_OK;
}
 
/**
* Retrieve a potentially cached object
*
* \param url URL of object to retrieve
* \param flags Fetch flags
* \param referer Referring URL, or NULL if none
* \param post POST data, or NULL for a GET request
* \param redirect_count Number of redirects followed so far
* \param result Pointer to location to recieve retrieved object
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_object_retrieve_from_cache(nsurl *url, uint32_t flags,
nsurl *referer, const llcache_post_data *post,
uint32_t redirect_count, llcache_object **result)
{
nserror error;
llcache_object *obj, *newest = NULL;
 
#ifdef LLCACHE_TRACE
LOG(("Searching cache for %s (%x %s %p)", url, flags, referer, post));
#endif
 
/* Search for the most recently fetched matching object */
for (obj = llcache->cached_objects; obj != NULL; obj = obj->next) {
 
if ((newest == NULL ||
obj->cache.req_time > newest->cache.req_time) &&
nsurl_compare(obj->url, url,
NSURL_COMPLETE) == true) {
newest = obj;
}
}
 
if (newest != NULL && llcache_object_is_fresh(newest)) {
/* Found a suitable object, and it's still fresh, so use it */
obj = newest;
 
#ifdef LLCACHE_TRACE
LOG(("Found fresh %p", obj));
#endif
 
/* The client needs to catch up with the object's state.
* This will occur the next time that llcache_poll is called.
*/
} else if (newest != NULL) {
/* Found a candidate object but it needs freshness validation */
 
/* Create a new object */
error = llcache_object_new(url, &obj);
if (error != NSERROR_OK)
return error;
 
#ifdef LLCACHE_TRACE
LOG(("Found candidate %p (%p)", obj, newest));
#endif
 
/* Clone candidate's cache data */
error = llcache_object_clone_cache_data(newest, obj, true);
if (error != NSERROR_OK) {
llcache_object_destroy(obj);
return error;
}
 
/* Record candidate, so we can fall back if it is still fresh */
newest->candidate_count++;
obj->candidate = newest;
 
/* Attempt to kick-off fetch */
error = llcache_object_fetch(obj, flags, referer, post,
redirect_count);
if (error != NSERROR_OK) {
newest->candidate_count--;
llcache_object_destroy(obj);
return error;
}
 
/* Add new object to cache */
llcache_object_add_to_list(obj, &llcache->cached_objects);
} else {
/* No object found; create a new one */
/* Create new object */
error = llcache_object_new(url, &obj);
if (error != NSERROR_OK)
return error;
 
#ifdef LLCACHE_TRACE
LOG(("Not found %p", obj));
#endif
 
/* Attempt to kick-off fetch */
error = llcache_object_fetch(obj, flags, referer, post,
redirect_count);
if (error != NSERROR_OK) {
llcache_object_destroy(obj);
return error;
}
 
/* Add new object to cache */
llcache_object_add_to_list(obj, &llcache->cached_objects);
}
 
*result = obj;
 
return NSERROR_OK;
}
 
/**
* Retrieve an object from the cache, fetching it if necessary.
*
* \param url URL of object to retrieve
* \param flags Fetch flags
* \param referer Referring URL, or NULL if none
* \param post POST data, or NULL for a GET request
* \param redirect_count Number of redirects followed so far
* \param result Pointer to location to recieve retrieved object
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_object_retrieve(nsurl *url, uint32_t flags,
nsurl *referer, const llcache_post_data *post,
uint32_t redirect_count, llcache_object **result)
{
nserror error;
llcache_object *obj;
bool has_query;
nsurl *defragmented_url;
 
#ifdef LLCACHE_TRACE
LOG(("Retrieve %s (%x, %s, %p)", url, flags, referer, post));
#endif
 
/**
* Caching Rules:
*
* 1) Forced fetches are never cached
* 2) POST requests are never cached
*/
 
/* Look for a query segment */
has_query = nsurl_has_component(url, NSURL_QUERY);
 
/* Get rid of any url fragment */
if (nsurl_has_component(url, NSURL_FRAGMENT)) {
error = nsurl_defragment(url, &defragmented_url);
if (error != NSERROR_OK)
return error;
} else {
defragmented_url = nsurl_ref(url);
}
 
if (flags & LLCACHE_RETRIEVE_FORCE_FETCH || post != NULL) {
/* Create new object */
error = llcache_object_new(defragmented_url, &obj);
if (error != NSERROR_OK) {
nsurl_unref(defragmented_url);
return error;
}
 
/* Attempt to kick-off fetch */
error = llcache_object_fetch(obj, flags, referer, post,
redirect_count);
if (error != NSERROR_OK) {
llcache_object_destroy(obj);
nsurl_unref(defragmented_url);
return error;
}
 
/* Add new object to uncached list */
llcache_object_add_to_list(obj, &llcache->uncached_objects);
} else {
error = llcache_object_retrieve_from_cache(defragmented_url,
flags, referer, post, redirect_count, &obj);
if (error != NSERROR_OK) {
nsurl_unref(defragmented_url);
return error;
}
 
/* Returned object is already in the cached list */
}
obj->has_query = has_query;
 
#ifdef LLCACHE_TRACE
LOG(("Retrieved %p", obj));
#endif
*result = obj;
nsurl_unref(defragmented_url);
return NSERROR_OK;
}
 
/**
* Add a user to a low-level cache object
*
* \param object Object to add user to
* \param user User to add
* \return NSERROR_OK.
*/
static nserror llcache_object_add_user(llcache_object *object,
llcache_object_user *user)
{
assert(user->next == NULL);
assert(user->prev == NULL);
 
user->handle->object = object;
 
user->prev = NULL;
user->next = object->users;
 
if (object->users != NULL)
object->users->prev = user;
object->users = user;
 
#ifdef LLCACHE_TRACE
LOG(("Adding user %p to %p", user, object));
#endif
 
return NSERROR_OK;
}
 
/**
* Handle FETCH_REDIRECT event
*
* \param object Object being redirected
* \param target Target of redirect (may be relative)
* \param replacement Pointer to location to receive replacement object
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_fetch_redirect(llcache_object *object, const char *target,
llcache_object **replacement)
{
nserror error;
llcache_object *dest;
llcache_object_user *user, *next;
const llcache_post_data *post = object->fetch.post;
nsurl *url;
lwc_string *scheme;
lwc_string *object_scheme;
bool match;
/* Extract HTTP response code from the fetch object */
long http_code = fetch_http_code(object->fetch.fetch);
 
/* Abort fetch for this object */
fetch_abort(object->fetch.fetch);
object->fetch.fetch = NULL;
/* Invalidate the cache control data */
llcache_invalidate_cache_control_data(object);
 
/* And mark it complete */
object->fetch.state = LLCACHE_FETCH_COMPLETE;
/* Forcibly stop redirecting if we've followed too many redirects */
#define REDIRECT_LIMIT 10
if (object->fetch.redirect_count > REDIRECT_LIMIT) {
llcache_event event;
 
LOG(("Too many nested redirects"));
 
event.type = LLCACHE_EVENT_ERROR;
event.data.msg = messages_get("BadRedirect");
return llcache_send_event_to_users(object, &event);
}
#undef REDIRECT_LIMIT
 
/* Make target absolute */
error = nsurl_join(object->url, target, &url);
if (error != NSERROR_OK)
return error;
 
/* Reject attempts to redirect from unvalidated to validated schemes
* A "validated" scheme is one over which we have some guarantee that
* the source is trustworthy. */
object_scheme = nsurl_get_component(object->url, NSURL_SCHEME);
scheme = nsurl_get_component(url, NSURL_SCHEME);
 
/* resource: and about: are allowed to redirect anywhere */
if ((lwc_string_isequal(object_scheme, llcache_resource_lwc,
&match) == lwc_error_ok && match == false) &&
(lwc_string_isequal(object_scheme, llcache_about_lwc,
&match) == lwc_error_ok && match == false)) {
/* file, about and resource are not valid redirect targets */
if ((lwc_string_isequal(object_scheme, llcache_file_lwc,
&match) == lwc_error_ok && match == true) ||
(lwc_string_isequal(object_scheme, llcache_about_lwc,
&match) == lwc_error_ok && match == true) ||
(lwc_string_isequal(object_scheme, llcache_resource_lwc,
&match) == lwc_error_ok && match == true)) {
lwc_string_unref(object_scheme);
lwc_string_unref(scheme);
nsurl_unref(url);
return NSERROR_OK;
}
}
 
lwc_string_unref(scheme);
lwc_string_unref(object_scheme);
 
/* Bail out if we've no way of handling this URL */
if (fetch_can_fetch(url) == false) {
nsurl_unref(url);
return NSERROR_OK;
}
 
if (http_code == 301 || http_code == 302 || http_code == 303) {
/* 301, 302, 303 redirects are all unconditional GET requests */
post = NULL;
} else if (http_code != 307 || post != NULL) {
/** \todo 300, 305, 307 with POST */
nsurl_unref(url);
return NSERROR_OK;
}
 
/* Attempt to fetch target URL */
error = llcache_object_retrieve(url, object->fetch.flags,
object->fetch.referer, post,
object->fetch.redirect_count + 1, &dest);
 
/* No longer require url */
nsurl_unref(url);
 
if (error != NSERROR_OK)
return error;
 
/* Move user(s) to replacement object */
for (user = object->users; user != NULL; user = next) {
next = user->next;
 
llcache_object_remove_user(object, user);
llcache_object_add_user(dest, user);
}
 
/* Dest is now our object */
*replacement = dest;
 
return NSERROR_OK;
}
 
/**
* Update an object's cache state
*
* \param object Object to update cache for
* \return NSERROR_OK.
*/
static nserror llcache_object_cache_update(llcache_object *object)
{
if (object->cache.date == 0)
object->cache.date = time(NULL);
 
return NSERROR_OK;
}
 
/**
* Handle FETCH_NOTMODIFIED event
*
* \param object Object to process
* \param replacement Pointer to location to receive replacement object
* \return NSERROR_OK.
*/
static nserror llcache_fetch_notmodified(llcache_object *object,
llcache_object **replacement)
{
/* There may be no candidate if the server erroneously responded
* to an unconditional request with a 304 Not Modified response.
* In this case, we simply retain the initial object, having
* invalidated it and marked it as complete.
*/
if (object->candidate != NULL) {
llcache_object_user *user, *next;
 
/* Move user(s) to candidate content */
for (user = object->users; user != NULL; user = next) {
next = user->next;
 
llcache_object_remove_user(object, user);
llcache_object_add_user(object->candidate, user);
}
 
/* Candidate is no longer a candidate for us */
object->candidate->candidate_count--;
 
/* Clone our cache control data into the candidate */
llcache_object_clone_cache_data(object, object->candidate,
false);
/* Bring candidate's cache data up to date */
llcache_object_cache_update(object->candidate);
/* Revert no-cache to normal, if required */
if (object->candidate->cache.no_cache ==
LLCACHE_VALIDATE_ONCE) {
object->candidate->cache.no_cache =
LLCACHE_VALIDATE_FRESH;
}
 
/* Candidate is now our object */
*replacement = object->candidate;
object->candidate = NULL;
} else {
/* There was no candidate: retain object */
*replacement = object;
}
 
/* Ensure fetch has stopped */
fetch_abort(object->fetch.fetch);
object->fetch.fetch = NULL;
 
/* Invalidate our cache-control data */
llcache_invalidate_cache_control_data(object);
 
/* Mark it complete */
object->fetch.state = LLCACHE_FETCH_COMPLETE;
 
/* Old object will be flushed from the cache on the next poll */
 
return NSERROR_OK;
}
 
/**
* Process a chunk of fetched data
*
* \param object Object being fetched
* \param data Data to process
* \param len Byte length of data
* \return NSERROR_OK on success, appropriate error otherwise.
*/
static nserror llcache_fetch_process_data(llcache_object *object, const uint8_t *data,
size_t len)
{
/* Resize source buffer if it's too small */
if (object->source_len + len >= object->source_alloc) {
const size_t new_len = object->source_len + len + 64 * 1024;
uint8_t *temp = realloc(object->source_data, new_len);
if (temp == NULL)
return NSERROR_NOMEM;
 
object->source_data = temp;
object->source_alloc = new_len;
}
 
/* Append this data chunk to source buffer */
memcpy(object->source_data + object->source_len, data, len);
object->source_len += len;
 
return NSERROR_OK;
}
 
/**
* Handle a query response
*
* \param proceed Whether to proceed with fetch
* \param cbpw Our context for query
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_query_handle_response(bool proceed, void *cbpw)
{
llcache_event event;
llcache_object *object = cbpw;
 
object->fetch.outstanding_query = false;
 
/* Refetch, using existing fetch parameters, if client allows us to */
if (proceed)
return llcache_object_refetch(object);
 
/* Invalidate cache-control data */
llcache_invalidate_cache_control_data(object);
 
/* Mark it complete */
object->fetch.state = LLCACHE_FETCH_COMPLETE;
 
/* Inform client(s) that object fetch failed */
event.type = LLCACHE_EVENT_ERROR;
/** \todo More appropriate error message */
event.data.msg = messages_get("FetchFailed");
return llcache_send_event_to_users(object, &event);
}
 
/**
* Handle an authentication request
*
* \param object Object being fetched
* \param realm Authentication realm
* \return NSERROR_OK on success, appropriate error otherwise.
*/
static nserror llcache_fetch_auth(llcache_object *object, const char *realm)
{
const char *auth;
nserror error = NSERROR_OK;
 
/* Abort fetch for this object */
fetch_abort(object->fetch.fetch);
object->fetch.fetch = NULL;
 
/* Invalidate cache-control data */
llcache_invalidate_cache_control_data(object);
 
/* Destroy headers */
llcache_destroy_headers(object);
 
/* If there was no realm, then default to the URL */
/** \todo If there was no WWW-Authenticate header, use response body */
if (realm == NULL)
realm = nsurl_access(object->url);
 
auth = urldb_get_auth_details(object->url, realm);
 
if (auth == NULL || object->fetch.tried_with_auth == true) {
/* No authentication details, or tried what we had, so ask */
object->fetch.tried_with_auth = false;
 
if (llcache->query_cb != NULL) {
llcache_query query;
 
/* Emit query for authentication details */
query.type = LLCACHE_QUERY_AUTH;
query.url = object->url;
query.data.auth.realm = realm;
 
object->fetch.outstanding_query = true;
 
error = llcache->query_cb(&query, llcache->query_cb_pw,
llcache_query_handle_response, object);
} else {
llcache_event event;
 
/* Mark object complete */
object->fetch.state = LLCACHE_FETCH_COMPLETE;
 
/* Inform client(s) that object fetch failed */
event.type = LLCACHE_EVENT_ERROR;
/** \todo More appropriate error message */
event.data.msg = messages_get("FetchFailed");
error = llcache_send_event_to_users(object, &event);
}
} else {
/* Flag that we've tried to refetch with credentials, so
* that if the fetch fails again, we ask the user again */
object->fetch.tried_with_auth = true;
error = llcache_object_refetch(object);
}
 
return error;
}
 
/**
* Handle a TLS certificate verification failure
*
* \param object Object being fetched
* \param certs Certificate chain
* \param num Number of certificates in chain
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_fetch_cert_error(llcache_object *object,
const struct ssl_cert_info *certs, size_t num)
{
nserror error = NSERROR_OK;
 
/* Fetch has been stopped, and destroyed. Invalidate object's pointer */
object->fetch.fetch = NULL;
 
/* Invalidate cache-control data */
llcache_invalidate_cache_control_data(object);
 
if (llcache->query_cb != NULL) {
llcache_query query;
 
/* Emit query for TLS */
query.type = LLCACHE_QUERY_SSL;
query.url = object->url;
query.data.ssl.certs = certs;
query.data.ssl.num = num;
 
object->fetch.outstanding_query = true;
 
error = llcache->query_cb(&query, llcache->query_cb_pw,
llcache_query_handle_response, object);
} else {
llcache_event event;
 
/* Mark object complete */
object->fetch.state = LLCACHE_FETCH_COMPLETE;
 
/* Inform client(s) that object fetch failed */
event.type = LLCACHE_EVENT_ERROR;
/** \todo More appropriate error message */
event.data.msg = messages_get("FetchFailed");
error = llcache_send_event_to_users(object, &event);
}
 
return error;
}
 
/**
* Handle a TLS connection setup failure
*
* \param object Object being fetched
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_fetch_ssl_error(llcache_object *object)
{
nserror error = NSERROR_OK;
 
/* Fetch has been stopped, and destroyed. Invalidate object's pointer */
object->fetch.fetch = NULL;
 
/* Invalidate cache-control data */
llcache_invalidate_cache_control_data(object);
 
if (object->fetch.tried_with_tls_downgrade == true) {
/* Have already tried to downgrade, so give up */
llcache_event event;
 
/* Mark object complete */
object->fetch.state = LLCACHE_FETCH_COMPLETE;
 
/* Inform client(s) that object fetch failed */
event.type = LLCACHE_EVENT_ERROR;
/** \todo More appropriate error message */
event.data.msg = messages_get("FetchFailed");
error = llcache_send_event_to_users(object, &event);
} else {
/* Flag that we've tried to downgrade, so that if the
* fetch fails again, we give up */
object->fetch.tried_with_tls_downgrade = true;
error = llcache_object_refetch(object);
}
 
return error;
}
 
/**
* Handler for fetch events
*
* \param msg Fetch event
* \param p Our private data
*/
static void llcache_fetch_callback(const fetch_msg *msg, void *p)
{
nserror error = NSERROR_OK;
llcache_object *object = p;
llcache_event event;
 
#ifdef LLCACHE_TRACE
LOG(("Fetch event %d for %p", msg->type, object));
#endif
 
switch (msg->type) {
case FETCH_HEADER:
/* Received a fetch header */
object->fetch.state = LLCACHE_FETCH_HEADERS;
 
error = llcache_fetch_process_header(object,
msg->data.header_or_data.buf,
msg->data.header_or_data.len);
break;
 
/* 3xx responses */
case FETCH_REDIRECT:
/* Request resulted in a redirect */
 
/* Release candidate, if any */
if (object->candidate != NULL) {
object->candidate->candidate_count--;
object->candidate = NULL;
}
 
error = llcache_fetch_redirect(object,
msg->data.redirect, &object);
break;
case FETCH_NOTMODIFIED:
/* Conditional request determined that cached object is fresh */
error = llcache_fetch_notmodified(object, &object);
break;
 
/* Normal 2xx state machine */
case FETCH_DATA:
/* Received some data */
if (object->fetch.state != LLCACHE_FETCH_DATA) {
/* On entry into this state, check if we need to
* invalidate the cache control data. We are guaranteed
* to have received all response headers.
*
* There are two cases in which we want to suppress
* cacheing of an object:
*
* 1) The HTTP response code is not 200 or 203
* 2) The request URI had a query string and the
* response headers did not provide an explicit
* object expiration time.
*/
long http_code = fetch_http_code(object->fetch.fetch);
 
if ((http_code != 200 && http_code != 203) ||
(object->has_query &&
(object->cache.max_age == INVALID_AGE &&
object->cache.expires == 0))) {
/* Invalidate cache control data */
llcache_invalidate_cache_control_data(object);
}
 
/* Release candidate, if any */
if (object->candidate != NULL) {
object->candidate->candidate_count--;
object->candidate = NULL;
}
}
 
object->fetch.state = LLCACHE_FETCH_DATA;
 
error = llcache_fetch_process_data(object,
msg->data.header_or_data.buf,
msg->data.header_or_data.len);
break;
case FETCH_FINISHED:
/* Finished fetching */
{
uint8_t *temp;
 
object->fetch.state = LLCACHE_FETCH_COMPLETE;
object->fetch.fetch = NULL;
 
/* Shrink source buffer to required size */
temp = realloc(object->source_data,
object->source_len);
/* If source_len is 0, then temp may be NULL */
if (temp != NULL || object->source_len == 0) {
object->source_data = temp;
object->source_alloc = object->source_len;
}
 
llcache_object_cache_update(object);
}
break;
 
/* Out-of-band information */
case FETCH_ERROR:
/* An error occurred while fetching */
/* The fetch has has already been cleaned up by the fetcher */
object->fetch.state = LLCACHE_FETCH_COMPLETE;
object->fetch.fetch = NULL;
 
/* Release candidate, if any */
if (object->candidate != NULL) {
object->candidate->candidate_count--;
object->candidate = NULL;
}
 
/* Invalidate cache control data */
llcache_invalidate_cache_control_data(object);
 
/** \todo Consider using errorcode for something */
 
event.type = LLCACHE_EVENT_ERROR;
event.data.msg = msg->data.error;
error = llcache_send_event_to_users(object, &event);
break;
case FETCH_PROGRESS:
/* Progress update */
event.type = LLCACHE_EVENT_PROGRESS;
event.data.msg = msg->data.progress;
 
error = llcache_send_event_to_users(object, &event);
break;
 
/* Events requiring action */
case FETCH_AUTH:
/* Need Authentication */
 
/* Release candidate, if any */
if (object->candidate != NULL) {
object->candidate->candidate_count--;
object->candidate = NULL;
}
 
error = llcache_fetch_auth(object, msg->data.auth.realm);
break;
case FETCH_CERT_ERR:
/* Something went wrong when validating TLS certificates */
 
/* Release candidate, if any */
if (object->candidate != NULL) {
object->candidate->candidate_count--;
object->candidate = NULL;
}
 
error = llcache_fetch_cert_error(object,
msg->data.cert_err.certs,
msg->data.cert_err.num_certs);
break;
case FETCH_SSL_ERR:
/* TLS connection setup failed */
 
/* Release candidate, if any */
if (object->candidate != NULL) {
object->candidate->candidate_count--;
object->candidate = NULL;
}
 
error = llcache_fetch_ssl_error(object);
break;
}
 
/* Deal with any errors reported by event handlers */
if (error != NSERROR_OK) {
if (object->fetch.fetch != NULL) {
fetch_abort(object->fetch.fetch);
object->fetch.fetch = NULL;
 
/* Invalidate cache control data */
llcache_invalidate_cache_control_data(object);
 
object->fetch.state = LLCACHE_FETCH_COMPLETE;
}
return;
}
}
 
/**
* Find a user of a low-level cache object
*
* \param handle External cache handle to search for
* \return Pointer to corresponding user, or NULL if not found
*/
static llcache_object_user *llcache_object_find_user(const llcache_handle *handle)
{
llcache_object_user *user;
 
assert(handle->object != NULL);
 
for (user = handle->object->users; user != NULL; user = user->next) {
if (user->handle == handle)
break;
}
 
return user;
}
 
/**
* Remove a low-level cache object from a cache list
*
* \param object Object to remove
* \param list List to remove from
* \return NSERROR_OK
*/
static nserror llcache_object_remove_from_list(llcache_object *object,
llcache_object **list)
{
if (object == *list)
*list = object->next;
else
object->prev->next = object->next;
 
if (object->next != NULL)
object->next->prev = object->prev;
 
return NSERROR_OK;
}
 
/**
* Determine if a low-level cache object resides in a given list
*
* \param object Object to search for
* \param list List to search in
* \return True if object resides in list, false otherwise
*/
static bool llcache_object_in_list(const llcache_object *object,
const llcache_object *list)
{
while (list != NULL) {
if (list == object)
break;
 
list = list->next;
}
 
return list != NULL;
}
 
/**
* Notify users of an object's current state
*
* \param object Object to notify users about
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_object_notify_users(llcache_object *object)
{
nserror error;
llcache_object_user *user, *next_user;
llcache_event event;
 
#ifdef LLCACHE_TRACE
bool emitted_notify = false;
#endif
 
/**
* State transitions and event emission for users.
* Rows: user state. Cols: object state.
*
* User\Obj INIT HEADERS DATA COMPLETE
* INIT - T T* T*
* HEADERS - - T T*
* DATA - - M T
* COMPLETE - - - -
*
* T => transition user to object state
* M => no transition required, but may need to emit event
*
* The transitions marked with an asterisk can be removed by moving
* the user context into the subsequent state and then reevaluating.
*
* Events are issued as follows:
*
* HAD_HEADERS: on transition from HEADERS -> DATA state
* HAD_DATA : in DATA state, whenever there's new source data
* DONE : on transition from DATA -> COMPLETE state
*/
 
for (user = object->users; user != NULL; user = next_user) {
/* Emit necessary events to bring the user up-to-date */
llcache_handle *handle = user->handle;
const llcache_fetch_state objstate = object->fetch.state;
 
/* Flag that this user is the current iteration target
* in case the client attempts to destroy it underneath us */
user->iterator_target = true;
 
/* A note on the computation of next_user:
*
* Within this loop, we may make a number of calls to
* client code. Our contract with clients is that they
* can do whatever they like from within their callback
* handlers. This is so that we limit the pain of
* reentrancy to this module alone.
*
* One of the things a client can do from within its
* callback handler is to remove users from this object's
* user list. In the common case, the user they attempt
* to remove is the current iteration target, and we
* already protect against that causing problems here.
* However, no such protection exists if the client
* attempts to remove other users from this object's
* user list.
*
* Therefore, we cannot compute next_user up-front
* and expect it to remain valid across calls to
* client code (as the identity of the next user
* in the list may change underneath us). Instead,
* we must compute next_user at the point where we
* are about to cause another iteration of this loop
* (i.e. at the very end, and also at the points where
* continue is used)
*/
 
#ifdef LLCACHE_TRACE
if (handle->state != objstate) {
if (emitted_notify == false) {
LOG(("Notifying users of %p", object));
emitted_notify = true;
}
 
LOG(("User %p state: %d Object state: %d",
user, handle->state, objstate));
}
#endif
 
/* User: INIT, Obj: HEADERS, DATA, COMPLETE => User->HEADERS */
if (handle->state == LLCACHE_FETCH_INIT &&
objstate > LLCACHE_FETCH_INIT) {
handle->state = LLCACHE_FETCH_HEADERS;
}
 
/* User: HEADERS, Obj: DATA, COMPLETE => User->DATA */
if (handle->state == LLCACHE_FETCH_HEADERS &&
objstate > LLCACHE_FETCH_HEADERS) {
handle->state = LLCACHE_FETCH_DATA;
 
/* Emit HAD_HEADERS event */
event.type = LLCACHE_EVENT_HAD_HEADERS;
 
error = handle->cb(handle, &event, handle->pw);
 
if (user->queued_for_delete) {
next_user = user->next;
llcache_object_remove_user(object, user);
llcache_object_user_destroy(user);
 
if (error != NSERROR_OK)
return error;
 
continue;
} else if (error == NSERROR_NEED_DATA) {
/* User requested replay */
handle->state = LLCACHE_FETCH_HEADERS;
 
/* Continue with the next user -- we'll
* reemit the event next time round */
user->iterator_target = false;
next_user = user->next;
continue;
} else if (error != NSERROR_OK) {
user->iterator_target = false;
return error;
}
}
 
/* User: DATA, Obj: DATA, COMPLETE, more source available */
if (handle->state == LLCACHE_FETCH_DATA &&
objstate >= LLCACHE_FETCH_DATA &&
object->source_len > handle->bytes) {
size_t orig_handle_read;
 
/* Construct HAD_DATA event */
event.type = LLCACHE_EVENT_HAD_DATA;
event.data.data.buf =
object->source_data + handle->bytes;
event.data.data.len =
object->source_len - handle->bytes;
 
/* Update record of last byte emitted */
if (object->fetch.flags &
LLCACHE_RETRIEVE_STREAM_DATA) {
/* Streaming, so reset to zero to
* minimise amount of cached source data.
* Additionally, we don't support replay
* when streaming. */
orig_handle_read = 0;
handle->bytes = object->source_len = 0;
} else {
orig_handle_read = handle->bytes;
handle->bytes = object->source_len;
}
 
/* Emit event */
error = handle->cb(handle, &event, handle->pw);
if (user->queued_for_delete) {
next_user = user->next;
llcache_object_remove_user(object, user);
llcache_object_user_destroy(user);
 
if (error != NSERROR_OK)
return error;
 
continue;
} else if (error == NSERROR_NEED_DATA) {
/* User requested replay */
handle->bytes = orig_handle_read;
 
/* Continue with the next user -- we'll
* reemit the data next time round */
user->iterator_target = false;
next_user = user->next;
continue;
} else if (error != NSERROR_OK) {
user->iterator_target = false;
return error;
}
}
 
/* User: DATA, Obj: COMPLETE => User->COMPLETE */
if (handle->state == LLCACHE_FETCH_DATA &&
objstate > LLCACHE_FETCH_DATA) {
handle->state = LLCACHE_FETCH_COMPLETE;
 
/* Emit DONE event */
event.type = LLCACHE_EVENT_DONE;
 
error = handle->cb(handle, &event, handle->pw);
if (user->queued_for_delete) {
next_user = user->next;
llcache_object_remove_user(object, user);
llcache_object_user_destroy(user);
 
if (error != NSERROR_OK)
return error;
 
continue;
} else if (error == NSERROR_NEED_DATA) {
/* User requested replay */
handle->state = LLCACHE_FETCH_DATA;
 
/* Continue with the next user -- we'll
* reemit the event next time round */
user->iterator_target = false;
next_user = user->next;
continue;
} else if (error != NSERROR_OK) {
user->iterator_target = false;
return error;
}
}
 
/* No longer the target of an iterator */
user->iterator_target = false;
 
next_user = user->next;
}
 
return NSERROR_OK;
}
 
/**
* Make a snapshot of the current state of an llcache_object.
*
* This has the side-effect of the new object being non-cacheable,
* also not-fetching and not a candidate for any other object.
*
* Also note that this new object has no users and at least one
* should be assigned to it before llcache_clean is entered or it
* will be immediately cleaned up.
*
* \param object The object to take a snapshot of
* \param snapshot Pointer to receive snapshot of \a object
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror llcache_object_snapshot(llcache_object *object,
llcache_object **snapshot)
{
llcache_object *newobj;
nserror error;
error = llcache_object_new(object->url, &newobj);
if (error != NSERROR_OK)
return error;
newobj->has_query = object->has_query;
 
newobj->source_alloc = newobj->source_len = object->source_len;
if (object->source_len > 0) {
newobj->source_data = malloc(newobj->source_alloc);
if (newobj->source_data == NULL) {
llcache_object_destroy(newobj);
return NSERROR_NOMEM;
}
memcpy(newobj->source_data, object->source_data,
newobj->source_len);
}
if (object->num_headers > 0) {
newobj->headers = calloc(sizeof(llcache_header),
object->num_headers);
if (newobj->headers == NULL) {
llcache_object_destroy(newobj);
return NSERROR_NOMEM;
}
while (newobj->num_headers < object->num_headers) {
llcache_header *nh =
&(newobj->headers[newobj->num_headers]);
llcache_header *oh =
&(object->headers[newobj->num_headers]);
newobj->num_headers += 1;
nh->name = strdup(oh->name);
nh->value = strdup(oh->value);
if (nh->name == NULL || nh->value == NULL) {
llcache_object_destroy(newobj);
return NSERROR_NOMEM;
}
}
}
newobj->fetch.state = LLCACHE_FETCH_COMPLETE;
*snapshot = newobj;
return NSERROR_OK;
}
 
 
/******************************************************************************
* Public API *
******************************************************************************/
 
/**
* Attempt to clean the cache
*/
/* Exported interface documented in llcache.h */
void llcache_clean(void)
{
llcache_object *object, *next;
uint32_t llcache_size = 0;
int remaining_lifetime;
 
#ifdef LLCACHE_TRACE
LOG(("Attempting cache clean"));
#endif
 
/* Candidates for cleaning are (in order of priority):
*
* 1) Uncacheable objects with no users
* 2) Stale cacheable objects with no users or pending fetches
* 3) Fresh cacheable objects with no users or pending fetches
*/
 
/* 1) Uncacheable objects with no users or fetches */
for (object = llcache->uncached_objects; object != NULL; object = next) {
next = object->next;
 
/* The candidate count of uncacheable objects is always 0 */
if ((object->users == NULL) &&
(object->candidate_count == 0) &&
(object->fetch.fetch == NULL) &&
(object->fetch.outstanding_query == false)) {
#ifdef LLCACHE_TRACE
LOG(("Found victim %p", object));
#endif
llcache_object_remove_from_list(object,
&llcache->uncached_objects);
llcache_object_destroy(object);
} else {
llcache_size += object->source_len + sizeof(*object);
}
}
 
/* 2) Stale cacheable objects with no users or pending fetches */
for (object = llcache->cached_objects; object != NULL; object = next) {
next = object->next;
 
remaining_lifetime = llcache_object_rfc2616_remaining_lifetime(&object->cache);
 
if ((object->users == NULL) &&
(object->candidate_count == 0) &&
(object->fetch.fetch == NULL) &&
(object->fetch.outstanding_query == false)) {
 
if (remaining_lifetime > 0) {
/* object is fresh */
llcache_size += object->source_len + sizeof(*object);
} else {
/* object is not fresh */
#ifdef LLCACHE_TRACE
LOG(("Found stale cacheable object (%p) with no users or pending fetches", object));
#endif
llcache_object_remove_from_list(object,
&llcache->cached_objects);
llcache_object_destroy(object);
}
} else {
llcache_size += object->source_len + sizeof(*object);
}
}
 
/* 3) Fresh cacheable objects with no users or pending
* fetches, only if the cache exceeds the configured size.
*/
if (llcache->limit < llcache_size) {
for (object = llcache->cached_objects; object != NULL;
object = next) {
next = object->next;
 
if ((object->users == NULL) &&
(object->candidate_count == 0) &&
(object->fetch.fetch == NULL) &&
(object->fetch.outstanding_query == false)) {
#ifdef LLCACHE_TRACE
LOG(("Found victim %p", object));
#endif
llcache_size -=
object->source_len + sizeof(*object);
 
llcache_object_remove_from_list(object,
&llcache->cached_objects);
llcache_object_destroy(object);
}
}
}
 
#ifdef LLCACHE_TRACE
LOG(("Size: %u", llcache_size));
#endif
 
}
 
/* See llcache.h for documentation */
nserror
llcache_initialise(llcache_query_callback cb, void *pw, uint32_t llcache_limit)
{
llcache = calloc(1, sizeof(struct llcache_s));
if (llcache == NULL) {
return NSERROR_NOMEM;
}
 
llcache->query_cb = cb;
llcache->query_cb_pw = pw;
llcache->limit = llcache_limit;
 
/* Create static scheme strings */
if (lwc_intern_string("file", SLEN("file"),
&llcache_file_lwc) != lwc_error_ok)
return NSERROR_NOMEM;
 
if (lwc_intern_string("about", SLEN("about"),
&llcache_about_lwc) != lwc_error_ok)
return NSERROR_NOMEM;
 
if (lwc_intern_string("resource", SLEN("resource"),
&llcache_resource_lwc) != lwc_error_ok)
return NSERROR_NOMEM;
 
LOG(("llcache initialised with a limit of %d bytes", llcache_limit));
 
return NSERROR_OK;
}
 
/* See llcache.h for documentation */
void llcache_finalise(void)
{
llcache_object *object, *next;
 
/* Clean uncached objects */
for (object = llcache->uncached_objects; object != NULL; object = next) {
llcache_object_user *user, *next_user;
 
next = object->next;
 
for (user = object->users; user != NULL; user = next_user) {
next_user = user->next;
 
if (user->handle != NULL)
free(user->handle);
 
free(user);
}
 
/* Fetch system has already been destroyed */
object->fetch.fetch = NULL;
 
llcache_object_destroy(object);
}
 
/* Clean cached objects */
for (object = llcache->cached_objects; object != NULL; object = next) {
llcache_object_user *user, *next_user;
 
next = object->next;
 
for (user = object->users; user != NULL; user = next_user) {
next_user = user->next;
 
if (user->handle != NULL)
free(user->handle);
 
free(user);
}
 
/* Fetch system has already been destroyed */
object->fetch.fetch = NULL;
 
llcache_object_destroy(object);
}
 
/* Unref static scheme lwc strings */
lwc_string_unref(llcache_file_lwc);
lwc_string_unref(llcache_about_lwc);
lwc_string_unref(llcache_resource_lwc);
 
free(llcache);
llcache = NULL;
}
 
/* See llcache.h for documentation */
nserror llcache_poll(void)
{
llcache_object *object;
fetch_poll();
/* Catch new users up with state of objects */
for (object = llcache->cached_objects; object != NULL;
object = object->next) {
llcache_object_notify_users(object);
}
 
for (object = llcache->uncached_objects; object != NULL;
object = object->next) {
llcache_object_notify_users(object);
}
 
return NSERROR_OK;
}
 
/* See llcache.h for documentation */
nserror llcache_handle_retrieve(nsurl *url, uint32_t flags,
nsurl *referer, const llcache_post_data *post,
llcache_handle_callback cb, void *pw,
llcache_handle **result)
{
nserror error;
llcache_object_user *user;
llcache_object *object;
 
/* Can we fetch this URL at all? */
if (fetch_can_fetch(url) == false)
return NSERROR_NO_FETCH_HANDLER;
 
/* Create a new object user */
error = llcache_object_user_new(cb, pw, &user);
if (error != NSERROR_OK)
return error;
 
/* Retrieve a suitable object from the cache,
* creating a new one if needed. */
error = llcache_object_retrieve(url, flags, referer, post, 0, &object);
if (error != NSERROR_OK) {
llcache_object_user_destroy(user);
return error;
}
 
/* Add user to object */
llcache_object_add_user(object, user);
 
*result = user->handle;
 
return NSERROR_OK;
}
 
/* See llcache.h for documentation */
nserror llcache_handle_change_callback(llcache_handle *handle,
llcache_handle_callback cb, void *pw)
{
handle->cb = cb;
handle->pw = pw;
 
return NSERROR_OK;
}
 
/* See llcache.h for documentation */
nserror llcache_handle_release(llcache_handle *handle)
{
nserror error = NSERROR_OK;
llcache_object *object = handle->object;
llcache_object_user *user = llcache_object_find_user(handle);
 
assert(user != NULL);
 
if (user->iterator_target) {
/* Can't remove / delete user object if it's
* the target of an iterator */
user->queued_for_delete = true;
} else {
/* Remove the user from the object and destroy it */
error = llcache_object_remove_user(object, user);
if (error == NSERROR_OK) {
error = llcache_object_user_destroy(user);
}
}
return error;
}
 
/* See llcache.h for documentation */
nserror llcache_handle_clone(llcache_handle *handle, llcache_handle **result)
{
nserror error;
llcache_object_user *newuser;
error = llcache_object_user_new(handle->cb, handle->pw, &newuser);
if (error == NSERROR_OK) {
llcache_object_add_user(handle->object, newuser);
newuser->handle->state = handle->state;
*result = newuser->handle;
}
return error;
}
 
/* See llcache.h for documentation */
nserror llcache_handle_abort(llcache_handle *handle)
{
llcache_object_user *user = llcache_object_find_user(handle);
llcache_object *object = handle->object, *newobject;
nserror error = NSERROR_OK;
bool all_alone = true;
/* Determine if we are the only user */
if (user->prev != NULL)
all_alone = false;
if (user->next != NULL)
all_alone = false;
if (all_alone == false) {
/* We must snapshot this object */
error = llcache_object_snapshot(object, &newobject);
if (error != NSERROR_OK)
return error;
 
/* Move across to the new object */
if (user->iterator_target) {
/* User is current iterator target, clone it */
llcache_object_user *newuser =
calloc(1, sizeof(llcache_object_user));
if (newuser == NULL) {
llcache_object_destroy(newobject);
return NSERROR_NOMEM;
}
 
/* Move handle across to clone */
newuser->handle = user->handle;
user->handle = NULL;
 
/* Mark user as needing deletion */
user->queued_for_delete = true;
 
llcache_object_add_user(newobject, newuser);
} else {
llcache_object_remove_user(object, user);
llcache_object_add_user(newobject, user);
}
/* Add new object to uncached list */
llcache_object_add_to_list(newobject,
&llcache->uncached_objects);
} else {
/* We're the only user, so abort any fetch in progress */
if (object->fetch.fetch != NULL) {
fetch_abort(object->fetch.fetch);
object->fetch.fetch = NULL;
}
object->fetch.state = LLCACHE_FETCH_COMPLETE;
/* Invalidate cache control data */
llcache_invalidate_cache_control_data(object);
}
return error;
}
 
/* See llcache.h for documentation */
nserror llcache_handle_force_stream(llcache_handle *handle)
{
llcache_object_user *user = llcache_object_find_user(handle);
llcache_object *object = handle->object;
 
/* Cannot stream if there are multiple users */
if (user->prev != NULL || user->next != NULL)
return NSERROR_OK;
 
/* Forcibly uncache this object */
if (llcache_object_in_list(object, llcache->cached_objects)) {
llcache_object_remove_from_list(object,
&llcache->cached_objects);
llcache_object_add_to_list(object, &llcache->uncached_objects);
}
 
object->fetch.flags |= LLCACHE_RETRIEVE_STREAM_DATA;
 
return NSERROR_OK;
}
 
/* See llcache.h for documentation */
nserror llcache_handle_invalidate_cache_data(llcache_handle *handle)
{
if (handle->object != NULL && handle->object->fetch.fetch == NULL &&
handle->object->cache.no_cache ==
LLCACHE_VALIDATE_FRESH) {
handle->object->cache.no_cache = LLCACHE_VALIDATE_ONCE;
}
 
return NSERROR_OK;
}
 
/* See llcache.h for documentation */
nsurl *llcache_handle_get_url(const llcache_handle *handle)
{
return handle->object != NULL ? handle->object->url : NULL;
}
 
/* See llcache.h for documentation */
const uint8_t *llcache_handle_get_source_data(const llcache_handle *handle,
size_t *size)
{
*size = handle->object != NULL ? handle->object->source_len : 0;
 
return handle->object != NULL ? handle->object->source_data : NULL;
}
 
/* See llcache.h for documentation */
const char *llcache_handle_get_header(const llcache_handle *handle,
const char *key)
{
const llcache_object *object = handle->object;
size_t i;
 
if (object == NULL)
return NULL;
 
/* About as trivial as possible */
for (i = 0; i < object->num_headers; i++) {
if (strcasecmp(key, object->headers[i].name) == 0)
return object->headers[i].value;
}
 
return NULL;
}
 
/* See llcache.h for documentation */
bool llcache_handle_references_same_object(const llcache_handle *a,
const llcache_handle *b)
{
return a->object == b->object;
}
 
/programs/network/netsurf/netsurf/content/llcache.h
0,0 → 1,295
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Low-level resource cache (interface)
*/
 
#ifndef NETSURF_CONTENT_LLCACHE_H_
#define NETSURF_CONTENT_LLCACHE_H_
 
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
 
#include "utils/errors.h"
#include "utils/nsurl.h"
 
struct ssl_cert_info;
struct fetch_multipart_data;
 
/** Handle for low-level cache object */
typedef struct llcache_handle llcache_handle;
 
/** POST data object for low-level cache requests */
typedef struct {
enum {
LLCACHE_POST_URL_ENCODED,
LLCACHE_POST_MULTIPART
} type; /**< Type of POST data */
union {
char *urlenc; /**< URL encoded data */
struct fetch_multipart_data *multipart; /**< Multipart data */
} data; /**< POST data content */
} llcache_post_data;
 
/** Low-level cache event types */
typedef enum {
LLCACHE_EVENT_HAD_HEADERS, /**< Received all headers */
LLCACHE_EVENT_HAD_DATA, /**< Received some data */
LLCACHE_EVENT_DONE, /**< Finished fetching data */
 
LLCACHE_EVENT_ERROR, /**< An error occurred during fetch */
LLCACHE_EVENT_PROGRESS, /**< Fetch progress update */
} llcache_event_type;
 
/** Low-level cache events */
typedef struct {
llcache_event_type type; /**< Type of event */
union {
struct {
const uint8_t *buf; /**< Buffer of data */
size_t len; /**< Length of buffer, in bytes */
} data; /**< Received data */
const char *msg; /**< Error or progress message */
} data; /**< Event data */
} llcache_event;
 
/**
* Client callback for low-level cache events
*
* \param handle Handle for which event is issued
* \param event Event data
* \param pw Pointer to client-specific data
* \return NSERROR_OK on success, appropriate error otherwise.
*/
typedef nserror (*llcache_handle_callback)(llcache_handle *handle,
const llcache_event *event, void *pw);
 
/** Flags for low-level cache object retrieval */
enum llcache_retrieve_flag {
/* Note: We're permitted a maximum of 16 flags which must reside in the
* bottom 16 bits of the flags word. See hlcache.h for further details.
*/
/** Force a new fetch */
LLCACHE_RETRIEVE_FORCE_FETCH = (1 << 0),
/** Requested URL was verified */
LLCACHE_RETRIEVE_VERIFIABLE = (1 << 1),
/**< No error pages */
LLCACHE_RETRIEVE_NO_ERROR_PAGES = (1 << 2),
/**< Stream data (implies that object is not cacheable) */
LLCACHE_RETRIEVE_STREAM_DATA = (1 << 3)
};
 
/** Low-level cache query types */
typedef enum {
LLCACHE_QUERY_AUTH, /**< Need authentication details */
LLCACHE_QUERY_REDIRECT, /**< Need permission to redirect */
LLCACHE_QUERY_SSL /**< SSL chain needs inspection */
} llcache_query_type;
 
/** Low-level cache query */
typedef struct {
llcache_query_type type; /**< Type of query */
 
nsurl *url; /**< URL being fetched */
 
union {
struct {
const char *realm; /**< Authentication realm */
} auth;
 
struct {
const char *target; /**< Redirect target */
} redirect;
 
struct {
const struct ssl_cert_info *certs;
size_t num; /**< Number of certs in chain */
} ssl;
} data;
} llcache_query;
 
/**
* Response handler for fetch-related queries
*
* \param proceed Whether to proceed with the fetch or not
* \param cbpw Opaque value provided to llcache_query_callback
* \return NSERROR_OK on success, appropriate error otherwise
*/
typedef nserror (*llcache_query_response)(bool proceed, void *cbpw);
 
/**
* Callback to handle fetch-related queries
*
* \param query Object containing details of query
* \param pw Pointer to callback-specific data
* \param cb Callback that client should call once query is satisfied
* \param cbpw Opaque value to pass into \a cb
* \return NSERROR_OK on success, appropriate error otherwise
*
* \note This callback should return immediately. Once a suitable answer to
* the query has been obtained, the provided response callback should be
* called. This is intended to be an entirely asynchronous process.
*/
typedef nserror (*llcache_query_callback)(const llcache_query *query, void *pw,
llcache_query_response cb, void *cbpw);
 
/**
* Initialise the low-level cache
*
* \param cb Query handler
* \param pw Pointer to query handler data
* \return NSERROR_OK on success, appropriate error otherwise.
*/
nserror llcache_initialise(llcache_query_callback cb, void *pw, uint32_t llcache_limit);
 
/**
* Finalise the low-level cache
*/
void llcache_finalise(void);
 
/**
* Cause the low-level cache to emit any pending notifications.
*
* \return NSERROR_OK on success, appropriate error otherwise.
*/
nserror llcache_poll(void);
 
/**
* Cause the low-level cache to attempt to perform cleanup. No
* guarantees are made as to whether or not cleanups will take
* place and what, if any, space savings will be made.
*/
void llcache_clean(void);
 
/**
* Retrieve a handle for a low-level cache object
*
* \param url URL of the object to fetch
* \param flags Object retrieval flags
* \param referer Referring URL, or NULL if none
* \param post POST data, or NULL for a GET request
* \param cb Client callback for events
* \param pw Pointer to client-specific data
* \param result Pointer to location to recieve cache handle
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror llcache_handle_retrieve(nsurl *url, uint32_t flags,
nsurl *referer, const llcache_post_data *post,
llcache_handle_callback cb, void *pw,
llcache_handle **result);
 
/**
* Change the callback associated with a low-level cache handle
*
* \param handle Handle to change callback of
* \param cb New callback
* \param pw Client data for new callback
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror llcache_handle_change_callback(llcache_handle *handle,
llcache_handle_callback cb, void *pw);
 
/**
* Release a low-level cache handle
*
* \param handle Handle to release
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror llcache_handle_release(llcache_handle *handle);
 
/**
* Clone a low-level cache handle, producing a new handle to
* the same fetch/content.
*
* \param handle Handle to clone
* \param result Pointer to location to receive cloned handle
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror llcache_handle_clone(llcache_handle *handle, llcache_handle **result);
 
/**
* Abort a low-level fetch, informing all users of this action.
*
* \param handle Handle to abort
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror llcache_handle_abort(llcache_handle *handle);
 
/**
* Force a low-level cache handle into streaming mode
*
* \param handle Handle to stream
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror llcache_handle_force_stream(llcache_handle *handle);
 
/**
* Invalidate cache data for a low-level cache object
*
* \param handle Handle to invalidate
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror llcache_handle_invalidate_cache_data(llcache_handle *handle);
 
/**
* Retrieve the post-redirect URL of a low-level cache object
*
* \param handle Handle to retrieve URL from
* \return Post-redirect URL of cache object
*/
nsurl *llcache_handle_get_url(const llcache_handle *handle);
 
/**
* Retrieve source data of a low-level cache object
*
* \param handle Handle to retrieve source data from
* \param size Pointer to location to receive byte length of data
* \return Pointer to source data
*/
const uint8_t *llcache_handle_get_source_data(const llcache_handle *handle,
size_t *size);
 
/**
* Retrieve a header value associated with a low-level cache object
*
* \param handle Handle to retrieve header from
* \param key Header name
* \return Header value, or NULL if header does not exist
*
* \todo Make the key an enumeration, to avoid needless string comparisons
* \todo Forcing the client to parse the header value seems wrong.
* Better would be to return the actual value part and an array of
* key-value pairs for any additional parameters.
* \todo Deal with multiple headers of the same key (e.g. Set-Cookie)
*/
const char *llcache_handle_get_header(const llcache_handle *handle,
const char *key);
 
/**
* Determine if the same underlying object is referenced by the given handles
*
* \param a First handle
* \param b Second handle
* \return True if handles reference the same object, false otherwise
*/
bool llcache_handle_references_same_object(const llcache_handle *a,
const llcache_handle *b);
 
#endif
/programs/network/netsurf/netsurf/content/make.content
0,0 → 1,22
CFLAGS += -O2
NETSURF_FB_FRONTEND := sdl
NETSURF_FB_FONTLIB := internal
 
NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
 
# Default resource install path
NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
 
# Default framebuffer search path
NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
 
# freetype compiled in font serch path
NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
OBJS := content.o content_factory.o dirlist.o fetch.o hlcache.o \
llcache.o mimesniff.o urldb.o
 
 
OUTFILE = cont.o
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include
include $(MENUETDEV)/makefiles/Makefile_for_o_lib
/programs/network/netsurf/netsurf/content/mimesniff.c
0,0 → 1,778
/*
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* MIME type sniffer (implementation)
*
* Spec version: 2011-11-27
*/
 
#include<string.h>
 
#include "content/content_factory.h"
#include "content/llcache.h"
#include "content/mimesniff.h"
#include "utils/http.h"
#include "utils/utils.h"
 
struct map_s {
const uint8_t *sig;
size_t len;
bool safe;
lwc_string **type;
};
 
static lwc_string *unknown_unknown;
static lwc_string *application_unknown;
static lwc_string *any;
static lwc_string *text_xml;
static lwc_string *application_xml;
static lwc_string *text_html;
static lwc_string *text_plain;
static lwc_string *application_octet_stream;
static lwc_string *image_gif;
static lwc_string *image_png;
static lwc_string *image_jpeg;
static lwc_string *image_bmp;
static lwc_string *image_vnd_microsoft_icon;
static lwc_string *image_webp;
static lwc_string *application_rss_xml;
static lwc_string *application_atom_xml;
static lwc_string *audio_wave;
static lwc_string *application_ogg;
static lwc_string *video_webm;
static lwc_string *application_x_rar_compressed;
static lwc_string *application_zip;
static lwc_string *application_x_gzip;
static lwc_string *application_postscript;
static lwc_string *application_pdf;
static lwc_string *video_mp4;
static lwc_string *image_svg;
 
nserror mimesniff_init(void)
{
lwc_error lerror;
 
#define SINIT(v, s) \
lerror = lwc_intern_string(s, SLEN(s), &v); \
if (lerror != lwc_error_ok) \
return NSERROR_NOMEM
 
SINIT(unknown_unknown, "unknown/unknown");
SINIT(application_unknown, "application/unknown");
SINIT(any, "*/*");
SINIT(text_xml, "text/xml");
SINIT(application_xml, "application/xml");
SINIT(text_html, "text/html");
SINIT(text_plain, "text/plain");
SINIT(application_octet_stream, "application/octet-stream");
SINIT(image_gif, "image/gif");
SINIT(image_png, "image/png");
SINIT(image_jpeg, "image/jpeg");
SINIT(image_bmp, "image/bmp");
SINIT(image_vnd_microsoft_icon, "image/vnd.microsoft.icon");
SINIT(image_webp, "image/webp");
SINIT(application_rss_xml, "application/rss+xml");
SINIT(application_atom_xml, "application/atom+xml");
SINIT(audio_wave, "audio/wave");
SINIT(application_ogg, "application/ogg");
SINIT(video_webm, "video/webm");
SINIT(application_x_rar_compressed, "application/x-rar-compressed");
SINIT(application_zip, "application/zip");
SINIT(application_x_gzip, "application/x-gzip");
SINIT(application_postscript, "application/postscript");
SINIT(application_pdf, "application/pdf");
SINIT(video_mp4, "video/mp4");
SINIT(image_svg, "image/svg+xml");
#undef SINIT
 
return NSERROR_OK;
}
 
void mimesniff_fini(void)
{
lwc_string_unref(image_svg);
lwc_string_unref(video_mp4);
lwc_string_unref(application_pdf);
lwc_string_unref(application_postscript);
lwc_string_unref(application_x_gzip);
lwc_string_unref(application_zip);
lwc_string_unref(application_x_rar_compressed);
lwc_string_unref(video_webm);
lwc_string_unref(application_ogg);
lwc_string_unref(audio_wave);
lwc_string_unref(application_atom_xml);
lwc_string_unref(application_rss_xml);
lwc_string_unref(image_webp);
lwc_string_unref(image_vnd_microsoft_icon);
lwc_string_unref(image_bmp);
lwc_string_unref(image_jpeg);
lwc_string_unref(image_png);
lwc_string_unref(image_gif);
lwc_string_unref(application_octet_stream);
lwc_string_unref(text_plain);
lwc_string_unref(text_html);
lwc_string_unref(application_xml);
lwc_string_unref(text_xml);
lwc_string_unref(any);
lwc_string_unref(application_unknown);
lwc_string_unref(unknown_unknown);
}
 
static bool mimesniff__has_binary_octets(const uint8_t *data, size_t len)
{
const uint8_t *end = data + len;
 
while (data != end) {
const uint8_t c = *data;
 
/* Binary iff in C0 and not ESC, CR, FF, LF, HT */
if (c <= 0x1f && c != 0x1b && c != '\r' && c != '\f' &&
c != '\n' && c != '\t')
break;
 
data++;
}
 
return data != end;
}
 
static nserror mimesniff__match_mp4(const uint8_t *data, size_t len,
lwc_string **effective_type)
{
size_t box_size, i;
 
/* ISO/IEC 14496-12:2008 $4.3 says (effectively):
*
* struct ftyp_box {
* uint32_t size; (in octets, including size+type words)
* uint32_t type; (== 'ftyp')
* uint32_t major_brand;
* uint32_t minor_version;
* uint32_t compatible_brands[];
* }
*
* Note 1: A size of 0 implies that the length of the box is designated
* by the remaining input data (and thus may only occur in the last
* box in the input). We'll reject this below, as it's pointless
* sniffing input that contains no boxes other than 'ftyp'.
*
* Note 2: A size of 1 implies an additional uint64_t field after
* the type which contains the extended box size. We'll reject this,
* too, as it implies a minimum of (2^32 - 24) / 4 compatible brands,
* which is decidely unlikely.
*/
 
/* 12 reflects the minimum number of octets needed to sniff useful
* information out of an 'ftyp' box (i.e. the size, type,
* and major_brand words). */
if (len < 12)
return NSERROR_NOT_FOUND;
 
/* Box size is big-endian */
box_size = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
 
/* Require that we can read the entire box, and reject bad box sizes */
if (len < box_size || box_size % 4 != 0)
return NSERROR_NOT_FOUND;
 
/* Ensure this is an 'ftyp' box */
if (data[4] != 'f' || data[5] != 't' ||
data[6] != 'y' || data[7] != 'p')
return NSERROR_NOT_FOUND;
 
/* Check if major brand begins with 'mp4' */
if (data[8] == 'm' && data[9] == 'p' && data[10] == '4') {
*effective_type = lwc_string_ref(video_mp4);
return NSERROR_OK;
}
 
/* Search each compatible brand in the box for "mp4" */
for (i = 16; i <= box_size - 4; i += 4) {
if (data[i] == 'm' && data[i+1] == 'p' && data[i+2] == '4') {
*effective_type = lwc_string_ref(video_mp4);
return NSERROR_OK;
}
}
 
return NSERROR_NOT_FOUND;
}
 
static nserror mimesniff__match_unknown_ws(const uint8_t *data, size_t len,
lwc_string **effective_type)
{
#define SIG(t, s, x) { (const uint8_t *) s, SLEN(s), x, t }
static const struct map_s ws_exact_match_types[] = {
SIG(&text_xml, "<?xml", false),
{ NULL, 0, false, NULL }
};
 
static const struct map_s ws_inexact_match_types[] = {
SIG(&text_html, "<!DOCTYPE HTML", false),
SIG(&text_html, "<HTML", false),
SIG(&text_html, "<HEAD", false),
SIG(&text_html, "<SCRIPT", false),
SIG(&text_html, "<IFRAME", false),
SIG(&text_html, "<H1", false),
SIG(&text_html, "<DIV", false),
SIG(&text_html, "<FONT", false),
SIG(&text_html, "<TABLE", false),
SIG(&text_html, "<A", false),
SIG(&text_html, "<STYLE", false),
SIG(&text_html, "<TITLE", false),
SIG(&text_html, "<B", false),
SIG(&text_html, "<BODY", false),
SIG(&text_html, "<BR", false),
SIG(&text_html, "<P", false),
SIG(&text_html, "<!--", false),
{ NULL, 0, false, NULL }
};
#undef SIG
const uint8_t *end = data + len;
const struct map_s *it;
 
/* Skip leading whitespace */
while (data != end) {
const uint8_t c = *data;
 
if (c != '\t' && c != '\n' && c != '\f' &&
c != '\r' && c != ' ')
break;
 
data++;
}
 
if (data == end)
return NSERROR_NOT_FOUND;
 
len = end - data;
 
for (it = ws_exact_match_types; it->sig != NULL; it++) {
if (it->len <= len && memcmp(data, it->sig, it->len) == 0) {
*effective_type = lwc_string_ref(*it->type);
return NSERROR_OK;
}
}
 
for (it = ws_inexact_match_types; it->sig != NULL; it++) {
/* +1 for trailing space or > */
if (len < it->len + 1)
continue;
 
if (strncasecmp((const char *) data,
(const char *) it->sig, it->len) == 0 &&
(data[it->len] == ' ' ||
data[it->len] == '>')) {
*effective_type = lwc_string_ref(*it->type);
return NSERROR_OK;
}
}
 
return NSERROR_NOT_FOUND;
}
 
static nserror mimesniff__match_unknown_bom(const uint8_t *data, size_t len,
lwc_string **effective_type)
{
#define SIG(t, s, x) { (const uint8_t *) s, SLEN(s), x, t }
static const struct map_s bom_match_types[] = {
SIG(&text_plain, "\xfe\xff", false),
SIG(&text_plain, "\xff\xfe", false),
SIG(&text_plain, "\xef\xbb\xbf", false),
{ NULL, 0, false, NULL }
};
#undef SIG
const struct map_s *it;
 
for (it = bom_match_types; it->sig != NULL; it++) {
if (it->len <= len && memcmp(data, it->sig, it->len) == 0) {
*effective_type = lwc_string_ref(*it->type);
return NSERROR_OK;
}
}
 
return NSERROR_NOT_FOUND;
}
 
static nserror mimesniff__match_unknown_riff(const uint8_t *data, size_t len,
lwc_string **effective_type)
{
#define SIG(t, s, x) { (const uint8_t *) s, SLEN(s), x, t }
static const struct map_s riff_match_types[] = {
SIG(&image_webp, "WEBPVP", true),
SIG(&audio_wave, "WAVE", true),
{ NULL, 0, false, NULL }
};
#undef SIG
const struct map_s *it;
 
for (it = riff_match_types; it->sig != NULL; it++) {
if (it->len + SLEN("RIFF????") <= len &&
memcmp(data, "RIFF", SLEN("RIFF")) == 0 &&
memcmp(data + SLEN("RIFF????"),
it->sig, it->len) == 0) {
*effective_type = lwc_string_ref(*it->type);
return NSERROR_OK;
}
}
 
return NSERROR_NOT_FOUND;
}
 
static nserror mimesniff__match_unknown_exact(const uint8_t *data, size_t len,
bool allow_unsafe, lwc_string **effective_type)
{
#define SIG(t, s, x) { (const uint8_t *) s, SLEN(s), x, t }
static const struct map_s exact_match_types[] = {
SIG(&image_gif, "GIF87a", true),
SIG(&image_gif, "GIF89a", true),
SIG(&image_png, "\x89PNG\r\n\x1a\n", true),
SIG(&image_jpeg, "\xff\xd8\xff", true),
SIG(&image_bmp, "BM", true),
SIG(&image_vnd_microsoft_icon, "\x00\x00\x01\x00", true),
SIG(&application_ogg, "OggS\x00", true),
SIG(&video_webm, "\x1a\x45\xdf\xa3", true),
SIG(&application_x_rar_compressed, "Rar \x1a\x07\x00", true),
SIG(&application_zip, "PK\x03\x04", true),
SIG(&application_x_gzip, "\x1f\x8b\x08", true),
SIG(&application_postscript, "%!PS-Adobe-", true),
SIG(&application_pdf, "%PDF-", false),
{ NULL, 0, false, NULL }
};
#undef SIG
const struct map_s *it;
 
for (it = exact_match_types; it->sig != NULL; it++) {
if (it->len <= len && memcmp(data, it->sig, it->len) == 0 &&
(allow_unsafe || it->safe)) {
*effective_type = lwc_string_ref(*it->type);
return NSERROR_OK;
}
}
 
return NSERROR_NOT_FOUND;
}
 
static nserror mimesniff__match_unknown(const uint8_t *data, size_t len,
bool allow_unsafe, lwc_string **effective_type)
{
if (mimesniff__match_unknown_exact(data, len, allow_unsafe,
effective_type) == NSERROR_OK)
return NSERROR_OK;
 
if (mimesniff__match_unknown_riff(data, len,
effective_type) == NSERROR_OK)
return NSERROR_OK;
 
if (allow_unsafe == false)
return NSERROR_NOT_FOUND;
 
if (mimesniff__match_unknown_bom(data, len,
effective_type) == NSERROR_OK)
return NSERROR_OK;
 
if (mimesniff__match_unknown_ws(data, len,
effective_type) == NSERROR_OK)
return NSERROR_OK;
 
if (mimesniff__match_mp4(data, len, effective_type) == NSERROR_OK)
return NSERROR_OK;
 
return NSERROR_NOT_FOUND;
}
 
static nserror mimesniff__compute_unknown(const uint8_t *data, size_t len,
lwc_string **effective_type)
{
if (data == NULL)
return NSERROR_NEED_DATA;
 
len = min(len, 512);
 
if (mimesniff__match_unknown(data, len, true,
effective_type) == NSERROR_OK)
return NSERROR_OK;
 
if (mimesniff__has_binary_octets(data, len) == false) {
/* No binary octets => text/plain */
*effective_type = lwc_string_ref(text_plain);
return NSERROR_OK;
}
 
*effective_type = lwc_string_ref(application_octet_stream);
 
return NSERROR_OK;
}
 
static nserror mimesniff__compute_text_or_binary(const uint8_t *data,
size_t len, lwc_string **effective_type)
{
if (data == NULL)
return NSERROR_NEED_DATA;
 
len = min(len, 512);
 
if (len >= 3 && ((data[0] == 0xfe && data[1] == 0xff) ||
(data[0] == 0xff && data[1] == 0xfe) ||
(data[0] == 0xef && data[1] == 0xbb &&
data[2] == 0xbf))) {
/* Found a BOM => text/plain */
*effective_type = lwc_string_ref(text_plain);
return NSERROR_OK;
}
 
if (mimesniff__has_binary_octets(data, len) == false) {
/* No binary octets => text/plain */
*effective_type = lwc_string_ref(text_plain);
return NSERROR_OK;
}
 
if (mimesniff__match_unknown(data, len, false,
effective_type) == NSERROR_OK)
return NSERROR_OK;
 
*effective_type = lwc_string_ref(application_octet_stream);
 
return NSERROR_OK;
}
 
static nserror mimesniff__compute_image(lwc_string *official_type,
const uint8_t *data, size_t len, lwc_string **effective_type)
{
#define SIG(t, s) { (const uint8_t *) s, SLEN(s), t }
static const struct it_s {
const uint8_t *sig;
size_t len;
lwc_string **type;
} image_types[] = {
SIG(&image_gif, "GIF87a"),
SIG(&image_gif, "GIF89a"),
SIG(&image_png, "\x89PNG\r\n\x1a\n"),
SIG(&image_jpeg, "\xff\xd8\xff"),
SIG(&image_bmp, "BM"),
SIG(&image_vnd_microsoft_icon, "\x00\x00\x01\x00"),
{ NULL, 0, NULL }
};
#undef SIG
 
const struct it_s *it;
 
if (data == NULL) {
lwc_string_unref(official_type);
return NSERROR_NEED_DATA;
}
 
for (it = image_types; it->sig != NULL; it++) {
if (it->len <= len && memcmp(data, it->sig, it->len) == 0) {
lwc_string_unref(official_type);
*effective_type = lwc_string_ref(*it->type);
return NSERROR_OK;
}
}
 
/* WebP has a signature that doesn't fit into the above table */
if (SLEN("RIFF????WEBPVP") <= len &&
memcmp(data, "RIFF", SLEN("RIFF")) == 0 &&
memcmp(data + SLEN("RIFF????"),
"WEBPVP", SLEN("WEBPVP")) == 0 ) {
lwc_string_unref(official_type);
*effective_type = lwc_string_ref(image_webp);
return NSERROR_OK;
}
 
*effective_type = official_type;
 
return NSERROR_OK;
}
 
static nserror mimesniff__compute_feed_or_html(const uint8_t *data,
size_t len, lwc_string **effective_type)
{
#define RDF_NS "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
#define RSS_NS "http://purl.org/rss/1.0"
 
enum state_e {
BEFORE_BOM,
BEFORE_MARKUP,
MARKUP_START,
COMMENT_OR_DOCTYPE,
IN_COMMENT,
IN_DOCTYPE,
IN_PI,
IN_TAG,
IN_RDF
} state = BEFORE_BOM;
 
bool rdf = false, rss = false;
const uint8_t *end;
 
if (data == NULL)
return NSERROR_NEED_DATA;
 
end = data + min(len, 512);
 
while (data < end) {
const uint8_t c = *data;
 
#define MATCH(s) SLEN(s) <= (size_t) (end - data) && \
memcmp(data, s, SLEN(s)) == 0
 
switch (state) {
case BEFORE_BOM:
if (3 <= end - data && c == 0xef && data[1] == 0xbb &&
data[2] == 0xbf) {
data += 3;
}
 
state = BEFORE_MARKUP;
break;
case BEFORE_MARKUP:
if (c == '\t' || c == '\n' || c == '\r' || c == ' ')
data++;
else if (c != '<')
data = end;
else {
state = MARKUP_START;
data++;
}
break;
case MARKUP_START:
if (c == '!') {
state = COMMENT_OR_DOCTYPE;
data++;
} else if (c == '?') {
state = IN_PI;
data++;
} else {
/* Reconsume input */
state = IN_TAG;
}
break;
case COMMENT_OR_DOCTYPE:
if (2 <= end - data && c == '-' && data[1] == '-') {
state = IN_COMMENT;
data += 2;
} else {
/* Reconsume input */
state = IN_DOCTYPE;
}
break;
case IN_COMMENT:
if (3 <= end - data && c == '-' && data[1] == '-' &&
data[2] == '>') {
state = BEFORE_MARKUP;
data += 3;
} else
data++;
break;
case IN_DOCTYPE:
if (c == '>')
state = BEFORE_MARKUP;
data++;
break;
case IN_PI:
if (2 <= end - data && c == '?' && data[1] == '>') {
state = BEFORE_MARKUP;
data += 2;
} else
data++;
break;
case IN_TAG:
if (MATCH("rss")) {
*effective_type =
lwc_string_ref(application_rss_xml);
return NSERROR_OK;
} else if (MATCH("feed")) {
*effective_type =
lwc_string_ref(application_atom_xml);
return NSERROR_OK;
} else if (MATCH("rdf:RDF")) {
state = IN_RDF;
data += SLEN("rdf:RDF");
} else
data = end;
break;
case IN_RDF:
if (MATCH(RSS_NS)) {
rss = true;
data += SLEN(RSS_NS);
} else if (MATCH(RDF_NS)) {
rdf = true;
data += SLEN(RDF_NS);
} else
data++;
 
if (rdf && rss) {
*effective_type =
lwc_string_ref(application_rss_xml);
return NSERROR_OK;
}
 
break;
}
#undef MATCH
}
 
*effective_type = lwc_string_ref(text_html);
 
return NSERROR_OK;
 
#undef RSS_NS
#undef RDF_NS
}
 
/* See mimesniff.h for documentation */
nserror mimesniff_compute_effective_type(llcache_handle *handle,
const uint8_t *data, size_t len, bool sniff_allowed,
bool image_only, lwc_string **effective_type)
{
#define S(s) { s, SLEN(s) }
static const struct tt_s {
const char *data;
size_t len;
} text_types[] = {
S("text/plain"),
S("text/plain; charset=ISO-8859-1"),
S("text/plain; charset=iso-8859-1"),
S("text/plain; charset=UTF-8"),
{ NULL, 0 }
};
#undef S
 
const char *content_type_header;
size_t content_type_header_len;
http_content_type *ct;
const struct tt_s *tt;
bool match;
nserror error;
 
content_type_header =
llcache_handle_get_header(handle, "Content-Type");
if (content_type_header == NULL) {
if (sniff_allowed == false)
return NSERROR_NOT_FOUND;
 
/* No official type => unknown */
return mimesniff__compute_unknown(data, len, effective_type);
}
 
error = http_parse_content_type(content_type_header, &ct);
if (error != NSERROR_OK) {
if (sniff_allowed == false)
return NSERROR_NOT_FOUND;
 
/* Unparseable => unknown */
return mimesniff__compute_unknown(data, len, effective_type);
}
 
if (sniff_allowed == false) {
*effective_type = lwc_string_ref(ct->media_type);
http_content_type_destroy(ct);
return NSERROR_OK;
}
 
if (image_only) {
lwc_string *official_type;
 
if (lwc_string_caseless_isequal(ct->media_type, image_svg,
&match) == lwc_error_ok && match) {
*effective_type = lwc_string_ref(image_svg);
http_content_type_destroy(ct);
return NSERROR_OK;
}
 
official_type = lwc_string_ref(ct->media_type);
http_content_type_destroy(ct);
return mimesniff__compute_image(official_type,
data, len, effective_type);
}
 
content_type_header_len = strlen(content_type_header);
 
/* Look for text types */
for (tt = text_types; tt->data != NULL; tt++) {
if (tt->len == content_type_header_len &&
memcmp(tt->data, content_type_header,
content_type_header_len) == 0) {
http_content_type_destroy(ct);
return mimesniff__compute_text_or_binary(data, len,
effective_type);
}
}
 
/* unknown/unknown, application/unknown, * / * */
if ((lwc_string_caseless_isequal(ct->media_type, unknown_unknown,
&match) == lwc_error_ok && match) ||
(lwc_string_caseless_isequal(ct->media_type,
application_unknown, &match) == lwc_error_ok &&
match) ||
(lwc_string_caseless_isequal(ct->media_type, any,
&match) == lwc_error_ok && match)) {
http_content_type_destroy(ct);
return mimesniff__compute_unknown(data, len, effective_type);
}
 
/* +xml */
if (lwc_string_length(ct->media_type) > SLEN("+xml") &&
strncasecmp(lwc_string_data(ct->media_type) +
lwc_string_length(ct->media_type) -
SLEN("+xml"),
"+xml", SLEN("+xml")) == 0) {
/* Use official type */
*effective_type = lwc_string_ref(ct->media_type);
http_content_type_destroy(ct);
return NSERROR_OK;
}
 
/* text/xml, application/xml */
if ((lwc_string_caseless_isequal(ct->media_type, text_xml,
&match) == lwc_error_ok && match) ||
(lwc_string_caseless_isequal(ct->media_type,
application_xml, &match) == lwc_error_ok &&
match)) {
/* Use official type */
*effective_type = lwc_string_ref(ct->media_type);
http_content_type_destroy(ct);
return NSERROR_OK;
}
/* Image types */
if (content_factory_type_from_mime_type(ct->media_type) ==
CONTENT_IMAGE) {
lwc_string *official_type = lwc_string_ref(ct->media_type);
http_content_type_destroy(ct);
return mimesniff__compute_image(official_type,
data, len, effective_type);
}
 
/* text/html */
if ((lwc_string_caseless_isequal(ct->media_type, text_html,
&match) == lwc_error_ok && match)) {
http_content_type_destroy(ct);
return mimesniff__compute_feed_or_html(data, len,
effective_type);
}
 
/* Use official type */
*effective_type = lwc_string_ref(ct->media_type);
 
http_content_type_destroy(ct);
 
return NSERROR_OK;
}
 
/programs/network/netsurf/netsurf/content/mimesniff.h
0,0 → 1,55
/*
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* MIME type sniffer (interface)
*/
 
#ifndef NETSURF_CONTENT_MIMESNIFF_H_
#define NETSURF_CONTENT_MIMESNIFF_H_
 
#include <stdbool.h>
 
#include <libwapcaplet/libwapcaplet.h>
#include "utils/errors.h"
 
struct llcache_handle;
 
/**
* Compute the effective MIME type for an object using the sniffing
* algorithm described in http://mimesniff.spec.whatwg.org/
*
* \param handle Source data handle to sniff
* \param data First data chunk, or NULL
* \param len Length of \a data, in bytes
* \param sniff_allowed Whether MIME type sniffing is allowed
* \param image_only Sniff image types only
* \param effective_type Location to receive computed type
* \return NSERROR_OK on success,
* NSERROR_NEED_DATA iff \a data is NULL and data is needed
* NSERROR_NOT_FOUND if sniffing is prohibited and no
* Content-Type header was found
*/
nserror mimesniff_compute_effective_type(struct llcache_handle *handle,
const uint8_t *data, size_t len, bool sniff_allowed,
bool image_only, lwc_string **effective_type);
 
nserror mimesniff_init(void);
void mimesniff_fini(void);
 
#endif
/programs/network/netsurf/netsurf/content/urldb.c
0,0 → 1,4107
/*
* Copyright 2006 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2009 John Tytgat <joty@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Unified URL information database (implementation)
*
* URLs are stored in a tree-based structure as follows:
*
* The host component is extracted from each URL and, if a FQDN, split on
* every '.'.The tree is constructed by inserting each FQDN segment in
* reverse order. Duplicate nodes are merged.
*
* If the host part of an URL is an IP address, then this is added to the
* tree verbatim (as if it were a TLD).
*
* This provides something looking like:
*
* root (a sentinel)
* |
* -------------------------------------------------
* | | | | | | |
* com edu gov 127.0.0.1 net org uk TLDs
* | | | | | |
* google ... ... ... ... co 2LDs
* | |
* www bbc Hosts/Subdomains
* |
* www ...
*
* Each of the nodes in this tree is a struct host_part. This stores the
* FQDN segment (or IP address) with which the node is concerned. Each node
* may contain further information about paths on a host (struct path_data)
* or SSL certificate processing on a host-wide basis
* (host_part::permit_invalid_certs).
*
* Path data is concerned with storing various metadata about the path in
* question. This includes global history data, HTTP authentication details
* and any associated HTTP cookies. This is stored as a tree of path segments
* hanging off the relevant host_part node.
*
* Therefore, to find the last visited time of the URL
* http://www.example.com/path/to/resource.html, the FQDN tree would be
* traversed in the order root -> "com" -> "example" -> "www". The "www"
* node would have attached to it a tree of struct path_data:
*
* (sentinel)
* |
* path
* |
* to
* |
* resource.html
*
* This represents the absolute path "/path/to/resource.html". The leaf node
* "resource.html" contains the last visited time of the resource.
*
* The mechanism described above is, however, not particularly conducive to
* fast searching of the database for a given URL (or URLs beginning with a
* given prefix). Therefore, an anciliary data structure is used to enable
* fast searching. This structure simply reflects the contents of the
* database, with entries being added/removed at the same time as for the
* core database. In order to ensure that degenerate cases are kept to a
* minimum, we use an AAtree. This is an approximation of a Red-Black tree
* with similar performance characteristics, but with a significantly
* simpler implementation. Entries in this tree comprise pointers to the
* leaf nodes of the host tree described above.
*
* REALLY IMPORTANT NOTE: urldb expects all URLs to be normalised. Use of
* non-normalised URLs with urldb will result in undefined behaviour and
* potential crashes.
*/
 
#include <assert.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
 
#include <curl/curl.h>
 
#include "image/bitmap.h"
#include "content/content.h"
#include "content/urldb.h"
#include "desktop/cookies.h"
#include "desktop/options.h"
#include "utils/log.h"
#include "utils/corestrings.h"
#include "utils/filename.h"
#include "utils/url.h"
#include "utils/utils.h"
 
struct cookie_internal_data {
char *name; /**< Cookie name */
char *value; /**< Cookie value */
bool value_was_quoted; /**< Value was quoted in Set-Cookie: */
char *comment; /**< Cookie comment */
bool domain_from_set; /**< Domain came from Set-Cookie: header */
char *domain; /**< Domain */
bool path_from_set; /**< Path came from Set-Cookie: header */
char *path; /**< Path */
time_t expires; /**< Expiry timestamp, or -1 for session */
time_t last_used; /**< Last used time */
bool secure; /**< Only send for HTTPS requests */
bool http_only; /**< Only expose to HTTP(S) requests */
cookie_version version; /**< Specification compliance */
bool no_destroy; /**< Never destroy this cookie,
* unless it's expired */
 
struct cookie_internal_data *prev; /**< Previous in list */
struct cookie_internal_data *next; /**< Next in list */
};
 
/* A protection space is defined as a tuple canonical_root_url and realm.
* This structure lives as linked list element in a leaf host_part struct
* so we need additional scheme and port to have a canonical_root_url. */
struct prot_space_data {
lwc_string *scheme; /**< URL scheme of canonical hostname of this
* protection space. */
unsigned int port; /**< Port number of canonical hostname of this
* protection space. When 0, it means the
* default port for given scheme, i.e. 80
* (http), 443 (https). */
char *realm; /**< Protection realm */
 
char *auth; /**< Authentication details for this
* protection space in form
* username:password */
struct prot_space_data *next; /**< Next sibling */
};
 
struct cache_internal_data {
char filename[12]; /**< Cached filename, or first byte 0 for none */
};
 
struct url_internal_data {
char *title; /**< Resource title */
unsigned int visits; /**< Visit count */
time_t last_visit; /**< Last visit time */
content_type type; /**< Type of resource */
};
 
struct path_data {
nsurl *url; /**< Full URL */
lwc_string *scheme; /**< URL scheme for data */
unsigned int port; /**< Port number for data. When 0, it means
* the default port for given scheme, i.e.
* 80 (http), 443 (https). */
char *segment; /**< Path segment for this node */
unsigned int frag_cnt; /**< Number of entries in path_data::fragment */
char **fragment; /**< Array of fragments */
bool persistent; /**< This entry should persist */
 
struct bitmap *thumb; /**< Thumbnail image of resource */
struct url_internal_data urld; /**< URL data for resource */
struct cache_internal_data cache; /**< Cache data for resource */
const struct prot_space_data *prot_space; /**< Protection space
* to which this resource belongs too. Can be
* NULL when it does not belong to a protection
* space or when it is not known. No
* ownership (is with struct host_part::prot_space). */
struct cookie_internal_data *cookies; /**< Cookies associated with resource */
struct cookie_internal_data *cookies_end; /**< Last cookie in list */
 
struct path_data *next; /**< Next sibling */
struct path_data *prev; /**< Previous sibling */
struct path_data *parent; /**< Parent path segment */
struct path_data *children; /**< Child path segments */
struct path_data *last; /**< Last child */
};
 
struct host_part {
/**< Known paths on this host. This _must_ be first so that
* struct host_part *h = (struct host_part *)mypath; works */
struct path_data paths;
bool permit_invalid_certs; /**< Allow access to SSL protected
* resources on this host without
* verifying certificate authenticity
*/
 
char *part; /**< Part of host string */
 
struct prot_space_data *prot_space; /**< Linked list of all known
* proctection spaces known for his host and
* all its schems and ports. */
 
struct host_part *next; /**< Next sibling */
struct host_part *prev; /**< Previous sibling */
struct host_part *parent; /**< Parent host part */
struct host_part *children; /**< Child host parts */
};
 
struct search_node {
const struct host_part *data; /**< Host tree entry */
 
unsigned int level; /**< Node level */
 
struct search_node *left; /**< Left subtree */
struct search_node *right; /**< Right subtree */
};
 
/* Destruction */
static void urldb_destroy_host_tree(struct host_part *root);
static void urldb_destroy_path_tree(struct path_data *root);
static void urldb_destroy_path_node_content(struct path_data *node);
static void urldb_destroy_cookie(struct cookie_internal_data *c);
static void urldb_destroy_prot_space(struct prot_space_data *space);
static void urldb_destroy_search_tree(struct search_node *root);
 
/* Saving */
static void urldb_save_search_tree(struct search_node *root, FILE *fp);
static void urldb_count_urls(const struct path_data *root, time_t expiry,
unsigned int *count);
static void urldb_write_paths(const struct path_data *parent,
const char *host, FILE *fp, char **path, int *path_alloc,
int *path_used, time_t expiry);
 
/* Iteration */
static bool urldb_iterate_partial_host(struct search_node *root,
const char *prefix, bool (*callback)(nsurl *url,
const struct url_data *data));
static bool urldb_iterate_partial_path(const struct path_data *parent,
const char *prefix, bool (*callback)(nsurl *url,
const struct url_data *data));
static bool urldb_iterate_entries_host(struct search_node *parent,
bool (*url_callback)(nsurl *url,
const struct url_data *data),
bool (*cookie_callback)(const struct cookie_data *data));
static bool urldb_iterate_entries_path(const struct path_data *parent,
bool (*url_callback)(nsurl *url,
const struct url_data *data),
bool (*cookie_callback)(const struct cookie_data *data));
 
/* Insertion */
static struct host_part *urldb_add_host_node(const char *part,
struct host_part *parent);
static struct path_data *urldb_add_path_node(lwc_string *scheme,
unsigned int port, const char *segment, lwc_string *fragment,
struct path_data *parent);
static int urldb_add_path_fragment_cmp(const void *a, const void *b);
static struct path_data *urldb_add_path_fragment(struct path_data *segment,
lwc_string *fragment);
 
/* Lookup */
static struct path_data *urldb_find_url(nsurl *url);
static struct path_data *urldb_match_path(const struct path_data *parent,
const char *path, lwc_string *scheme, unsigned short port);
static struct search_node **urldb_get_search_tree_direct(const char *host);
static struct search_node *urldb_get_search_tree(const char *host);
 
/* Dump */
static void urldb_dump_hosts(struct host_part *parent);
static void urldb_dump_paths(struct path_data *parent);
static void urldb_dump_search(struct search_node *parent, int depth);
 
/* Search tree */
static struct search_node *urldb_search_insert(struct search_node *root,
const struct host_part *data);
static struct search_node *urldb_search_insert_internal(
struct search_node *root, struct search_node *n);
/* for urldb_search_remove, see r5531 which removed it */
static const struct host_part *urldb_search_find(struct search_node *root,
const char *host);
static struct search_node *urldb_search_skew(struct search_node *root);
static struct search_node *urldb_search_split(struct search_node *root);
static int urldb_search_match_host(const struct host_part *a,
const struct host_part *b);
static int urldb_search_match_string(const struct host_part *a,
const char *b);
static int urldb_search_match_prefix(const struct host_part *a,
const char *b);
 
/* Cookies */
static struct cookie_internal_data *urldb_parse_cookie(nsurl *url,
const char **cookie);
static bool urldb_parse_avpair(struct cookie_internal_data *c, char *n,
char *v, bool was_quoted);
static bool urldb_insert_cookie(struct cookie_internal_data *c,
lwc_string *scheme, nsurl *url);
static void urldb_free_cookie(struct cookie_internal_data *c);
static bool urldb_concat_cookie(struct cookie_internal_data *c, int version,
int *used, int *alloc, char **buf);
static void urldb_delete_cookie_hosts(const char *domain, const char *path,
const char *name, struct host_part *parent);
static void urldb_delete_cookie_paths(const char *domain, const char *path,
const char *name, struct path_data *parent);
static void urldb_save_cookie_hosts(FILE *fp, struct host_part *parent);
static void urldb_save_cookie_paths(FILE *fp, struct path_data *parent);
 
/** Root database handle */
static struct host_part db_root;
 
/** Search trees - one per letter + 1 for IPs + 1 for Everything Else */
#define NUM_SEARCH_TREES 28
#define ST_IP 0
#define ST_EE 1
#define ST_DN 2
static struct search_node empty = { 0, 0, &empty, &empty };
static struct search_node *search_trees[NUM_SEARCH_TREES] = {
&empty, &empty, &empty, &empty, &empty, &empty, &empty, &empty,
&empty, &empty, &empty, &empty, &empty, &empty, &empty, &empty,
&empty, &empty, &empty, &empty, &empty, &empty, &empty, &empty,
&empty, &empty, &empty, &empty
};
 
#define MIN_COOKIE_FILE_VERSION 100
#define COOKIE_FILE_VERSION 102
static int loaded_cookie_file_version;
#define MIN_URL_FILE_VERSION 106
#define URL_FILE_VERSION 106
 
/**
* Import an URL database from file, replacing any existing database
*
* \param filename Name of file containing data
*/
void urldb_load(const char *filename)
{
#define MAXIMUM_URL_LENGTH 4096
char s[MAXIMUM_URL_LENGTH];
char host[256];
struct host_part *h;
int urls;
int i;
int version;
int length;
FILE *fp;
 
assert(filename);
 
LOG(("Loading URL file"));
 
fp = fopen(filename, "r");
if (!fp) {
LOG(("Failed to open file '%s' for reading", filename));
return;
}
 
if (!fgets(s, MAXIMUM_URL_LENGTH, fp)) {
fclose(fp);
return;
}
 
version = atoi(s);
if (version < MIN_URL_FILE_VERSION) {
LOG(("Unsupported URL file version."));
fclose(fp);
return;
}
if (version > URL_FILE_VERSION) {
LOG(("Unknown URL file version."));
fclose(fp);
return;
}
 
while (fgets(host, sizeof host, fp)) {
/* get the hostname */
length = strlen(host) - 1;
host[length] = '\0';
 
/* skip data that has ended up with a host of '' */
if (length == 0) {
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
urls = atoi(s);
/* Eight fields/url */
for (i = 0; i < (8 * urls); i++) {
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
}
continue;
}
 
/* read number of URLs */
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
urls = atoi(s);
 
/* no URLs => try next host */
if (urls == 0) {
LOG(("No URLs for '%s'", host));
continue;
}
 
h = urldb_add_host(host);
if (!h) {
LOG(("Failed adding host: '%s'", host));
die("Memory exhausted whilst loading URL file");
}
 
/* load the non-corrupt data */
for (i = 0; i < urls; i++) {
struct path_data *p = NULL;
char scheme[64], ports[10];
char url[64 + 3 + 256 + 6 + 4096 + 1];
unsigned int port;
bool is_file = false;
nsurl *nsurl;
lwc_string *scheme_lwc, *fragment_lwc;
char *path_query;
size_t len;
 
if (!fgets(scheme, sizeof scheme, fp))
break;
length = strlen(scheme) - 1;
scheme[length] = '\0';
 
if (!fgets(ports, sizeof ports, fp))
break;
length = strlen(ports) - 1;
ports[length] = '\0';
port = atoi(ports);
 
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
length = strlen(s) - 1;
s[length] = '\0';
 
if (!strcasecmp(host, "localhost") &&
!strcasecmp(scheme, "file"))
is_file = true;
 
snprintf(url, sizeof url, "%s://%s%s%s%s",
scheme,
/* file URLs have no host */
(is_file ? "" : host),
(port ? ":" : ""),
(port ? ports : ""),
s);
 
/* TODO: store URLs in pre-parsed state, and make
* a nsurl_load to generate the nsurl more
* swiftly.
* Need a nsurl_save too.
*/
if (nsurl_create(url, &nsurl) != NSERROR_OK) {
LOG(("Failed inserting '%s'", url));
die("Memory exhausted whilst loading "
"URL file");
}
 
/* Copy and merge path/query strings */
if (nsurl_get(nsurl, NSURL_PATH | NSURL_QUERY,
&path_query, &len) != NSERROR_OK) {
LOG(("Failed inserting '%s'", url));
die("Memory exhausted whilst loading "
"URL file");
}
 
scheme_lwc = nsurl_get_component(nsurl, NSURL_SCHEME);
fragment_lwc = nsurl_get_component(nsurl,
NSURL_FRAGMENT);
p = urldb_add_path(scheme_lwc, port, h, path_query,
fragment_lwc, nsurl);
if (!p) {
LOG(("Failed inserting '%s'", url));
die("Memory exhausted whilst loading "
"URL file");
}
nsurl_unref(nsurl);
lwc_string_unref(scheme_lwc);
if (fragment_lwc != NULL)
lwc_string_unref(fragment_lwc);
 
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
if (p)
p->urld.visits = (unsigned int)atoi(s);
 
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
if (p)
p->urld.last_visit = (time_t)atoi(s);
 
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
if (p)
p->urld.type = (content_type)atoi(s);
 
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
 
 
if (!fgets(s, MAXIMUM_URL_LENGTH, fp))
break;
length = strlen(s) - 1;
if (p && length > 0) {
s[length] = '\0';
p->urld.title = malloc(length + 1);
if (p->urld.title)
memcpy(p->urld.title, s, length + 1);
}
}
}
 
fclose(fp);
LOG(("Successfully loaded URL file"));
#undef MAXIMUM_URL_LENGTH
}
 
/**
* Export the current database to file
*
* \param filename Name of file to export to
*/
void urldb_save(const char *filename)
{
FILE *fp;
int i;
 
assert(filename);
 
fp = fopen(filename, "w");
if (!fp) {
LOG(("Failed to open file '%s' for writing", filename));
return;
}
 
/* file format version number */
fprintf(fp, "%d\n", URL_FILE_VERSION);
 
for (i = 0; i != NUM_SEARCH_TREES; i++) {
urldb_save_search_tree(search_trees[i], fp);
}
 
fclose(fp);
}
 
/**
* Save a search (sub)tree
*
* \param root Root of (sub)tree to save
* \param fp File to write to
*/
void urldb_save_search_tree(struct search_node *parent, FILE *fp)
{
char host[256];
const struct host_part *h;
unsigned int path_count = 0;
char *path, *p, *end;
int path_alloc = 64, path_used = 1;
time_t expiry;
 
expiry = time(NULL) - ((60 * 60 * 24) * nsoption_int(expire_url));
 
if (parent == &empty)
return;
 
urldb_save_search_tree(parent->left, fp);
 
path = malloc(path_alloc);
if (!path)
return;
 
path[0] = '\0';
 
for (h = parent->data, p = host, end = host + sizeof host;
h && h != &db_root && p < end; h = h->parent) {
int written = snprintf(p, end - p, "%s%s", h->part,
(h->parent && h->parent->parent) ? "." : "");
if (written < 0) {
free(path);
return;
}
p += written;
}
 
urldb_count_urls(&parent->data->paths, expiry, &path_count);
 
if (path_count > 0) {
fprintf(fp, "%s\n%i\n", host, path_count);
 
urldb_write_paths(&parent->data->paths, host, fp,
&path, &path_alloc, &path_used, expiry);
}
 
free(path);
 
urldb_save_search_tree(parent->right, fp);
}
 
/**
* Count number of URLs associated with a host
*
* \param root Root of path data tree
* \param expiry Expiry time for URLs
* \param count Pointer to count
*/
void urldb_count_urls(const struct path_data *root, time_t expiry,
unsigned int *count)
{
const struct path_data *p = root;
 
do {
if (p->children != NULL) {
/* Drill down into children */
p = p->children;
} else {
/* No more children, increment count if required */
if (p->persistent || ((p->urld.last_visit > expiry) &&
(p->urld.visits > 0)))
(*count)++;
 
/* Now, find next node to process. */
while (p != root) {
if (p->next != NULL) {
/* Have a sibling, process that */
p = p->next;
break;
}
 
/* Ascend tree */
p = p->parent;
}
}
} while (p != root);
}
 
/**
* Write paths associated with a host
*
* \param parent Root of (sub)tree to write
* \param host Current host name
* \param fp File to write to
* \param path Current path string
* \param path_alloc Allocated size of path
* \param path_used Used size of path
* \param expiry Expiry time of URLs
*/
void urldb_write_paths(const struct path_data *parent, const char *host,
FILE *fp, char **path, int *path_alloc, int *path_used,
time_t expiry)
{
const struct path_data *p = parent;
int i;
 
do {
int seglen = p->segment != NULL ? strlen(p->segment) : 0;
int len = *path_used + seglen + 1;
 
if (*path_alloc < len) {
char *temp = realloc(*path,
(len > 64) ? len : *path_alloc + 64);
if (!temp)
return;
*path = temp;
*path_alloc = (len > 64) ? len : *path_alloc + 64;
}
 
if (p->segment != NULL)
memcpy(*path + *path_used - 1, p->segment, seglen);
 
if (p->children != NULL) {
(*path)[*path_used + seglen - 1] = '/';
(*path)[*path_used + seglen] = '\0';
} else {
(*path)[*path_used + seglen - 1] = '\0';
len -= 1;
}
 
*path_used = len;
 
if (p->children != NULL) {
/* Drill down into children */
p = p->children;
} else {
/* leaf node */
if (p->persistent ||((p->urld.last_visit > expiry) &&
(p->urld.visits > 0))) {
fprintf(fp, "%s\n", lwc_string_data(p->scheme));
 
if (p->port)
fprintf(fp,"%d\n", p->port);
else
fprintf(fp, "\n");
 
fprintf(fp, "%s\n", *path);
 
/** \todo handle fragments? */
 
fprintf(fp, "%i\n%i\n%i\n", p->urld.visits,
(int)p->urld.last_visit,
(int)p->urld.type);
 
fprintf(fp, "\n");
 
if (p->urld.title) {
uint8_t *s = (uint8_t *) p->urld.title;
 
for (i = 0; s[i] != '\0'; i++)
if (s[i] < 32)
s[i] = ' ';
for (--i; ((i > 0) && (s[i] == ' '));
i--)
s[i] = '\0';
fprintf(fp, "%s\n", p->urld.title);
} else
fprintf(fp, "\n");
}
 
/* Now, find next node to process. */
while (p != parent) {
int seglen = p->segment != NULL
? strlen(p->segment) : 0;
 
/* Remove our segment from the path */
*path_used -= seglen;
(*path)[*path_used - 1] = '\0';
 
if (p->next != NULL) {
/* Have a sibling, process that */
p = p->next;
break;
}
 
/* Going up, so remove '/' */
*path_used -= 1;
(*path)[*path_used - 1] = '\0';
 
/* Ascend tree */
p = p->parent;
}
}
} while (p != parent);
}
 
/**
* Set the cross-session persistence of the entry for an URL
*
* \param url Absolute URL to persist
* \param persist True to persist, false otherwise
*/
void urldb_set_url_persistence(nsurl *url, bool persist)
{
struct path_data *p;
 
assert(url);
 
p = urldb_find_url(url);
if (!p)
return;
 
p->persistent = persist;
}
 
/**
* Insert an URL into the database
*
* \param url Absolute URL to insert
* \return true on success, false otherwise
*/
bool urldb_add_url(nsurl *url)
{
struct host_part *h;
struct path_data *p;
lwc_string *scheme;
lwc_string *port;
lwc_string *host;
lwc_string *fragment;
const char *host_str;
char *path_query;
size_t len;
bool match;
unsigned int port_int;
 
assert(url);
 
/* Copy and merge path/query strings */
if (nsurl_get(url, NSURL_PATH | NSURL_QUERY, &path_query, &len) !=
NSERROR_OK) {
return false;
}
 
scheme = nsurl_get_component(url, NSURL_SCHEME);
if (scheme == NULL)
return false;
 
host = nsurl_get_component(url, NSURL_HOST);
if (host != NULL) {
host_str = lwc_string_data(host);
lwc_string_unref(host);
 
} else if (lwc_string_isequal(scheme, corestring_lwc_file, &match) ==
lwc_error_ok && match == true) {
host_str = "localhost";
 
} else {
lwc_string_unref(scheme);
return false;
}
 
fragment = nsurl_get_component(url, NSURL_FRAGMENT);
 
port = nsurl_get_component(url, NSURL_PORT);
if (port != NULL) {
port_int = atoi(lwc_string_data(port));
lwc_string_unref(port);
} else {
port_int = 0;
}
 
/* Get host entry */
h = urldb_add_host(host_str);
 
/* Get path entry */
p = (h != NULL) ? urldb_add_path(scheme, port_int, h, path_query,
fragment, url) : NULL;
 
lwc_string_unref(scheme);
if (fragment != NULL)
lwc_string_unref(fragment);
 
return (p != NULL);
}
 
/**
* Set an URL's title string, replacing any existing one
*
* \param url The URL to look for
* \param title The title string to use (copied)
*/
void urldb_set_url_title(nsurl *url, const char *title)
{
struct path_data *p;
char *temp;
 
assert(url && title);
 
p = urldb_find_url(url);
if (!p)
return;
 
temp = strdup(title);
if (!temp)
return;
 
free(p->urld.title);
p->urld.title = temp;
}
 
/**
* Set an URL's content type
*
* \param url The URL to look for
* \param type The type to set
*/
void urldb_set_url_content_type(nsurl *url, content_type type)
{
struct path_data *p;
 
assert(url);
 
p = urldb_find_url(url);
if (!p)
return;
 
p->urld.type = type;
}
 
/**
* Update an URL's visit data
*
* \param url The URL to update
*/
void urldb_update_url_visit_data(nsurl *url)
{
struct path_data *p;
 
assert(url);
 
p = urldb_find_url(url);
if (!p)
return;
 
p->urld.last_visit = time(NULL);
p->urld.visits++;
}
 
/**
* Reset an URL's visit statistics
*
* \param url The URL to reset
*/
void urldb_reset_url_visit_data(nsurl *url)
{
struct path_data *p;
 
assert(url);
 
p = urldb_find_url(url);
if (!p)
return;
 
p->urld.last_visit = (time_t)0;
p->urld.visits = 0;
}
 
 
/**
* Find data for an URL.
*
* \param url Absolute URL to look for
* \return Pointer to result struct, or NULL
*/
const struct url_data *urldb_get_url_data(nsurl *url)
{
struct path_data *p;
struct url_internal_data *u;
 
assert(url);
 
p = urldb_find_url(url);
if (!p)
return NULL;
 
u = &p->urld;
 
return (const struct url_data *) u;
}
 
/**
* Extract an URL from the db
*
* \param url URL to extract
* \return Pointer to database's copy of URL or NULL if not found
*/
nsurl *urldb_get_url(nsurl *url)
{
struct path_data *p;
 
assert(url);
 
p = urldb_find_url(url);
if (!p)
return NULL;
 
return p->url;
}
 
/**
* Look up authentication details in database
*
* \param url Absolute URL to search for
* \param realm When non-NULL, it is realm which can be used to determine
* the protection space when that's not been done before for given URL.
* \return Pointer to authentication details, or NULL if not found
*/
const char *urldb_get_auth_details(nsurl *url, const char *realm)
{
struct path_data *p, *p_cur, *p_top;
 
assert(url);
 
/* add to the db, so our lookup will work */
urldb_add_url(url);
 
p = urldb_find_url(url);
if (!p)
return NULL;
 
/* Check for any auth details attached to the path_data node or any of
* its parents. */
for (p_cur = p; p_cur != NULL; p_top = p_cur, p_cur = p_cur->parent) {
if (p_cur->prot_space) {
return p_cur->prot_space->auth;
}
}
 
/* Only when we have a realm (and canonical root of given URL), we can
* uniquely locate the protection space. */
if (realm != NULL) {
const struct host_part *h = (const struct host_part *)p_top;
const struct prot_space_data *space;
bool match;
 
/* Search for a possible matching protection space. */
for (space = h->prot_space; space != NULL;
space = space->next) {
if (!strcmp(space->realm, realm) &&
lwc_string_isequal(space->scheme,
p->scheme, &match) ==
lwc_error_ok &&
match == true &&
space->port == p->port) {
p->prot_space = space;
return p->prot_space->auth;
}
}
}
 
return NULL;
}
 
/**
* Retrieve certificate verification permissions from database
*
* \param url Absolute URL to search for
* \return true to permit connections to hosts with invalid certificates,
* false otherwise.
*/
bool urldb_get_cert_permissions(nsurl *url)
{
struct path_data *p;
const struct host_part *h;
 
assert(url);
 
p = urldb_find_url(url);
if (!p)
return false;
 
for (; p && p->parent; p = p->parent)
/* do nothing */;
assert(p);
 
h = (const struct host_part *)p;
 
return h->permit_invalid_certs;
}
 
/**
* Set authentication data for an URL
*
* \param url The URL to consider
* \param realm The authentication realm
* \param auth The authentication details (in form username:password)
*/
void urldb_set_auth_details(nsurl *url, const char *realm,
const char *auth)
{
struct path_data *p, *pi;
struct host_part *h;
struct prot_space_data *space, *space_alloc;
char *realm_alloc, *auth_alloc;
bool match;
 
assert(url && realm && auth);
 
/* add url, in case it's missing */
urldb_add_url(url);
 
p = urldb_find_url(url);
 
if (!p)
return;
 
/* Search for host_part */
for (pi = p; pi->parent != NULL; pi = pi->parent)
;
h = (struct host_part *)pi;
 
/* Search if given URL belongs to a protection space we already know of. */
for (space = h->prot_space; space; space = space->next) {
if (!strcmp(space->realm, realm) &&
lwc_string_isequal(space->scheme, p->scheme,
&match) == lwc_error_ok &&
match == true &&
space->port == p->port)
break;
}
 
if (space != NULL) {
/* Overrule existing auth. */
free(space->auth);
space->auth = strdup(auth);
} else {
/* Create a new protection space. */
space = space_alloc = malloc(sizeof(struct prot_space_data));
realm_alloc = strdup(realm);
auth_alloc = strdup(auth);
 
if (!space_alloc || !realm_alloc || !auth_alloc) {
free(space_alloc);
free(realm_alloc);
free(auth_alloc);
return;
}
 
space->scheme = lwc_string_ref(p->scheme);
space->port = p->port;
space->realm = realm_alloc;
space->auth = auth_alloc;
space->next = h->prot_space;
h->prot_space = space;
}
 
p->prot_space = space;
}
 
/**
* Set certificate verification permissions
*
* \param url URL to consider
* \param permit Set to true to allow invalid certificates
*/
void urldb_set_cert_permissions(nsurl *url, bool permit)
{
struct path_data *p;
struct host_part *h;
 
assert(url);
 
/* add url, in case it's missing */
urldb_add_url(url);
 
p = urldb_find_url(url);
if (!p)
return;
 
for (; p && p->parent; p = p->parent)
/* do nothing */;
assert(p);
 
h = (struct host_part *)p;
 
h->permit_invalid_certs = permit;
}
 
/**
* Set thumbnail for url, replacing any existing thumbnail
*
* \param url Absolute URL to consider
* \param bitmap Opaque pointer to thumbnail data, or NULL to invalidate
*/
void urldb_set_thumbnail(nsurl *url, struct bitmap *bitmap)
{
struct path_data *p;
 
assert(url);
 
p = urldb_find_url(url);
if (!p)
return;
 
if (p->thumb && p->thumb != bitmap)
bitmap_destroy(p->thumb);
 
p->thumb = bitmap;
}
 
/**
* Retrieve thumbnail data for given URL
*
* \param url Absolute URL to search for
* \return Pointer to thumbnail data, or NULL if not found.
*/
struct bitmap *urldb_get_thumbnail(nsurl *url)
{
struct path_data *p;
 
assert(url);
 
p = urldb_find_url(url);
if (!p)
return NULL;
 
return p->thumb;
}
 
/**
* Iterate over entries in the database which match the given prefix
*
* \param prefix Prefix to match
* \param callback Callback function
*/
void urldb_iterate_partial(const char *prefix,
bool (*callback)(nsurl *url,
const struct url_data *data))
{
char host[256];
char buf[260]; /* max domain + "www." */
const char *slash, *scheme_sep;
struct search_node *tree;
const struct host_part *h;
 
assert(prefix && callback);
 
/* strip scheme */
scheme_sep = strstr(prefix, "://");
if (scheme_sep)
prefix = scheme_sep + 3;
 
slash = strchr(prefix, '/');
tree = urldb_get_search_tree(prefix);
 
if (slash) {
/* if there's a slash in the input, then we can
* assume that we're looking for a path */
snprintf(host, sizeof host, "%.*s",
(int) (slash - prefix), prefix);
 
h = urldb_search_find(tree, host);
if (!h) {
int len = slash - prefix;
 
if (len <= 3 || strncasecmp(host, "www.", 4) != 0) {
snprintf(buf, sizeof buf, "www.%s", host);
h = urldb_search_find(
search_trees[ST_DN + 'w' - 'a'],
buf);
if (!h)
return;
} else
return;
}
 
if (h->paths.children) {
/* Have paths, iterate them */
urldb_iterate_partial_path(&h->paths, slash + 1,
callback);
}
 
} else {
int len = strlen(prefix);
 
/* looking for hosts */
if (!urldb_iterate_partial_host(tree, prefix, callback))
return;
 
if (len <= 3 || strncasecmp(prefix, "www.", 4) != 0) {
/* now look for www.prefix */
snprintf(buf, sizeof buf, "www.%s", prefix);
if(!urldb_iterate_partial_host(
search_trees[ST_DN + 'w' - 'a'],
buf, callback))
return;
}
}
}
 
/**
* Partial host iterator (internal)
*
* \param root Root of (sub)tree to traverse
* \param prefix Prefix to match
* \param callback Callback function
* \return true to continue, false otherwise
*/
bool urldb_iterate_partial_host(struct search_node *root, const char *prefix,
bool (*callback)(nsurl *url, const struct url_data *data))
{
int c;
 
assert(root && prefix && callback);
 
if (root == &empty)
return true;
 
c = urldb_search_match_prefix(root->data, prefix);
 
if (c > 0)
/* No match => look in left subtree */
return urldb_iterate_partial_host(root->left, prefix,
callback);
else if (c < 0)
/* No match => look in right subtree */
return urldb_iterate_partial_host(root->right, prefix,
callback);
else {
/* Match => iterate over l/r subtrees & process this node */
if (!urldb_iterate_partial_host(root->left, prefix,
callback))
return false;
 
if (root->data->paths.children) {
/* and extract all paths attached to this host */
if (!urldb_iterate_entries_path(&root->data->paths,
callback, NULL)) {
return false;
}
}
 
if (!urldb_iterate_partial_host(root->right, prefix,
callback))
return false;
}
 
return true;
}
 
/**
* Partial path iterator (internal)
*
* \param parent Root of (sub)tree to traverse
* \param prefix Prefix to match
* \param callback Callback function
* \return true to continue, false otherwise
*/
bool urldb_iterate_partial_path(const struct path_data *parent,
const char *prefix, bool (*callback)(nsurl *url,
const struct url_data *data))
{
const struct path_data *p = parent->children;
const char *slash, *end = prefix + strlen(prefix);
 
/*
* Given: http://www.example.org/a/b/c/d//e
* and assuming a path tree:
* .
* / \
* a1 b1
* / \
* a2 b2
* /|\
* a b c
* 3 3 |
* d
* |
* e
* / \
* f g
*
* Prefix will be: p will be:
*
* a/b/c/d//e a1
* b/c/d//e a2
* b/c/d//e b3
* c/d//e a3
* c/d//e b3
* c/d//e c
* d//e d
* /e e (skip /)
* e e
*
* I.E. we perform a breadth-first search of the tree.
*/
 
do {
slash = strchr(prefix, '/');
if (!slash)
slash = end;
 
if (slash == prefix && *prefix == '/') {
/* Ignore "//" */
prefix++;
continue;
}
if (strncasecmp(p->segment, prefix, slash - prefix) == 0) {
/* prefix matches so far */
if (slash == end) {
/* we've run out of prefix, so all
* paths below this one match */
if (!urldb_iterate_entries_path(p, callback,
NULL))
return false;
 
/* Progress to next sibling */
p = p->next;
} else {
/* Skip over this segment */
prefix = slash + 1;
 
p = p->children;
}
} else {
/* Doesn't match this segment, try next sibling */
p = p->next;
}
} while (p != NULL);
 
return true;
}
 
/**
* Iterate over all entries in database
*
* \param callback Function to callback for each entry
*/
void urldb_iterate_entries(bool (*callback)(nsurl *url,
const struct url_data *data))
{
int i;
 
assert(callback);
 
for (i = 0; i < NUM_SEARCH_TREES; i++) {
if (!urldb_iterate_entries_host(search_trees[i],
callback, NULL))
break;
}
}
 
/**
* Iterate over all cookies in database
*
* \param callback Function to callback for each entry
*/
void urldb_iterate_cookies(bool (*callback)(const struct cookie_data *data))
{
int i;
 
assert(callback);
 
for (i = 0; i < NUM_SEARCH_TREES; i++) {
if (!urldb_iterate_entries_host(search_trees[i],
NULL, callback))
break;
}
}
 
/**
* Host data iterator (internal)
*
* \param parent Root of subtree to iterate over
* \param url_callback Callback function
* \param cookie_callback Callback function
* \return true to continue, false otherwise
*/
bool urldb_iterate_entries_host(struct search_node *parent,
bool (*url_callback)(nsurl *url,
const struct url_data *data),
bool (*cookie_callback)(const struct cookie_data *data))
{
if (parent == &empty)
return true;
 
if (!urldb_iterate_entries_host(parent->left,
url_callback, cookie_callback))
return false;
 
if ((parent->data->paths.children) || ((cookie_callback) &&
(parent->data->paths.cookies))) {
/* We have paths (or domain cookies), so iterate them */
if (!urldb_iterate_entries_path(&parent->data->paths,
url_callback, cookie_callback)) {
return false;
}
}
 
if (!urldb_iterate_entries_host(parent->right,
url_callback, cookie_callback))
return false;
 
return true;
}
 
/**
* Path data iterator (internal)
*
* \param parent Root of subtree to iterate over
* \param url_callback Callback function
* \param cookie_callback Callback function
* \return true to continue, false otherwise
*/
bool urldb_iterate_entries_path(const struct path_data *parent,
bool (*url_callback)(nsurl *url,
const struct url_data *data),
bool (*cookie_callback)(const struct cookie_data *data))
{
const struct path_data *p = parent;
const struct cookie_data *c;
do {
if (p->children != NULL) {
/* Drill down into children */
p = p->children;
} else {
/* All leaf nodes in the path tree should have an URL or
* cookies attached to them. If this is not the case, it
* indicates that there's a bug in the file loader/URL
* insertion code. Therefore, assert this here. */
assert(url_callback || cookie_callback);
 
/** \todo handle fragments? */
if (url_callback) {
const struct url_internal_data *u = &p->urld;
 
assert(p->url);
 
if (!url_callback(p->url,
(const struct url_data *) u))
return false;
} else {
c = (const struct cookie_data *)p->cookies;
for (; c != NULL; c = c->next)
if (!cookie_callback(c))
return false;
}
 
/* Now, find next node to process. */
while (p != parent) {
if (p->next != NULL) {
/* Have a sibling, process that */
p = p->next;
break;
}
 
/* Ascend tree */
p = p->parent;
}
}
} while (p != parent);
 
return true;
}
 
/**
* Add a host node to the tree
*
* \param part Host segment to add (or whole IP address) (copied)
* \param parent Parent node to add to
* \return Pointer to added node, or NULL on memory exhaustion
*/
struct host_part *urldb_add_host_node(const char *part,
struct host_part *parent)
{
struct host_part *d;
 
assert(part && parent);
 
d = calloc(1, sizeof(struct host_part));
if (!d)
return NULL;
 
d->part = strdup(part);
if (!d->part) {
free(d);
return NULL;
}
 
d->next = parent->children;
if (parent->children)
parent->children->prev = d;
d->parent = parent;
parent->children = d;
 
return d;
}
 
/**
* Add a host to the database, creating any intermediate entries
*
* \param host Hostname to add
* \return Pointer to leaf node, or NULL on memory exhaustion
*/
struct host_part *urldb_add_host(const char *host)
{
struct host_part *d = (struct host_part *) &db_root, *e;
struct search_node *s;
char buf[256]; /* 256 bytes is sufficient - domain names are
* limited to 255 chars. */
char *part;
 
assert(host);
 
if (url_host_is_ip_address(host)) {
/* Host is an IP, so simply add as TLD */
 
/* Check for existing entry */
for (e = d->children; e; e = e->next)
if (strcasecmp(host, e->part) == 0)
/* found => return it */
return e;
 
d = urldb_add_host_node(host, d);
 
s = urldb_search_insert(search_trees[ST_IP], d);
if (!s) {
/* failed */
d = NULL;
} else {
search_trees[ST_IP] = s;
}
 
return d;
}
 
/* Copy host string, so we can corrupt it */
strncpy(buf, host, sizeof buf);
buf[sizeof buf - 1] = '\0';
 
/* Process FQDN segments backwards */
do {
part = strrchr(buf, '.');
if (!part) {
/* last segment */
/* Check for existing entry */
for (e = d->children; e; e = e->next)
if (strcasecmp(buf, e->part) == 0)
break;
 
if (e) {
d = e;
} else {
d = urldb_add_host_node(buf, d);
}
 
/* And insert into search tree */
if (d) {
struct search_node **r;
 
r = urldb_get_search_tree_direct(buf);
s = urldb_search_insert(*r, d);
if (!s) {
/* failed */
d = NULL;
} else {
*r = s;
}
}
break;
}
 
/* Check for existing entry */
for (e = d->children; e; e = e->next)
if (strcasecmp(part + 1, e->part) == 0)
break;
 
d = e ? e : urldb_add_host_node(part + 1, d);
if (!d)
break;
 
*part = '\0';
} while (1);
 
return d;
}
 
/**
* Add a path node to the tree
*
* \param scheme URL scheme associated with path (copied)
* \param port Port number on host associated with path
* \param segment Path segment to add (copied)
* \param fragment URL fragment (copied), or NULL
* \param parent Parent node to add to
* \return Pointer to added node, or NULL on memory exhaustion
*/
struct path_data *urldb_add_path_node(lwc_string *scheme, unsigned int port,
const char *segment, lwc_string *fragment,
struct path_data *parent)
{
struct path_data *d, *e;
 
assert(scheme && segment && parent);
 
d = calloc(1, sizeof(struct path_data));
if (!d)
return NULL;
 
d->scheme = lwc_string_ref(scheme);
 
d->port = port;
 
d->segment = strdup(segment);
if (!d->segment) {
lwc_string_unref(d->scheme);
free(d);
return NULL;
}
 
if (fragment) {
if (!urldb_add_path_fragment(d, fragment)) {
free(d->segment);
lwc_string_unref(d->scheme);
free(d);
return NULL;
}
}
 
for (e = parent->children; e; e = e->next)
if (strcmp(e->segment, d->segment) > 0)
break;
 
if (e) {
d->prev = e->prev;
d->next = e;
if (e->prev)
e->prev->next = d;
else
parent->children = d;
e->prev = d;
} else if (!parent->children) {
d->prev = d->next = NULL;
parent->children = parent->last = d;
} else {
d->next = NULL;
d->prev = parent->last;
parent->last->next = d;
parent->last = d;
}
d->parent = parent;
 
return d;
}
 
/**
* Add a path to the database, creating any intermediate entries
*
* \param scheme URL scheme associated with path
* \param port Port number on host associated with path
* \param host Host tree node to attach to
* \param path_query Absolute path plus query to add (freed)
* \param fragment URL fragment, or NULL
* \param url URL (fragment ignored)
* \return Pointer to leaf node, or NULL on memory exhaustion
*/
struct path_data *urldb_add_path(lwc_string *scheme, unsigned int port,
const struct host_part *host, char *path_query,
lwc_string *fragment, nsurl *url)
{
struct path_data *d, *e;
char *buf = path_query;
char *segment, *slash;
bool match;
 
assert(scheme && host && url);
 
d = (struct path_data *) &host->paths;
 
/* skip leading '/' */
segment = buf;
if (*segment == '/')
segment++;
 
/* Process path segments */
do {
slash = strchr(segment, '/');
if (!slash) {
/* last segment */
/* look for existing entry */
for (e = d->children; e; e = e->next)
if (strcmp(segment, e->segment) == 0 &&
lwc_string_isequal(scheme,
e->scheme, &match) ==
lwc_error_ok &&
match == true &&
e->port == port)
break;
 
d = e ? urldb_add_path_fragment(e, fragment) :
urldb_add_path_node(scheme, port,
segment, fragment, d);
break;
}
 
*slash = '\0';
 
/* look for existing entry */
for (e = d->children; e; e = e->next)
if (strcmp(segment, e->segment) == 0 &&
lwc_string_isequal(scheme, e->scheme,
&match) == lwc_error_ok &&
match == true &&
e->port == port)
break;
 
d = e ? e : urldb_add_path_node(scheme, port, segment, NULL, d);
if (!d)
break;
 
segment = slash + 1;
} while (1);
 
free(path_query);
 
if (d && !d->url) {
/* Insert URL */
if (nsurl_has_component(url, NSURL_FRAGMENT)) {
nserror err = nsurl_defragment(url, &d->url);
if (err != NSERROR_OK)
return NULL;
} else {
d->url = nsurl_ref(url);
}
}
 
return d;
}
 
/**
* Fragment comparator callback for qsort
*/
int urldb_add_path_fragment_cmp(const void *a, const void *b)
{
return strcasecmp(*((const char **) a), *((const char **) b));
}
 
/**
* Add a fragment to a path segment
*
* \param segment Path segment to add to
* \param fragment Fragment to add (copied), or NULL
* \return segment or NULL on memory exhaustion
*/
struct path_data *urldb_add_path_fragment(struct path_data *segment,
lwc_string *fragment)
{
char **temp;
 
assert(segment);
 
/* If no fragment, this function is a NOP
* This may seem strange, but it makes the rest
* of the code cleaner */
if (!fragment)
return segment;
 
temp = realloc(segment->fragment,
(segment->frag_cnt + 1) * sizeof(char *));
if (!temp)
return NULL;
 
segment->fragment = temp;
segment->fragment[segment->frag_cnt] =
strdup(lwc_string_data(fragment));
if (!segment->fragment[segment->frag_cnt]) {
/* Don't free temp - it's now our buffer */
return NULL;
}
 
segment->frag_cnt++;
 
/* We want fragments in alphabetical order, so sort them
* It may prove better to insert in alphabetical order instead */
qsort(segment->fragment, segment->frag_cnt, sizeof (char *),
urldb_add_path_fragment_cmp);
 
return segment;
}
 
/**
* Find an URL in the database
*
* \param url Absolute URL to find
* \return Pointer to path data, or NULL if not found
*/
struct path_data *urldb_find_url(nsurl *url)
{
const struct host_part *h;
struct path_data *p;
struct search_node *tree;
char *plq;
const char *host_str;
lwc_string *scheme, *host, *port;
size_t len = 0;
unsigned int port_int;
bool match;
 
assert(url);
 
scheme = nsurl_get_component(url, NSURL_SCHEME);
if (scheme == NULL)
return NULL;
 
host = nsurl_get_component(url, NSURL_HOST);
if (host != NULL) {
host_str = lwc_string_data(host);
lwc_string_unref(host);
 
} else if (lwc_string_isequal(scheme, corestring_lwc_file, &match) ==
lwc_error_ok && match == true) {
host_str = "localhost";
 
} else {
lwc_string_unref(scheme);
return NULL;
}
 
tree = urldb_get_search_tree(host_str);
h = urldb_search_find(tree, host_str);
if (!h) {
lwc_string_unref(scheme);
return NULL;
}
 
/* generate plq (path, leaf, query) */
if (nsurl_get(url, NSURL_PATH | NSURL_QUERY, &plq, &len) !=
NSERROR_OK) {
lwc_string_unref(scheme);
return NULL;
}
 
/* Get port */
port = nsurl_get_component(url, NSURL_PORT);
if (port != NULL) {
port_int = atoi(lwc_string_data(port));
lwc_string_unref(port);
} else {
port_int = 0;
}
 
p = urldb_match_path(&h->paths, plq, scheme, port_int);
 
free(plq);
lwc_string_unref(scheme);
 
return p;
}
 
/**
* Match a path string
*
* \param parent Path (sub)tree to look in
* \param path The path to search for
* \param scheme The URL scheme associated with the path
* \param port The port associated with the path
* \return Pointer to path data or NULL if not found.
*/
struct path_data *urldb_match_path(const struct path_data *parent,
const char *path, lwc_string *scheme, unsigned short port)
{
const struct path_data *p;
const char *slash;
bool match;
 
assert(parent != NULL);
assert(parent->segment == NULL);
assert(path[0] == '/');
 
/* Start with children, as parent has no segment */
p = parent->children;
 
while (p != NULL) {
slash = strchr(path + 1, '/');
if (!slash)
slash = path + strlen(path);
 
if (strncmp(p->segment, path + 1, slash - path - 1) == 0 &&
lwc_string_isequal(p->scheme, scheme, &match) ==
lwc_error_ok &&
match == true &&
p->port == port) {
if (*slash == '\0') {
/* Complete match */
return (struct path_data *) p;
}
 
/* Match so far, go down tree */
p = p->children;
 
path = slash;
} else {
/* No match, try next sibling */
p = p->next;
}
}
 
return NULL;
}
 
/**
* Get the search tree for a particular host
*
* \param host the host to lookup
* \return the corresponding search tree
*/
struct search_node **urldb_get_search_tree_direct(const char *host) {
assert(host);
 
if (url_host_is_ip_address(host))
return &search_trees[ST_IP];
else if (isalpha(*host))
return &search_trees[ST_DN + tolower(*host) - 'a'];
return &search_trees[ST_EE];
}
 
/**
* Get the search tree for a particular host
*
* \param host the host to lookup
* \return the corresponding search tree
*/
struct search_node *urldb_get_search_tree(const char *host) {
return *urldb_get_search_tree_direct(host);
}
 
/**
* Dump URL database to stderr
*/
void urldb_dump(void)
{
int i;
 
urldb_dump_hosts(&db_root);
 
for (i = 0; i != NUM_SEARCH_TREES; i++)
urldb_dump_search(search_trees[i], 0);
}
 
/**
* Dump URL database hosts to stderr
*
* \param parent Parent node of tree to dump
*/
void urldb_dump_hosts(struct host_part *parent)
{
struct host_part *h;
 
if (parent->part) {
LOG(("%s", parent->part));
 
LOG(("\t%s invalid SSL certs",
parent->permit_invalid_certs ? "Permits" : "Denies"));
}
 
/* Dump path data */
urldb_dump_paths(&parent->paths);
 
/* and recurse */
for (h = parent->children; h; h = h->next)
urldb_dump_hosts(h);
}
 
/**
* Dump URL database paths to stderr
*
* \param parent Parent node of tree to dump
*/
void urldb_dump_paths(struct path_data *parent)
{
const struct path_data *p = parent;
unsigned int i;
 
do {
if (p->segment != NULL) {
LOG(("\t%s : %u", lwc_string_data(p->scheme), p->port));
 
LOG(("\t\t'%s'", p->segment));
 
for (i = 0; i != p->frag_cnt; i++)
LOG(("\t\t\t#%s", p->fragment[i]));
}
 
if (p->children != NULL) {
p = p->children;
} else {
while (p != parent) {
if (p->next != NULL) {
p = p->next;
break;
}
 
p = p->parent;
}
}
} while (p != parent);
}
 
/**
* Dump search tree
*
* \param parent Parent node of tree to dump
* \param depth Tree depth
*/
void urldb_dump_search(struct search_node *parent, int depth)
{
const struct host_part *h;
int i;
 
if (parent == &empty)
return;
 
urldb_dump_search(parent->left, depth + 1);
 
for (i = 0; i != depth; i++)
fputc(' ', stderr);
 
for (h = parent->data; h; h = h->parent) {
if (h->part)
fprintf(stderr, "%s", h->part);
 
if (h->parent && h->parent->parent)
fputc('.', stderr);
}
 
fputc('\n', stderr);
 
urldb_dump_search(parent->right, depth + 1);
}
 
/**
* Insert a node into the search tree
*
* \param root Root of tree to insert into
* \param data User data to insert
* \return Pointer to updated root, or NULL if failed
*/
struct search_node *urldb_search_insert(struct search_node *root,
const struct host_part *data)
{
struct search_node *n;
 
assert(root && data);
 
n = malloc(sizeof(struct search_node));
if (!n)
return NULL;
 
n->level = 1;
n->data = data;
n->left = n->right = &empty;
 
root = urldb_search_insert_internal(root, n);
 
return root;
}
 
/**
* Insert node into search tree
*
* \param root Root of (sub)tree to insert into
* \param n Node to insert
* \return Pointer to updated root
*/
struct search_node *urldb_search_insert_internal(struct search_node *root,
struct search_node *n)
{
assert(root && n);
 
if (root == &empty) {
root = n;
} else {
int c = urldb_search_match_host(root->data, n->data);
 
if (c > 0) {
root->left = urldb_search_insert_internal(
root->left, n);
} else if (c < 0) {
root->right = urldb_search_insert_internal(
root->right, n);
} else {
/* exact match */
free(n);
return root;
}
 
root = urldb_search_skew(root);
root = urldb_search_split(root);
}
 
return root;
}
 
/**
* Find a node in a search tree
*
* \param root Tree to look in
* \param host Host to find
* \return Pointer to host tree node, or NULL if not found
*/
const struct host_part *urldb_search_find(struct search_node *root,
const char *host)
{
int c;
 
assert(root && host);
 
if (root == &empty) {
return NULL;
}
 
c = urldb_search_match_string(root->data, host);
 
if (c > 0)
return urldb_search_find(root->left, host);
else if (c < 0)
return urldb_search_find(root->right, host);
else
return root->data;
}
 
/**
* Compare a pair of host_parts
*
* \param a
* \param b
* \return 0 if match, non-zero, otherwise
*/
int urldb_search_match_host(const struct host_part *a,
const struct host_part *b)
{
int ret;
 
assert(a && b);
 
/* traverse up tree to root, comparing parts as we go. */
for (; a && a != &db_root && b && b != &db_root;
a = a->parent, b = b->parent)
if ((ret = strcasecmp(a->part, b->part)) != 0)
/* They differ => return the difference here */
return ret;
 
/* If we get here then either:
* a) The path lengths differ
* or b) The hosts are identical
*/
if (a && a != &db_root && (!b || b == &db_root))
/* len(a) > len(b) */
return 1;
else if ((!a || a == &db_root) && b && b != &db_root)
/* len(a) < len(b) */
return -1;
 
/* identical */
return 0;
}
 
/**
* Compare host_part with a string
*
* \param a
* \param b
* \return 0 if match, non-zero, otherwise
*/
int urldb_search_match_string(const struct host_part *a,
const char *b)
{
const char *end, *dot;
int plen, ret;
 
assert(a && a != &db_root && b);
 
if (url_host_is_ip_address(b)) {
/* IP address */
return strcasecmp(a->part, b);
}
 
end = b + strlen(b) + 1;
 
while (b < end && a && a != &db_root) {
dot = strchr(b, '.');
if (!dot) {
/* last segment */
dot = end - 1;
}
 
/* Compare strings (length limited) */
if ((ret = strncasecmp(a->part, b, dot - b)) != 0)
/* didn't match => return difference */
return ret;
 
/* The strings matched, now check that the lengths do, too */
plen = strlen(a->part);
 
if (plen > dot - b)
/* len(a) > len(b) */
return 1;
else if (plen < dot - b)
/* len(a) < len(b) */
return -1;
 
b = dot + 1;
a = a->parent;
}
 
/* If we get here then either:
* a) The path lengths differ
* or b) The hosts are identical
*/
if (a && a != &db_root && b >= end)
/* len(a) > len(b) */
return 1;
else if ((!a || a == &db_root) && b < end)
/* len(a) < len(b) */
return -1;
 
/* Identical */
return 0;
}
 
/**
* Compare host_part with prefix
*
* \param a
* \param b
* \return 0 if match, non-zero, otherwise
*/
int urldb_search_match_prefix(const struct host_part *a,
const char *b)
{
const char *end, *dot;
int plen, ret;
 
assert(a && a != &db_root && b);
 
if (url_host_is_ip_address(b)) {
/* IP address */
return strncasecmp(a->part, b, strlen(b));
}
 
end = b + strlen(b) + 1;
 
while (b < end && a && a != &db_root) {
dot = strchr(b, '.');
if (!dot) {
/* last segment */
dot = end - 1;
}
 
/* Compare strings (length limited) */
if ((ret = strncasecmp(a->part, b, dot - b)) != 0)
/* didn't match => return difference */
return ret;
 
/* The strings matched */
if (dot < end - 1) {
/* Consider segment lengths only in the case
* where the prefix contains segments */
plen = strlen(a->part);
if (plen > dot - b)
/* len(a) > len(b) */
return 1;
else if (plen < dot - b)
/* len(a) < len(b) */
return -1;
}
 
b = dot + 1;
a = a->parent;
}
 
/* If we get here then either:
* a) The path lengths differ
* or b) The hosts are identical
*/
if (a && a != &db_root && b >= end)
/* len(a) > len(b) => prefix matches */
return 0;
else if ((!a || a == &db_root) && b < end)
/* len(a) < len(b) => prefix does not match */
return -1;
 
/* Identical */
return 0;
}
 
/**
* Rotate a subtree right
*
* \param root Root of subtree to rotate
* \return new root of subtree
*/
struct search_node *urldb_search_skew(struct search_node *root)
{
struct search_node *temp;
 
assert(root);
 
if (root->left->level == root->level) {
temp = root->left;
root->left = temp->right;
temp->right = root;
root = temp;
}
 
return root;
}
 
/**
* Rotate a node left, increasing the parent's level
*
* \param root Root of subtree to rotate
* \return New root of subtree
*/
struct search_node *urldb_search_split(struct search_node *root)
{
struct search_node *temp;
 
assert(root);
 
if (root->right->right->level == root->level) {
temp = root->right;
root->right = temp->left;
temp->left = root;
root = temp;
 
root->level++;
}
 
return root;
}
 
/**
* Retrieve cookies for an URL
*
* \param url URL being fetched
* \param include_http_only Whether to include HTTP(S) only cookies.
* \return Cookies string for libcurl (on heap), or NULL on error/no cookies
*/
char *urldb_get_cookie(nsurl *url, bool include_http_only)
{
const struct path_data *p, *q;
const struct host_part *h;
lwc_string *path_lwc;
struct cookie_internal_data *c;
int count = 0, version = COOKIE_RFC2965;
struct cookie_internal_data **matched_cookies;
int matched_cookies_size = 20;
int ret_alloc = 4096, ret_used = 1;
const char *path;
char *ret;
lwc_string *scheme;
time_t now;
int i;
bool match;
 
assert(url != NULL);
 
/* The URL must exist in the db in order to find relevant cookies, since
* we search up the tree from the URL node, and cookies from further
* up also apply. */
urldb_add_url(url);
 
p = urldb_find_url(url);
if (!p)
return NULL;
 
scheme = p->scheme;
 
matched_cookies = malloc(matched_cookies_size *
sizeof(struct cookie_internal_data *));
if (!matched_cookies)
return NULL;
 
#define GROW_MATCHED_COOKIES \
do { \
if (count == matched_cookies_size) { \
struct cookie_internal_data **temp; \
temp = realloc(matched_cookies, \
(matched_cookies_size + 20) * \
sizeof(struct cookie_internal_data *)); \
\
if (temp == NULL) { \
free(ret); \
free(matched_cookies); \
return NULL; \
} \
\
matched_cookies = temp; \
matched_cookies_size += 20; \
} \
} while(0)
 
ret = malloc(ret_alloc);
if (!ret) {
free(matched_cookies);
return NULL;
}
 
ret[0] = '\0';
 
path_lwc = nsurl_get_component(url, NSURL_PATH);
if (path_lwc == NULL) {
free(ret);
free(matched_cookies);
return NULL;
}
path = lwc_string_data(path_lwc);
lwc_string_unref(path_lwc);
 
now = time(NULL);
 
if (*(p->segment) != '\0') {
/* Match exact path, unless directory, when prefix matching
* will handle this case for us. */
for (q = p->parent->children; q; q = q->next) {
if (strcmp(q->segment, p->segment))
continue;
 
/* Consider all cookies associated with
* this exact path */
for (c = q->cookies; c; c = c->next) {
if (c->expires != -1 && c->expires < now)
/* cookie has expired => ignore */
continue;
 
if (c->secure && lwc_string_isequal(
q->scheme,
corestring_lwc_https,
&match) &&
match == false)
/* secure cookie for insecure host.
* ignore */
continue;
 
if (c->http_only && !include_http_only)
/* Ignore HttpOnly */
continue;
 
matched_cookies[count++] = c;
 
GROW_MATCHED_COOKIES;
 
if (c->version < (unsigned int)version)
version = c->version;
 
c->last_used = now;
cookies_schedule_update((struct cookie_data *)c);
}
}
}
 
/* Now consider cookies whose paths prefix-match ours */
for (p = p->parent; p; p = p->parent) {
/* Find directory's path entry(ies) */
/* There are potentially multiple due to differing schemes */
for (q = p->children; q; q = q->next) {
if (*(q->segment) != '\0')
continue;
 
for (c = q->cookies; c; c = c->next) {
if (c->expires != -1 && c->expires < now)
/* cookie has expired => ignore */
continue;
 
if (c->secure && lwc_string_isequal(
q->scheme,
corestring_lwc_https,
&match) &&
match == false)
/* Secure cookie for insecure server
* => ignore */
continue;
 
matched_cookies[count++] = c;
 
GROW_MATCHED_COOKIES;
 
if (c->version < (unsigned int) version)
version = c->version;
 
c->last_used = now;
cookies_schedule_update((struct cookie_data *)c);
}
}
 
if (!p->parent) {
/* No parent, so bail here. This can't go in
* the loop exit condition as we also want to
* process the top-level node.
*
* If p->parent is NULL then p->cookies are
* the domain cookies and thus we don't even
* try matching against them.
*/
break;
}
 
/* Consider p itself - may be the result of Path=/foo */
for (c = p->cookies; c; c = c->next) {
if (c->expires != -1 && c->expires < now)
/* cookie has expired => ignore */
continue;
 
/* Ensure cookie path is a prefix of the resource */
if (strncmp(c->path, path, strlen(c->path)) != 0)
/* paths don't match => ignore */
continue;
 
if (c->secure && lwc_string_isequal(p->scheme,
corestring_lwc_https,
&match) &&
match == false)
/* Secure cookie for insecure server
* => ignore */
continue;
 
matched_cookies[count++] = c;
 
GROW_MATCHED_COOKIES;
 
if (c->version < (unsigned int) version)
version = c->version;
 
c->last_used = now;
cookies_schedule_update((struct cookie_data *)c);
}
 
}
 
/* Finally consider domain cookies for hosts which domain match ours */
for (h = (const struct host_part *)p; h && h != &db_root;
h = h->parent) {
for (c = h->paths.cookies; c; c = c->next) {
if (c->expires != -1 && c->expires < now)
/* cookie has expired => ignore */
continue;
 
/* Ensure cookie path is a prefix of the resource */
if (strncmp(c->path, path, strlen(c->path)) != 0)
/* paths don't match => ignore */
continue;
 
if (c->secure && lwc_string_isequal(scheme,
corestring_lwc_https,
&match) &&
match == false)
/* secure cookie for insecure host. ignore */
continue;
 
matched_cookies[count++] = c;
 
GROW_MATCHED_COOKIES;
 
if (c->version < (unsigned int)version)
version = c->version;
 
c->last_used = now;
cookies_schedule_update((struct cookie_data *)c);
}
}
 
if (count == 0) {
/* No cookies found */
free(ret);
free(matched_cookies);
return NULL;
}
 
/* and build output string */
if (version > COOKIE_NETSCAPE) {
sprintf(ret, "$Version=%d", version);
ret_used = strlen(ret) + 1;
}
 
for (i = 0; i < count; i++) {
if (!urldb_concat_cookie(matched_cookies[i], version,
&ret_used, &ret_alloc, &ret)) {
free(ret);
free(matched_cookies);
return NULL;
}
}
 
if (version == COOKIE_NETSCAPE) {
/* Old-style cookies => no version & skip "; " */
memmove(ret, ret + 2, ret_used - 2);
ret_used -= 2;
}
 
/* Now, shrink the output buffer to the required size */
{
char *temp = realloc(ret, ret_used);
if (!temp) {
free(ret);
free(matched_cookies);
return NULL;
}
 
ret = temp;
}
 
free(matched_cookies);
 
return ret;
 
#undef GROW_MATCHED_COOKIES
}
 
/**
* Parse Set-Cookie header and insert cookie(s) into database
*
* \param header Header to parse, with Set-Cookie: stripped
* \param url URL being fetched
* \param referer Referring resource, or 0 for verifiable transaction
* \return true on success, false otherwise
*/
bool urldb_set_cookie(const char *header, nsurl *url, nsurl *referer)
{
const char *cur = header, *end;
lwc_string *path, *host, *scheme;
nsurl *urlt;
bool match;
 
assert(url && header);
 
/* Get defragmented URL, as 'urlt' */
if (nsurl_has_component(url, NSURL_FRAGMENT)) {
if (nsurl_defragment(url, &urlt) != NSERROR_OK)
return NULL;
} else {
urlt = nsurl_ref(url);
}
 
scheme = nsurl_get_component(url, NSURL_SCHEME);
if (scheme == NULL) {
nsurl_unref(urlt);
return false;
}
 
path = nsurl_get_component(url, NSURL_PATH);
if (path == NULL) {
lwc_string_unref(scheme);
nsurl_unref(urlt);
return false;
}
 
host = nsurl_get_component(url, NSURL_HOST);
if (host == NULL) {
lwc_string_unref(path);
lwc_string_unref(scheme);
nsurl_unref(urlt);
return false;
}
 
if (referer) {
lwc_string *rhost;
 
/* Ensure that url's host name domain matches
* referer's (4.3.5) */
rhost = nsurl_get_component(url, NSURL_HOST);
if (rhost == NULL) {
goto error;
}
 
/* Domain match host names */
if (lwc_string_isequal(host, rhost, &match) == lwc_error_ok &&
match == false) {
const char *hptr;
const char *rptr;
const char *dot;
const char *host_data = lwc_string_data(host);
const char *rhost_data = lwc_string_data(rhost);
 
/* Ensure neither host nor rhost are IP addresses */
if (url_host_is_ip_address(host_data) ||
url_host_is_ip_address(rhost_data)) {
/* IP address, so no partial match */
lwc_string_unref(rhost);
goto error;
}
 
/* Not exact match, so try the following:
*
* 1) Find the longest common suffix of host and rhost
* (may be all of host/rhost)
* 2) Discard characters from the start of the suffix
* until the suffix starts with a dot
* (prevents foobar.com matching bar.com)
* 3) Ensure the suffix is non-empty and contains
* embedded dots (to avoid permitting .com as a
* suffix)
*
* Note that the above in no way resembles the
* domain matching algorithm found in RFC2109.
* It does, however, model the real world rather
* more accurately.
*/
 
/** \todo In future, we should consult a TLD service
* instead of just looking for embedded dots.
*/
 
hptr = host_data + lwc_string_length(host) - 1;
rptr = rhost_data + lwc_string_length(rhost) - 1;
 
/* 1 */
while (hptr >= host_data && rptr >= rhost_data) {
if (*hptr != *rptr)
break;
hptr--;
rptr--;
}
/* Ensure we end up pointing at the start of the
* common suffix. The above loop will exit pointing
* to the byte before the start of the suffix. */
hptr++;
 
/* 2 */
while (*hptr != '\0' && *hptr != '.')
hptr++;
 
/* 3 */
if (*hptr == '\0' ||
(dot = strchr(hptr + 1, '.')) == NULL ||
*(dot + 1) == '\0') {
lwc_string_unref(rhost);
goto error;
}
}
 
lwc_string_unref(rhost);
}
 
end = cur + strlen(cur) - 2 /* Trailing CRLF */;
 
do {
struct cookie_internal_data *c;
char *dot;
size_t len;
 
c = urldb_parse_cookie(url, &cur);
if (!c) {
/* failed => stop parsing */
goto error;
}
 
/* validate cookie */
 
/* 4.2.2:i Cookie must have NAME and VALUE */
if (!c->name || !c->value) {
urldb_free_cookie(c);
goto error;
}
 
/* 4.3.2:i Cookie path must be a prefix of URL path */
len = strlen(c->path);
if (len > lwc_string_length(path) ||
strncmp(c->path, lwc_string_data(path),
len) != 0) {
urldb_free_cookie(c);
goto error;
}
 
/* 4.3.2:ii Cookie domain must contain embedded dots */
dot = strchr(c->domain + 1, '.');
if (!dot || *(dot + 1) == '\0') {
/* no embedded dots */
urldb_free_cookie(c);
goto error;
}
 
/* Domain match fetch host with cookie domain */
if (strcasecmp(lwc_string_data(host), c->domain) != 0) {
int hlen, dlen;
char *domain = c->domain;
 
/* c->domain must be a domain cookie here because:
* c->domain is either:
* + specified in the header as a domain cookie
* (non-domain cookies in the header are ignored
* by urldb_parse_cookie / urldb_parse_avpair)
* + defaulted to the URL's host part
* (by urldb_parse_cookie if no valid domain was
* specified in the header)
*
* The latter will pass the strcasecmp above, which
* leaves the former (i.e. a domain cookie)
*/
assert(c->domain[0] == '.');
 
/* 4.3.2:iii */
if (url_host_is_ip_address(lwc_string_data(host))) {
/* IP address, so no partial match */
urldb_free_cookie(c);
goto error;
}
 
hlen = lwc_string_length(host);
dlen = strlen(c->domain);
 
if (hlen <= dlen && hlen != dlen - 1) {
/* Partial match not possible */
urldb_free_cookie(c);
goto error;
}
 
if (hlen == dlen - 1) {
/* Relax matching to allow
* host a.com to match .a.com */
domain++;
dlen--;
}
 
if (strcasecmp(lwc_string_data(host) + (hlen - dlen),
domain)) {
urldb_free_cookie(c);
goto error;
}
 
/* 4.3.2:iv Ensure H contains no dots
*
* If you believe the spec, H should contain no
* dots in _any_ cookie. Unfortunately, however,
* reality differs in that many sites send domain
* cookies of the form .foo.com from hosts such
* as bar.bat.foo.com and then expect domain
* matching to work. Thus we have to do what they
* expect, regardless of any potential security
* implications.
*
* This is what code conforming to the spec would
* look like:
*
* for (int i = 0; i < (hlen - dlen); i++) {
* if (host[i] == '.') {
* urldb_free_cookie(c);
* goto error;
* }
* }
*/
}
 
/* Now insert into database */
if (!urldb_insert_cookie(c, scheme, urlt))
goto error;
} while (cur < end);
 
lwc_string_unref(host);
lwc_string_unref(path);
lwc_string_unref(scheme);
nsurl_unref(urlt);
 
return true;
 
error:
lwc_string_unref(host);
lwc_string_unref(path);
lwc_string_unref(scheme);
nsurl_unref(urlt);
 
return false;
}
 
/**
* Parse a cookie
*
* \param url URL being fetched
* \param cookie Pointer to cookie string (updated on exit)
* \return Pointer to cookie structure (on heap, caller frees) or NULL
*/
struct cookie_internal_data *urldb_parse_cookie(nsurl *url,
const char **cookie)
{
struct cookie_internal_data *c;
const char *cur;
char name[1024], value[4096];
char *n = name, *v = value;
bool in_value = false;
bool had_value_data = false;
bool value_verbatim = false;
bool quoted = false;
bool was_quoted = false;
 
assert(url && cookie && *cookie);
 
c = calloc(1, sizeof(struct cookie_internal_data));
if (c == NULL)
return NULL;
 
c->expires = -1;
 
name[0] = '\0';
value[0] = '\0';
 
for (cur = *cookie; *cur; cur++) {
if (*cur == '\r' && *(cur + 1) == '\n') {
/* End of header */
if (quoted) {
/* Unmatched quote encountered */
 
/* Match Firefox 2.0.0.11 */
value[0] = '\0';
 
#if 0
/* This is what IE6/7 & Safari 3 do */
/* Opera 9.25 discards the entire cookie */
 
/* Shuffle value up by 1 */
memmove(value + 1, value,
min(v - value, sizeof(value) - 2));
v++;
/* And insert " character at the start */
value[0] = '"';
 
/* Now, run forwards through the value
* looking for a semicolon. If one exists,
* terminate the value at this point. */
for (char *s = value; s < v; s++) {
if (*s == ';') {
*s = '\0';
v = s;
break;
}
}
#endif
}
 
break;
} else if (*cur == '\r') {
/* Spurious linefeed */
continue;
} else if (*cur == '\n') {
/* Spurious newline */
continue;
}
 
if (in_value && !had_value_data) {
if (*cur == ' ' || *cur == '\t') {
/* Strip leading whitespace from value */
continue;
} else {
had_value_data = true;
 
/* Value is taken verbatim if first non-space
* character is not a " */
if (*cur != '"') {
value_verbatim = true;
}
}
}
 
if (in_value && !value_verbatim && (*cur == '"')) {
/* Only non-verbatim values may be quoted */
if (cur == *cookie || *(cur - 1) != '\\') {
/* Only unescaped quotes count */
was_quoted = quoted;
quoted = !quoted;
 
continue;
}
}
 
if (!quoted && !in_value && *cur == '=') {
/* First equals => attr-value separator */
in_value = true;
continue;
}
 
if (!quoted && (was_quoted || *cur == ';')) {
/* Semicolon or after quoted value
* => end of current avpair */
 
/* NUL-terminate tokens */
*n = '\0';
*v = '\0';
 
if (!urldb_parse_avpair(c, name, value, was_quoted)) {
/* Memory exhausted */
urldb_free_cookie(c);
return NULL;
}
 
/* And reset to start */
n = name;
v = value;
in_value = false;
had_value_data = false;
value_verbatim = false;
was_quoted = false;
 
/* Now, if the current input is anything other than a
* semicolon, we must be sure to reprocess it */
if (*cur != ';') {
cur--;
}
 
continue;
}
 
/* And now handle commas. These are a pain as they may mean
* any of the following:
*
* + End of cookie
* + Day separator in Expires avpair
* + (Invalid) comma in unquoted value
*
* Therefore, in order to handle all 3 cases (2 and 3 are
* identical, the difference being that 2 is in the spec and
* 3 isn't), we need to determine where the comma actually
* lies. We use the following heuristic:
*
* Given a comma at the current input position, find the
* immediately following semicolon (or end of input if none
* found). Then, consider the input characters between
* these two positions. If any of these characters is an
* '=', we must assume that the comma signified the end of
* the current cookie.
*
* This holds as the first avpair of any cookie must be
* NAME=VALUE, so the '=' is guaranteed to appear in the
* case where the comma marks the end of a cookie.
*
* This will fail, however, in the case where '=' appears in
* the value of the current avpair after the comma or the
* subsequent cookie does not start with NAME=VALUE. Neither
* of these is particularly likely and if they do occur, the
* website is more broken than we can be bothered to handle.
*/
if (!quoted && *cur == ',') {
/* Find semi-colon, if any */
const char *p;
const char *semi = strchr(cur + 1, ';');
if (!semi)
semi = cur + strlen(cur) - 2 /* CRLF */;
 
/* Look for equals sign between comma and semi */
for (p = cur + 1; p < semi; p++)
if (*p == '=')
break;
 
if (p == semi) {
/* none found => comma internal to value */
/* do nothing */
} else {
/* found one => comma marks end of cookie */
cur++;
break;
}
}
 
/* Accumulate into buffers, always leaving space for a NUL */
/** \todo is silently truncating overlong names/values wise? */
if (!in_value) {
if (n < name + (sizeof(name) - 1))
*n++ = *cur;
} else {
if (v < value + (sizeof(value) - 1))
*v++ = *cur;
}
}
 
/* Parse final avpair */
*n = '\0';
*v = '\0';
 
if (!urldb_parse_avpair(c, name, value, was_quoted)) {
/* Memory exhausted */
urldb_free_cookie(c);
return NULL;
}
 
/* Now fix-up default values */
if (c->domain == NULL) {
lwc_string *host = nsurl_get_component(url, NSURL_HOST);
if (host == NULL) {
urldb_free_cookie(c);
return NULL;
}
c->domain = strdup(lwc_string_data(host));
lwc_string_unref(host);
}
 
if (c->path == NULL) {
const char *path_data;
char *path, *slash;
lwc_string *path_lwc;
 
path_lwc = nsurl_get_component(url, NSURL_PATH);
if (path_lwc == NULL) {
urldb_free_cookie(c);
return NULL;
}
path_data = lwc_string_data(path_lwc);
 
/* Strip leafname and trailing slash (4.3.1) */
slash = strrchr(path_data, '/');
if (slash != NULL) {
/* Special case: retain first slash in path */
if (slash == path_data)
slash++;
 
slash = strndup(path_data, slash - path_data);
if (slash == NULL) {
lwc_string_unref(path_lwc);
urldb_free_cookie(c);
return NULL;
}
 
path = slash;
lwc_string_unref(path_lwc);
} else {
path = strdup(lwc_string_data(path_lwc));
lwc_string_unref(path_lwc);
if (path == NULL) {
urldb_free_cookie(c);
return NULL;
}
}
 
c->path = path;
}
 
/* Write back current position */
*cookie = cur;
 
return c;
}
 
/**
* Parse a cookie avpair
*
* \param c Cookie struct to populate
* \param n Name component
* \param v Value component
* \param was_quoted Whether ::v was quoted in the input
* \return true on success, false on memory exhaustion
*/
bool urldb_parse_avpair(struct cookie_internal_data *c, char *n, char *v,
bool was_quoted)
{
int vlen;
 
assert(c && n && v);
 
/* Strip whitespace from start of name */
for (; *n; n++) {
if (*n != ' ' && *n != '\t')
break;
}
 
/* Strip whitespace from end of name */
for (vlen = strlen(n); vlen; vlen--) {
if (n[vlen] == ' ' || n[vlen] == '\t')
n[vlen] = '\0';
else
break;
}
 
/* Strip whitespace from start of value */
for (; *v; v++) {
if (*v != ' ' && *v != '\t')
break;
}
 
/* Strip whitespace from end of value */
for (vlen = strlen(v); vlen; vlen--) {
if (v[vlen] == ' ' || v[vlen] == '\t')
v[vlen] = '\0';
else
break;
}
 
if (!c->comment && strcasecmp(n, "Comment") == 0) {
c->comment = strdup(v);
if (!c->comment)
return false;
} else if (!c->domain && strcasecmp(n, "Domain") == 0) {
if (v[0] == '.') {
/* Domain must start with a dot */
c->domain_from_set = true;
c->domain = strdup(v);
if (!c->domain)
return false;
}
} else if (strcasecmp(n, "Max-Age") == 0) {
int temp = atoi(v);
if (temp == 0)
/* Special case - 0 means delete */
c->expires = 0;
else
c->expires = time(NULL) + temp;
} else if (!c->path && strcasecmp(n, "Path") == 0) {
c->path_from_set = true;
c->path = strdup(v);
if (!c->path)
return false;
} else if (strcasecmp(n, "Version") == 0) {
c->version = atoi(v);
} else if (strcasecmp(n, "Expires") == 0) {
char *datenoday;
time_t expires;
 
/* Strip dayname from date (these are hugely
* variable and liable to break the parser.
* They also serve no useful purpose) */
for (datenoday = v; *datenoday && !isdigit(*datenoday);
datenoday++)
; /* do nothing */
 
expires = curl_getdate(datenoday, NULL);
if (expires == -1) {
/* assume we have an unrepresentable
* date => force it to the maximum
* possible value of a 32bit time_t
* (this may break in 2038. We'll
* deal with that once we come to
* it) */
expires = (time_t)0x7fffffff;
}
c->expires = expires;
} else if (strcasecmp(n, "Secure") == 0) {
c->secure = true;
} else if (strcasecmp(n, "HttpOnly") == 0) {
c->http_only = true;
} else if (!c->name) {
c->name = strdup(n);
c->value = strdup(v);
c->value_was_quoted = was_quoted;
if (!c->name || !c->value)
return false;
}
 
return true;
}
 
/**
* Insert a cookie into the database
*
* \param c The cookie to insert
* \param scheme URL scheme associated with cookie path
* \param url URL (sans fragment) associated with cookie
* \return true on success, false on memory exhaustion (c will be freed)
*/
bool urldb_insert_cookie(struct cookie_internal_data *c, lwc_string *scheme,
nsurl *url)
{
struct cookie_internal_data *d;
const struct host_part *h;
struct path_data *p;
time_t now = time(NULL);
 
assert(c);
 
if (c->domain[0] == '.') {
h = urldb_search_find(
urldb_get_search_tree(&(c->domain[1])),
c->domain + 1);
if (!h) {
h = urldb_add_host(c->domain + 1);
if (!h) {
urldb_free_cookie(c);
return false;
}
}
 
p = (struct path_data *) &h->paths;
} else {
/* Need to have a URL and scheme, if it's not a domain cookie */
assert(url != NULL);
assert(scheme != NULL);
 
h = urldb_search_find(
urldb_get_search_tree(c->domain),
c->domain);
 
if (!h) {
h = urldb_add_host(c->domain);
if (!h) {
urldb_free_cookie(c);
return false;
}
}
 
/* find path */
p = urldb_add_path(scheme, 0, h,
strdup(c->path), NULL, url);
if (!p) {
urldb_free_cookie(c);
return false;
}
}
 
/* add cookie */
for (d = p->cookies; d; d = d->next) {
if (!strcmp(d->domain, c->domain) &&
!strcmp(d->path, c->path) &&
!strcmp(d->name, c->name))
break;
}
 
if (d) {
if (c->expires != -1 && c->expires < now) {
/* remove cookie */
if (d->next)
d->next->prev = d->prev;
else
p->cookies_end = d->prev;
if (d->prev)
d->prev->next = d->next;
else
p->cookies = d->next;
cookies_remove((struct cookie_data *)d);
urldb_free_cookie(d);
urldb_free_cookie(c);
} else {
/* replace d with c */
c->prev = d->prev;
c->next = d->next;
if (c->next)
c->next->prev = c;
else
p->cookies_end = c;
if (c->prev)
c->prev->next = c;
else
p->cookies = c;
cookies_remove((struct cookie_data *)d);
urldb_free_cookie(d);
cookies_schedule_update((struct cookie_data *)c);
}
} else {
c->prev = p->cookies_end;
c->next = NULL;
if (p->cookies_end)
p->cookies_end->next = c;
else
p->cookies = c;
p->cookies_end = c;
 
cookies_schedule_update((struct cookie_data *)c);
}
 
return true;
}
 
/**
* Free a cookie
*
* \param c The cookie to free
*/
void urldb_free_cookie(struct cookie_internal_data *c)
{
assert(c);
 
free(c->comment);
free(c->domain);
free(c->path);
free(c->name);
free(c->value);
free(c);
}
 
/**
* Concatenate a cookie into the provided buffer
*
* \param c Cookie to concatenate
* \param version The version of the cookie string to output
* \param used Pointer to amount of buffer used (updated)
* \param alloc Pointer to allocated size of buffer (updated)
* \param buf Pointer to Pointer to buffer (updated)
* \return true on success, false on memory exhaustion
*/
bool urldb_concat_cookie(struct cookie_internal_data *c, int version,
int *used, int *alloc, char **buf)
{
/* Combined (A)BNF for the Cookie: request header:
*
* CHAR = <any US-ASCII character (octets 0 - 127)>
* CTL = <any US-ASCII control character
* (octets 0 - 31) and DEL (127)>
* CR = <US-ASCII CR, carriage return (13)>
* LF = <US-ASCII LF, linefeed (10)>
* SP = <US-ASCII SP, space (32)>
* HT = <US-ASCII HT, horizontal-tab (9)>
* <"> = <US-ASCII double-quote mark (34)>
*
* CRLF = CR LF
*
* LWS = [CRLF] 1*( SP | HT )
*
* TEXT = <any OCTET except CTLs,
* but including LWS>
*
* token = 1*<any CHAR except CTLs or separators>
* separators = "(" | ")" | "<" | ">" | "@"
* | "," | ";" | ":" | "\" | <">
* | "/" | "[" | "]" | "?" | "="
* | "{" | "}" | SP | HT
*
* quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
* qdtext = <any TEXT except <">>
* quoted-pair = "\" CHAR
*
* attr = token
* value = word
* word = token | quoted-string
*
* cookie = "Cookie:" cookie-version
* 1*((";" | ",") cookie-value)
* cookie-value = NAME "=" VALUE [";" path] [";" domain]
* cookie-version = "$Version" "=" value
* NAME = attr
* VALUE = value
* path = "$Path" "=" value
* domain = "$Domain" "=" value
*
* A note on quoted-string handling:
* The cookie data stored in the db is verbatim (i.e. sans enclosing
* <">, if any, and with all quoted-pairs intact) thus all that we
* need to do here is ensure that value strings which were quoted
* in Set-Cookie or which include any of the separators are quoted
* before use.
*
* A note on cookie-value separation:
* We use semicolons for all separators, including between
* cookie-values. This simplifies things and is backwards compatible.
*/
const char * const separators = "()<>@,;:\\\"/[]?={} \t";
 
int max_len;
 
assert(c && used && alloc && buf && *buf);
 
/* "; " cookie-value
* We allow for the possibility that values are quoted
*/
max_len = 2 + strlen(c->name) + 1 + strlen(c->value) + 2 +
(c->path_from_set ?
8 + strlen(c->path) + 2 : 0) +
(c->domain_from_set ?
10 + strlen(c->domain) + 2 : 0);
 
if (*used + max_len >= *alloc) {
char *temp = realloc(*buf, *alloc + 4096);
if (!temp) {
return false;
}
*buf = temp;
*alloc += 4096;
}
 
if (version == COOKIE_NETSCAPE) {
/* Original Netscape cookie */
sprintf(*buf + *used - 1, "; %s=", c->name);
*used += 2 + strlen(c->name) + 1;
 
/* The Netscape spec doesn't mention quoting of cookie values.
* RFC 2109 $10.1.3 indicates that values must not be quoted.
*
* However, other browsers preserve quoting, so we should, too
*/
if (c->value_was_quoted) {
sprintf(*buf + *used - 1, "\"%s\"", c->value);
*used += 1 + strlen(c->value) + 1;
} else {
/** \todo should we %XX-encode [;HT,SP] ? */
/** \todo Should we strip escaping backslashes? */
sprintf(*buf + *used - 1, "%s", c->value);
*used += strlen(c->value);
}
 
/* We don't send path/domain information -- that's what the
* Netscape spec suggests we should do, anyway. */
} else {
/* RFC2109 or RFC2965 cookie */
sprintf(*buf + *used - 1, "; %s=", c->name);
*used += 2 + strlen(c->name) + 1;
 
/* Value needs quoting if it contains any separator or if
* it needs preserving from the Set-Cookie header */
if (c->value_was_quoted ||
strpbrk(c->value, separators) != NULL) {
sprintf(*buf + *used - 1, "\"%s\"", c->value);
*used += 1 + strlen(c->value) + 1;
} else {
sprintf(*buf + *used - 1, "%s", c->value);
*used += strlen(c->value);
}
 
if (c->path_from_set) {
/* Path, quoted if necessary */
sprintf(*buf + *used - 1, "; $Path=");
*used += 8;
 
if (strpbrk(c->path, separators) != NULL) {
sprintf(*buf + *used - 1, "\"%s\"", c->path);
*used += 1 + strlen(c->path) + 1;
} else {
sprintf(*buf + *used - 1, "%s", c->path);
*used += strlen(c->path);
}
}
 
if (c->domain_from_set) {
/* Domain, quoted if necessary */
sprintf(*buf + *used - 1, "; $Domain=");
*used += 10;
 
if (strpbrk(c->domain, separators) != NULL) {
sprintf(*buf + *used - 1, "\"%s\"", c->domain);
*used += 1 + strlen(c->domain) + 1;
} else {
sprintf(*buf + *used - 1, "%s", c->domain);
*used += strlen(c->domain);
}
}
}
 
return true;
}
 
/**
* Load a cookie file into the database
*
* \param filename File to load
*/
void urldb_load_cookies(const char *filename)
{
FILE *fp;
char s[16*1024];
 
assert(filename);
 
fp = fopen(filename, "r");
if (!fp)
return;
 
#define FIND_T { \
for (; *p && *p != '\t'; p++) \
; /* do nothing */ \
if (p >= end) { \
LOG(("Overran input")); \
continue; \
} \
*p++ = '\0'; \
}
 
#define SKIP_T { \
for (; *p && *p == '\t'; p++) \
; /* do nothing */ \
if (p >= end) { \
LOG(("Overran input")); \
continue; \
} \
}
 
while (fgets(s, sizeof s, fp)) {
char *p = s, *end = 0,
*domain, *path, *name, *value, *scheme, *url,
*comment;
int version, domain_specified, path_specified,
secure, http_only, no_destroy, value_quoted;
time_t expires, last_used;
struct cookie_internal_data *c;
 
if(s[0] == 0 || s[0] == '#')
/* Skip blank lines or comments */
continue;
 
s[strlen(s) - 1] = '\0'; /* lose terminating newline */
end = s + strlen(s);
 
/* Look for file version first
* (all input is ignored until this is read)
*/
if (strncasecmp(s, "Version:", 8) == 0) {
FIND_T; SKIP_T; loaded_cookie_file_version = atoi(p);
 
if (loaded_cookie_file_version <
MIN_COOKIE_FILE_VERSION) {
LOG(("Unsupported Cookie file version"));
break;
}
 
continue;
} else if (loaded_cookie_file_version == 0) {
/* Haven't yet seen version; skip this input */
continue;
}
 
/* One cookie/line */
 
/* Parse input */
FIND_T; version = atoi(s);
SKIP_T; domain = p; FIND_T;
SKIP_T; domain_specified = atoi(p); FIND_T;
SKIP_T; path = p; FIND_T;
SKIP_T; path_specified = atoi(p); FIND_T;
SKIP_T; secure = atoi(p); FIND_T;
if (loaded_cookie_file_version > 101) {
/* Introduced in version 1.02 */
SKIP_T; http_only = atoi(p); FIND_T;
} else {
http_only = 0;
}
SKIP_T; expires = (time_t)atoi(p); FIND_T;
SKIP_T; last_used = (time_t)atoi(p); FIND_T;
SKIP_T; no_destroy = atoi(p); FIND_T;
SKIP_T; name = p; FIND_T;
SKIP_T; value = p; FIND_T;
if (loaded_cookie_file_version > 100) {
/* Introduced in version 1.01 */
SKIP_T; value_quoted = atoi(p); FIND_T;
} else {
value_quoted = 0;
}
SKIP_T; scheme = p; FIND_T;
SKIP_T; url = p; FIND_T;
 
/* Comment may have no content, so don't
* use macros as they'll break */
for (; *p && *p == '\t'; p++)
; /* do nothing */
comment = p;
 
assert(p <= end);
 
/* Now create cookie */
c = malloc(sizeof(struct cookie_internal_data));
if (!c)
break;
 
c->name = strdup(name);
c->value = strdup(value);
c->value_was_quoted = value_quoted;
c->comment = strdup(comment);
c->domain_from_set = domain_specified;
c->domain = strdup(domain);
c->path_from_set = path_specified;
c->path = strdup(path);
c->expires = expires;
c->last_used = last_used;
c->secure = secure;
c->http_only = http_only;
c->version = version;
c->no_destroy = no_destroy;
 
if (!(c->name && c->value && c->comment &&
c->domain && c->path)) {
urldb_free_cookie(c);
break;
}
 
if (c->domain[0] != '.') {
lwc_string *scheme_lwc = NULL;
nsurl *url_nsurl = NULL;
 
assert(scheme[0] != 'u');
 
if (nsurl_create(url, &url_nsurl) != NSERROR_OK) {
urldb_free_cookie(c);
break;
}
scheme_lwc = nsurl_get_component(url_nsurl,
NSURL_SCHEME);
 
/* And insert it into database */
if (!urldb_insert_cookie(c, scheme_lwc, url_nsurl)) {
/* Cookie freed for us */
nsurl_unref(url_nsurl);
lwc_string_unref(scheme_lwc);
break;
}
nsurl_unref(url_nsurl);
lwc_string_unref(scheme_lwc);
 
} else {
if (!urldb_insert_cookie(c, NULL, NULL)) {
/* Cookie freed for us */
break;
}
}
}
 
#undef SKIP_T
#undef FIND_T
 
fclose(fp);
}
 
/**
* Delete a cookie
*
* \param domain The cookie's domain
* \param path The cookie's path
* \param name The cookie's name
*/
void urldb_delete_cookie(const char *domain, const char *path,
const char *name)
{
urldb_delete_cookie_hosts(domain, path, name, &db_root);
}
 
void urldb_delete_cookie_hosts(const char *domain, const char *path,
const char *name, struct host_part *parent)
{
struct host_part *h;
assert(parent);
 
urldb_delete_cookie_paths(domain, path, name, &parent->paths);
 
for (h = parent->children; h; h = h->next)
urldb_delete_cookie_hosts(domain, path, name, h);
}
 
void urldb_delete_cookie_paths(const char *domain, const char *path,
const char *name, struct path_data *parent)
{
struct cookie_internal_data *c;
struct path_data *p = parent;
 
assert(parent);
 
do {
for (c = p->cookies; c; c = c->next) {
if (strcmp(c->domain, domain) == 0 &&
strcmp(c->path, path) == 0 &&
strcmp(c->name, name) == 0) {
if (c->prev)
c->prev->next = c->next;
else
p->cookies = c->next;
 
if (c->next)
c->next->prev = c->prev;
else
p->cookies_end = c->prev;
 
cookies_remove((struct cookie_data *)c);
urldb_free_cookie(c);
 
return;
}
}
 
if (p->children) {
p = p->children;
} else {
while (p != parent) {
if (p->next != NULL) {
p = p->next;
break;
}
 
p = p->parent;
}
}
} while(p != parent);
}
 
/**
* Save persistent cookies to file
*
* \param filename Path to save to
*/
void urldb_save_cookies(const char *filename)
{
FILE *fp;
int cookie_file_version = max(loaded_cookie_file_version,
COOKIE_FILE_VERSION);
 
assert(filename);
 
fp = fopen(filename, "w");
if (!fp)
return;
 
fprintf(fp, "# >%s\n", filename);
fprintf(fp, "# NetSurf cookies file.\n"
"#\n"
"# Lines starting with a '#' are comments, "
"blank lines are ignored.\n"
"#\n"
"# All lines prior to \"Version:\t%d\" are discarded.\n"
"#\n"
"# Version\tDomain\tDomain from Set-Cookie\tPath\t"
"Path from Set-Cookie\tSecure\tHTTP-Only\tExpires\tLast used\t"
"No destroy\tName\tValue\tValue was quoted\tScheme\t"
"URL\tComment\n",
cookie_file_version);
fprintf(fp, "Version:\t%d\n", cookie_file_version);
 
urldb_save_cookie_hosts(fp, &db_root);
 
fclose(fp);
}
 
/**
* Save a host subtree's cookies
*
* \param fp File pointer to write to
* \param parent Parent host
*/
void urldb_save_cookie_hosts(FILE *fp, struct host_part *parent)
{
struct host_part *h;
assert(fp && parent);
 
urldb_save_cookie_paths(fp, &parent->paths);
 
for (h = parent->children; h; h = h->next)
urldb_save_cookie_hosts(fp, h);
}
 
/**
* Save a path subtree's cookies
*
* \param fp File pointer to write to
* \param parent Parent path
*/
void urldb_save_cookie_paths(FILE *fp, struct path_data *parent)
{
struct path_data *p = parent;
time_t now = time(NULL);
 
assert(fp && parent);
 
do {
if (p->cookies != NULL) {
struct cookie_internal_data *c;
 
for (c = p->cookies; c != NULL; c = c->next) {
if (c->expires == -1 || c->expires < now)
/* Skip expired & session cookies */
continue;
 
fprintf(fp,
"%d\t%s\t%d\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t"
"%s\t%s\t%d\t%s\t%s\t%s\n",
c->version, c->domain,
c->domain_from_set, c->path,
c->path_from_set, c->secure,
c->http_only,
(int)c->expires, (int)c->last_used,
c->no_destroy, c->name, c->value,
c->value_was_quoted,
p->scheme ? lwc_string_data(p->scheme) :
"unused",
p->url ? nsurl_access(p->url) :
"unused",
c->comment ? c->comment : "");
}
}
 
if (p->children != NULL) {
p = p->children;
} else {
while (p != parent) {
if (p->next != NULL) {
p = p->next;
break;
}
 
p = p->parent;
}
}
} while (p != parent);
}
 
 
/**
* Destroy urldb
*/
void urldb_destroy(void)
{
struct host_part *a, *b;
int i;
 
/* Clean up search trees */
for (i = 0; i < NUM_SEARCH_TREES; i++) {
if (search_trees[i] != &empty)
urldb_destroy_search_tree(search_trees[i]);
}
 
/* And database */
for (a = db_root.children; a; a = b) {
b = a->next;
urldb_destroy_host_tree(a);
}
}
 
/**
* Destroy a host tree
*
* \param root Root node of tree to destroy
*/
void urldb_destroy_host_tree(struct host_part *root)
{
struct host_part *a, *b;
struct path_data *p, *q;
struct prot_space_data *s, *t;
 
/* Destroy children */
for (a = root->children; a; a = b) {
b = a->next;
urldb_destroy_host_tree(a);
}
 
/* Now clean up paths */
for (p = root->paths.children; p; p = q) {
q = p->next;
urldb_destroy_path_tree(p);
}
 
/* Root path */
urldb_destroy_path_node_content(&root->paths);
 
/* Proctection space data */
for (s = root->prot_space; s; s = t) {
t = s->next;
urldb_destroy_prot_space(s);
}
 
/* And ourselves */
free(root->part);
free(root);
}
 
/**
* Destroy a path tree
*
* \param root Root node of tree to destroy
*/
void urldb_destroy_path_tree(struct path_data *root)
{
struct path_data *p = root;
 
do {
if (p->children != NULL) {
p = p->children;
} else {
struct path_data *q = p;
 
while (p != root) {
if (p->next != NULL) {
p = p->next;
break;
}
 
p = p->parent;
 
urldb_destroy_path_node_content(q);
free(q);
 
q = p;
}
 
urldb_destroy_path_node_content(q);
free(q);
}
} while (p != root);
}
 
/**
* Destroy the contents of a path node
*
* \param node Node to destroy contents of (does not destroy node)
*/
void urldb_destroy_path_node_content(struct path_data *node)
{
struct cookie_internal_data *a, *b;
unsigned int i;
 
if (node->url != NULL)
nsurl_unref(node->url);
 
if (node->scheme != NULL)
lwc_string_unref(node->scheme);
 
free(node->segment);
for (i = 0; i < node->frag_cnt; i++)
free(node->fragment[i]);
free(node->fragment);
 
if (node->thumb)
bitmap_destroy(node->thumb);
 
free(node->urld.title);
 
for (a = node->cookies; a; a = b) {
b = a->next;
urldb_destroy_cookie(a);
}
}
 
/**
* Destroy a cookie node
*
* \param c Cookie to destroy
*/
void urldb_destroy_cookie(struct cookie_internal_data *c)
{
free(c->name);
free(c->value);
free(c->comment);
free(c->domain);
free(c->path);
 
free(c);
}
 
/**
* Destroy protection space data
*
* \param space Protection space to destroy
*/
void urldb_destroy_prot_space(struct prot_space_data *space)
{
lwc_string_unref(space->scheme);
free(space->realm);
free(space->auth);
 
free(space);
}
 
 
/**
* Destroy a search tree
*
* \param root Root node of tree to destroy
*/
void urldb_destroy_search_tree(struct search_node *root)
{
/* Destroy children */
if (root->left != &empty)
urldb_destroy_search_tree(root->left);
if (root->right != &empty)
urldb_destroy_search_tree(root->right);
 
/* And destroy ourselves */
free(root);
}
 
/programs/network/netsurf/netsurf/content/urldb.h
0,0 → 1,124
/*
* Copyright 2006 John M Bell <jmb202@ecs.soton.ac.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Unified URL information database (interface)
*/
 
#ifndef _NETSURF_CONTENT_URLDB_H_
#define _NETSURF_CONTENT_URLDB_H_
 
#include <stdbool.h>
#include <time.h>
#include "content/content.h"
#include "content/content_type.h"
#include "utils/nsurl.h"
 
typedef enum {
COOKIE_NETSCAPE = 0,
COOKIE_RFC2109 = 1,
COOKIE_RFC2965 = 2
} cookie_version;
 
struct url_data {
const char *title; /**< Resource title */
unsigned int visits; /**< Visit count */
time_t last_visit; /**< Last visit time */
content_type type; /**< Type of resource */
};
 
struct cookie_data {
const char *name; /**< Cookie name */
const char *value; /**< Cookie value */
const bool value_was_quoted; /**< Value was quoted in Set-Cookie: */
const char *comment; /**< Cookie comment */
const bool domain_from_set; /**< Domain came from Set-Cookie: header */
const char *domain; /**< Domain */
const bool path_from_set; /**< Path came from Set-Cookie: header */
const char *path; /**< Path */
const time_t expires; /**< Expiry timestamp, or 1 for session */
const time_t last_used; /**< Last used time */
const bool secure; /**< Only send for HTTPS requests */
const bool http_only; /**< Only expose to HTTP(S) requests */
cookie_version version; /**< Specification compliance */
const bool no_destroy; /**< Never destroy this cookie,
* unless it's expired */
 
const struct cookie_data *prev; /**< Previous in list */
const struct cookie_data *next; /**< Next in list */
};
 
struct bitmap;
 
/* Destruction */
void urldb_destroy(void);
 
/* Persistence support */
void urldb_load(const char *filename);
void urldb_save(const char *filename);
void urldb_set_url_persistence(nsurl *url, bool persist);
 
/* URL insertion */
bool urldb_add_url(nsurl *url);
struct host_part *urldb_add_host(const char *host);
struct path_data *urldb_add_path(lwc_string *scheme, unsigned int port,
const struct host_part *host, char *path_query,
lwc_string *fragment, nsurl *url);
 
/* URL data modification / lookup */
void urldb_set_url_title(nsurl *url, const char *title);
void urldb_set_url_content_type(nsurl *url, content_type type);
void urldb_update_url_visit_data(nsurl *url);
void urldb_reset_url_visit_data(nsurl *url);
const struct url_data *urldb_get_url_data(nsurl *url);
nsurl *urldb_get_url(nsurl *url);
 
/* Authentication modification / lookup */
void urldb_set_auth_details(nsurl *url, const char *realm,
const char *auth);
const char *urldb_get_auth_details(nsurl *url, const char *realm);
 
/* SSL certificate permissions */
void urldb_set_cert_permissions(nsurl *url, bool permit);
bool urldb_get_cert_permissions(nsurl *url);
 
/* Thumbnail handling */
void urldb_set_thumbnail(nsurl *url, struct bitmap *bitmap);
struct bitmap *urldb_get_thumbnail(nsurl *url);
 
/* URL completion */
void urldb_iterate_partial(const char *prefix,
bool (*callback)(nsurl *url,
const struct url_data *data));
 
/* Iteration */
void urldb_iterate_entries(bool (*callback)(nsurl *url,
const struct url_data *data));
void urldb_iterate_cookies(bool (*callback)(const struct cookie_data *cookie));
 
/* Debug */
void urldb_dump(void);
 
/* Cookies */
bool urldb_set_cookie(const char *header, nsurl *url, nsurl *referer);
char *urldb_get_cookie(nsurl *url, bool include_http_only);
void urldb_delete_cookie(const char *domain, const char *path, const char *name);
void urldb_load_cookies(const char *filename);
void urldb_save_cookies(const char *filename);
 
#endif
/programs/network/netsurf/netsurf/css/css.c
0,0 → 1,819
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <assert.h>
 
#include <libwapcaplet/libwapcaplet.h>
#include <dom/dom.h>
 
#include "content/content_protected.h"
#include "content/fetch.h"
#include "content/hlcache.h"
#include "css/css.h"
#include "css/internal.h"
#include "desktop/gui.h"
#include "render/html.h"
#include "utils/utils.h"
#include "utils/http.h"
#include "utils/log.h"
#include "utils/messages.h"
 
/* Define to trace import fetches */
#undef NSCSS_IMPORT_TRACE
 
/**
* CSS content data
*/
typedef struct nscss_content
{
struct content base; /**< Underlying content object */
 
struct content_css_data data; /**< CSS data */
} nscss_content;
 
/**
* Context for import fetches
*/
typedef struct {
struct content_css_data *css; /**< Object containing import */
uint32_t index; /**< Index into parent sheet's
* imports array */
} nscss_import_ctx;
 
static nserror nscss_create(const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c);
static bool nscss_process_data(struct content *c, const char *data,
unsigned int size);
static bool nscss_convert(struct content *c);
static void nscss_destroy(struct content *c);
static nserror nscss_clone(const struct content *old, struct content **newc);
static bool nscss_matches_quirks(const struct content *c, bool quirks);
static content_type nscss_content_type(void);
 
static void nscss_content_done(struct content_css_data *css, void *pw);
static css_error nscss_handle_import(void *pw, css_stylesheet *parent,
lwc_string *url, uint64_t media);
static nserror nscss_import(hlcache_handle *handle,
const hlcache_event *event, void *pw);
static css_error nscss_import_complete(nscss_import_ctx *ctx);
 
static css_error nscss_register_imports(struct content_css_data *c);
static css_error nscss_register_import(struct content_css_data *c,
const hlcache_handle *import);
 
 
static lwc_string *css_charset;
static css_stylesheet *blank_import;
 
 
/**
* Initialise a CSS content
*
* \param c Content to initialise
* \param params Content-Type parameters
* \return true on success, false on failure
*/
nserror nscss_create(const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
nscss_content *result;
const char *charset = NULL;
lwc_string *charset_value = NULL;
union content_msg_data msg_data;
nserror error;
 
result = calloc(1, sizeof(nscss_content));
if (result == NULL)
return NSERROR_NOMEM;
 
error = content__init(&result->base, handler, imime_type,
params, llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(result);
return error;
}
 
/* Find charset specified on HTTP layer, if any */
error = http_parameter_list_find_item(params, css_charset,
&charset_value);
if (error != NSERROR_OK || lwc_string_length(charset_value) == 0) {
/* No charset specified, use fallback, if any */
/** \todo libcss will take this as gospel, which is wrong */
charset = fallback_charset;
} else {
charset = lwc_string_data(charset_value);
}
 
error = nscss_create_css_data(&result->data,
nsurl_access(content_get_url(&result->base)),
charset, result->base.quirks,
nscss_content_done, result);
if (error != NSERROR_OK) {
msg_data.error = messages_get("NoMemory");
content_broadcast(&result->base, CONTENT_MSG_ERROR, msg_data);
if (charset_value != NULL)
lwc_string_unref(charset_value);
free(result);
return error;
}
 
if (charset_value != NULL)
lwc_string_unref(charset_value);
 
*c = (struct content *) result;
 
return NSERROR_OK;
}
 
/**
* Create a struct content_css_data, creating a stylesheet object
*
* \param c Struct to populate
* \param url URL of stylesheet
* \param charset Stylesheet charset
* \param quirks Stylesheet quirks mode
* \param done Callback to call when content has completed
* \param pw Client data for \a done
* \return NSERROR_OK on success, NSERROR_NOMEM on memory exhaustion
*/
nserror nscss_create_css_data(struct content_css_data *c,
const char *url, const char *charset, bool quirks,
nscss_done_callback done, void *pw)
{
css_error error;
css_stylesheet_params params;
 
c->pw = pw;
c->done = done;
c->next_to_register = (uint32_t) -1;
c->import_count = 0;
c->imports = NULL;
if (charset != NULL)
c->charset = strdup(charset);
else
c->charset = NULL;
 
params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1;
params.level = CSS_LEVEL_DEFAULT;
params.charset = charset;
params.url = url;
params.title = NULL;
params.allow_quirks = quirks;
params.inline_style = false;
params.resolve = nscss_resolve_url;
params.resolve_pw = NULL;
params.import = nscss_handle_import;
params.import_pw = c;
params.color = gui_system_colour;
params.color_pw = NULL;
params.font = NULL;
params.font_pw = NULL;
 
error = css_stylesheet_create(&params, ns_realloc, NULL, &c->sheet);
if (error != CSS_OK) {
return NSERROR_NOMEM;
}
 
return NSERROR_OK;
}
 
/**
* Process CSS source data
*
* \param c Content structure
* \param data Data to process
* \param size Number of bytes to process
* \return true on success, false on failure
*/
bool nscss_process_data(struct content *c, const char *data, unsigned int size)
{
nscss_content *css = (nscss_content *) c;
union content_msg_data msg_data;
css_error error;
 
error = nscss_process_css_data(&css->data, data, size);
if (error != CSS_OK && error != CSS_NEEDDATA) {
msg_data.error = "?";
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
}
 
return (error == CSS_OK || error == CSS_NEEDDATA);
}
 
/**
* Process CSS data
*
* \param c CSS content object
* \param data Data to process
* \param size Number of bytes to process
* \return CSS_OK on success, appropriate error otherwise
*/
css_error nscss_process_css_data(struct content_css_data *c, const char *data,
unsigned int size)
{
return css_stylesheet_append_data(c->sheet,
(const uint8_t *) data, size);
}
 
/**
* Convert a CSS content ready for use
*
* \param c Content to convert
* \return true on success, false on failure
*/
bool nscss_convert(struct content *c)
{
nscss_content *css = (nscss_content *) c;
union content_msg_data msg_data;
css_error error;
 
error = nscss_convert_css_data(&css->data);
if (error != CSS_OK) {
msg_data.error = "?";
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
return true;
}
 
/**
* Convert CSS data ready for use
*
* \param c CSS data to convert
* \return CSS error
*/
css_error nscss_convert_css_data(struct content_css_data *c)
{
css_error error;
 
error = css_stylesheet_data_done(c->sheet);
 
/* Process pending imports */
if (error == CSS_IMPORTS_PENDING) {
/* We must not have registered any imports yet */
assert(c->next_to_register == (uint32_t) -1);
 
/* Start registering, until we find one that
* hasn't finished fetching */
c->next_to_register = 0;
error = nscss_register_imports(c);
} else if (error == CSS_OK) {
/* No imports, and no errors, so complete conversion */
c->done(c, c->pw);
} else {
const char *url;
 
if (css_stylesheet_get_url(c->sheet, &url) == CSS_OK) {
LOG(("Failed converting %p %s (%d)", c, url, error));
} else {
LOG(("Failed converting %p (%d)", c, error));
}
}
 
return error;
}
 
/**
* Clean up a CSS content
*
* \param c Content to clean up
*/
void nscss_destroy(struct content *c)
{
nscss_content *css = (nscss_content *) c;
 
nscss_destroy_css_data(&css->data);
}
 
/**
* Clean up CSS data
*
* \param c CSS data to clean up
*/
void nscss_destroy_css_data(struct content_css_data *c)
{
uint32_t i;
 
for (i = 0; i < c->import_count; i++) {
if (c->imports[i].c != NULL) {
hlcache_handle_release(c->imports[i].c);
}
c->imports[i].c = NULL;
}
 
free(c->imports);
 
if (c->sheet != NULL) {
css_stylesheet_destroy(c->sheet);
c->sheet = NULL;
}
 
free(c->charset);
}
 
nserror nscss_clone(const struct content *old, struct content **newc)
{
const nscss_content *old_css = (const nscss_content *) old;
nscss_content *new_css;
const char *data;
unsigned long size;
nserror error;
 
new_css = calloc(1, sizeof(nscss_content));
if (new_css == NULL)
return NSERROR_NOMEM;
 
/* Clone content */
error = content__clone(old, &new_css->base);
if (error != NSERROR_OK) {
content_destroy(&new_css->base);
return error;
}
 
/* Simply replay create/process/convert */
error = nscss_create_css_data(&new_css->data,
nsurl_access(content_get_url(&new_css->base)),
old_css->data.charset,
new_css->base.quirks,
nscss_content_done, new_css);
if (error != NSERROR_OK) {
content_destroy(&new_css->base);
return error;
}
 
data = content__get_source_data(&new_css->base, &size);
if (size > 0) {
if (nscss_process_data(&new_css->base, data, size) == false) {
content_destroy(&new_css->base);
return NSERROR_CLONE_FAILED;
}
}
 
if (old->status == CONTENT_STATUS_READY ||
old->status == CONTENT_STATUS_DONE) {
if (nscss_convert(&new_css->base) == false) {
content_destroy(&new_css->base);
return NSERROR_CLONE_FAILED;
}
}
 
*newc = (struct content *) new_css;
 
return NSERROR_OK;
}
 
bool nscss_matches_quirks(const struct content *c, bool quirks)
{
return c->quirks == quirks;
}
 
/**
* Retrieve the stylesheet object associated with a CSS content
*
* \param h Stylesheet content
* \return Pointer to stylesheet object
*/
css_stylesheet *nscss_get_stylesheet(struct hlcache_handle *h)
{
nscss_content *c = (nscss_content *) hlcache_handle_get_content(h);
 
assert(c != NULL);
 
return c->data.sheet;
}
 
/**
* Retrieve imported stylesheets
*
* \param h Stylesheet containing imports
* \param n Pointer to location to receive number of imports
* \return Pointer to array of imported stylesheets
*/
struct nscss_import *nscss_get_imports(hlcache_handle *h, uint32_t *n)
{
nscss_content *c = (nscss_content *) hlcache_handle_get_content(h);
 
assert(c != NULL);
assert(n != NULL);
 
*n = c->data.import_count;
 
return c->data.imports;
}
 
/**
* Compute the type of a content
*
* \return CONTENT_CSS
*/
content_type nscss_content_type(void)
{
return CONTENT_CSS;
}
 
/*****************************************************************************
* Object completion *
*****************************************************************************/
 
/**
* Handle notification that a CSS object is done
*
* \param css CSS object
* \param pw Private data
*/
void nscss_content_done(struct content_css_data *css, void *pw)
{
union content_msg_data msg_data;
struct content *c = pw;
uint32_t i;
size_t size;
css_error error;
 
/* Retrieve the size of this sheet */
error = css_stylesheet_size(css->sheet, &size);
if (error != CSS_OK) {
msg_data.error = "?";
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
content_set_error(c);
return;
}
c->size += size;
 
/* Add on the size of the imported sheets */
for (i = 0; i < css->import_count; i++) {
if (css->imports[i].c != NULL) {
struct content *import = hlcache_handle_get_content(
css->imports[i].c);
 
if (import != NULL) {
c->size += import->size;
}
}
}
 
/* Finally, catch the content's users up with reality */
content_set_ready(c);
content_set_done(c);
}
 
/*****************************************************************************
* Import handling *
*****************************************************************************/
 
/**
* Handle notification of the need for an imported stylesheet
*
* \param pw CSS object requesting the import
* \param parent Stylesheet requesting the import
* \param url URL of the imported sheet
* \param media Applicable media for the imported sheet
* \return CSS_OK on success, appropriate error otherwise
*/
css_error nscss_handle_import(void *pw, css_stylesheet *parent,
lwc_string *url, uint64_t media)
{
content_type accept = CONTENT_CSS;
struct content_css_data *c = pw;
nscss_import_ctx *ctx;
hlcache_child_context child;
struct nscss_import *imports;
const char *referer;
css_error error;
nserror nerror;
 
nsurl *ns_url;
nsurl *ns_ref;
 
assert(parent == c->sheet);
 
error = css_stylesheet_get_url(c->sheet, &referer);
if (error != CSS_OK) {
return error;
}
 
ctx = malloc(sizeof(*ctx));
if (ctx == NULL)
return CSS_NOMEM;
 
ctx->css = c;
ctx->index = c->import_count;
 
/* Increase space in table */
imports = realloc(c->imports, (c->import_count + 1) *
sizeof(struct nscss_import));
if (imports == NULL) {
free(ctx);
return CSS_NOMEM;
}
c->imports = imports;
 
/** \todo fallback charset */
child.charset = NULL;
error = css_stylesheet_quirks_allowed(c->sheet, &child.quirks);
if (error != CSS_OK) {
free(ctx);
return error;
}
 
/* Create content */
c->imports[c->import_count].media = media;
 
/* TODO: Why aren't we getting a relative url part, to join? */
nerror = nsurl_create(lwc_string_data(url), &ns_url);
if (nerror != NSERROR_OK) {
free(ctx);
return CSS_NOMEM;
}
 
/* TODO: Constructing nsurl for referer here is silly, avoid */
nerror = nsurl_create(referer, &ns_ref);
if (nerror != NSERROR_OK) {
nsurl_unref(ns_url);
free(ctx);
return CSS_NOMEM;
}
 
/* Avoid importing ourself */
if (nsurl_compare(ns_url, ns_ref, NSURL_COMPLETE)) {
c->imports[c->import_count].c = NULL;
/* No longer require context as we're not fetching anything */
free(ctx);
ctx = NULL;
} else {
nerror = hlcache_handle_retrieve(ns_url,
0, ns_ref, NULL, nscss_import, ctx,
&child, accept,
&c->imports[c->import_count].c);
if (nerror != NSERROR_OK) {
free(ctx);
return CSS_NOMEM;
}
}
 
nsurl_unref(ns_url);
nsurl_unref(ns_ref);
 
#ifdef NSCSS_IMPORT_TRACE
LOG(("Import %d '%s' -> (handle: %p ctx: %p)",
c->import_count, lwc_string_data(url),
c->imports[c->import_count].c, ctx));
#endif
 
c->import_count++;
 
return CSS_OK;
}
 
/**
* Handler for imported stylesheet events
*
* \param handle Handle for stylesheet
* \param event Event object
* \param pw Callback context
* \return NSERROR_OK on success, appropriate error otherwise
*/
nserror nscss_import(hlcache_handle *handle,
const hlcache_event *event, void *pw)
{
nscss_import_ctx *ctx = pw;
css_error error = CSS_OK;
 
#ifdef NSCSS_IMPORT_TRACE
LOG(("Event %d for %p (%p)", event->type, handle, ctx));
#endif
 
assert(ctx->css->imports[ctx->index].c == handle);
 
switch (event->type) {
case CONTENT_MSG_LOADING:
break;
case CONTENT_MSG_READY:
break;
case CONTENT_MSG_DONE:
error = nscss_import_complete(ctx);
break;
case CONTENT_MSG_ERROR:
hlcache_handle_release(handle);
ctx->css->imports[ctx->index].c = NULL;
 
error = nscss_import_complete(ctx);
/* Already released handle */
break;
case CONTENT_MSG_STATUS:
break;
default:
assert(0);
}
 
/* Preserve out-of-memory. Anything else is OK */
return error == CSS_NOMEM ? NSERROR_NOMEM : NSERROR_OK;
}
 
/**
* Handle an imported stylesheet completing
*
* \param ctx Import context
* \return CSS_OK on success, appropriate error otherwise
*/
css_error nscss_import_complete(nscss_import_ctx *ctx)
{
css_error error = CSS_OK;
 
/* If this import is the next to be registered, do so */
if (ctx->css->next_to_register == ctx->index)
error = nscss_register_imports(ctx->css);
 
#ifdef NSCSS_IMPORT_TRACE
LOG(("Destroying import context %p for %d", ctx, ctx->index));
#endif
 
/* No longer need import context */
free(ctx);
 
return error;
}
 
/*****************************************************************************
* Import registration *
*****************************************************************************/
 
/**
* Register imports with a stylesheet
*
* \param c CSS object containing the imports
* \return CSS_OK on success, appropriate error otherwise
*/
css_error nscss_register_imports(struct content_css_data *c)
{
uint32_t index;
css_error error;
 
assert(c->next_to_register != (uint32_t) -1);
assert(c->next_to_register < c->import_count);
 
/* Register imported sheets */
for (index = c->next_to_register; index < c->import_count; index++) {
/* Stop registering if we encounter one whose fetch hasn't
* completed yet. We'll resume at this point when it has
* completed.
*/
if (c->imports[index].c != NULL &&
content_get_status(c->imports[index].c) !=
CONTENT_STATUS_DONE) {
break;
}
 
error = nscss_register_import(c, c->imports[index].c);
if (error != CSS_OK)
return error;
}
 
/* Record identity of the next import to register */
c->next_to_register = (uint32_t) index;
 
if (c->next_to_register == c->import_count) {
/* No more imports: notify parent that we're DONE */
c->done(c, c->pw);
}
 
return CSS_OK;
}
 
 
/**
* Register an import with a stylesheet
*
* \param c CSS object that requested the import
* \param import Cache handle of import, or NULL for blank
* \return CSS_OK on success, appropriate error otherwise
*/
css_error nscss_register_import(struct content_css_data *c,
const hlcache_handle *import)
{
css_stylesheet *sheet;
css_error error;
 
if (import != NULL) {
nscss_content *s =
(nscss_content *) hlcache_handle_get_content(import);
sheet = s->data.sheet;
} else {
/* Create a blank sheet if needed. */
if (blank_import == NULL) {
css_stylesheet_params params;
 
params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1;
params.level = CSS_LEVEL_DEFAULT;
params.charset = NULL;
params.url = "";
params.title = NULL;
params.allow_quirks = false;
params.inline_style = false;
params.resolve = nscss_resolve_url;
params.resolve_pw = NULL;
params.import = NULL;
params.import_pw = NULL;
params.color = gui_system_colour;
params.color_pw = NULL;
params.font = NULL;
params.font_pw = NULL;
 
error = css_stylesheet_create(&params,
ns_realloc, NULL,
&blank_import);
if (error != CSS_OK) {
return error;
}
 
error = css_stylesheet_data_done(blank_import);
if (error != CSS_OK) {
css_stylesheet_destroy(blank_import);
return error;
}
}
 
sheet = blank_import;
}
 
error = css_stylesheet_register_import(c->sheet, sheet);
if (error != CSS_OK) {
return error;
}
 
return error;
}
 
/**
* Clean up after the CSS content handler
*/
static void nscss_fini(void)
{
if (css_charset != NULL) {
lwc_string_unref(css_charset);
css_charset = NULL;
}
 
if (blank_import != NULL) {
css_stylesheet_destroy(blank_import);
blank_import = NULL;
}
}
 
static const content_handler css_content_handler = {
.fini = nscss_fini,
.create = nscss_create,
.process_data = nscss_process_data,
.data_complete = nscss_convert,
.destroy = nscss_destroy,
.clone = nscss_clone,
.matches_quirks = nscss_matches_quirks,
.type = nscss_content_type,
.no_share = false,
};
 
/**
* Initialise the CSS content handler
*/
nserror nscss_init(void)
{
lwc_error lerror;
nserror error;
 
lerror = lwc_intern_string("charset", SLEN("charset"), &css_charset);
if (lerror != lwc_error_ok) {
error = NSERROR_NOMEM;
goto error;
}
 
error = content_factory_register_handler("text/css",
&css_content_handler);
if (error != NSERROR_OK)
goto error;
 
return NSERROR_OK;
 
error:
nscss_fini();
 
return error;
}
/programs/network/netsurf/netsurf/css/css.h
0,0 → 1,78
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef netsurf_css_css_h_
#define netsurf_css_css_h_
 
#include <stdint.h>
 
#include <libcss/libcss.h>
 
#include "utils/errors.h"
 
struct content;
struct content_css_data;
struct hlcache_handle;
struct http_parameter;
struct nscss_import;
 
/**
* Type of callback called when a CSS object has finished
*
* \param css CSS object that has completed
* \param pw Client-specific data
*/
typedef void (*nscss_done_callback)(struct content_css_data *css, void *pw);
 
/**
* CSS content data
*/
struct content_css_data
{
css_stylesheet *sheet; /**< Stylesheet object */
char *charset; /**< Character set of stylesheet */
struct nscss_import *imports; /**< Array of imported sheets */
uint32_t import_count; /**< Number of sheets imported */
uint32_t next_to_register; /**< Index of next import to register */
nscss_done_callback done; /**< Completion callback */
void *pw; /**< Client data */
};
 
/**
* Imported stylesheet record
*/
struct nscss_import {
struct hlcache_handle *c; /**< Content containing sheet */
uint64_t media; /**< Media types that sheet applies to */
};
 
nserror nscss_init(void);
 
nserror nscss_create_css_data(struct content_css_data *c,
const char *url, const char *charset, bool quirks,
nscss_done_callback done, void *pw);
css_error nscss_process_css_data(struct content_css_data *c, const char *data,
unsigned int size);
css_error nscss_convert_css_data(struct content_css_data *c);
void nscss_destroy_css_data(struct content_css_data *c);
 
css_stylesheet *nscss_get_stylesheet(struct hlcache_handle *h);
struct nscss_import *nscss_get_imports(struct hlcache_handle *h, uint32_t *n);
 
#endif
 
/programs/network/netsurf/netsurf/css/dump.c
0,0 → 1,1787
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdio.h>
 
#include "css/dump.h"
 
static void dump_css_fixed(FILE *stream, css_fixed f);
static void dump_css_number(FILE *stream, css_fixed val);
static void dump_css_unit(FILE *stream, css_fixed val, css_unit unit);
 
/**
* Dump a computed style \a style to the give file handle \a stream.
*
* \param stream Stream to write to
* \param style Computed style to dump
*/
void nscss_dump_computed_style(FILE *stream, const css_computed_style *style)
{
uint8_t val;
css_color color = 0;
lwc_string *url = NULL;
css_fixed len1 = 0, len2 = 0;
css_unit unit1 = CSS_UNIT_PX, unit2 = CSS_UNIT_PX;
css_computed_clip_rect rect = { 0, 0, 0, 0, CSS_UNIT_PX, CSS_UNIT_PX,
CSS_UNIT_PX, CSS_UNIT_PX, true, true,
true, true };
const css_computed_content_item *content = NULL;
const css_computed_counter *counter = NULL;
lwc_string **string_list = NULL;
int32_t zindex = 0;
 
fprintf(stream, "{ ");
 
/* background-attachment */
val = css_computed_background_attachment(style);
switch (val) {
case CSS_BACKGROUND_ATTACHMENT_FIXED:
fprintf(stream, "background-attachment: fixed ");
break;
case CSS_BACKGROUND_ATTACHMENT_SCROLL:
fprintf(stream, "background-attachment: scroll ");
break;
default:
break;
}
 
/* background-color */
val = css_computed_background_color(style, &color);
switch (val) {
case CSS_BACKGROUND_COLOR_COLOR:
fprintf(stream, "background-color: #%08x ", color);
break;
default:
break;
}
 
/* background-image */
val = css_computed_background_image(style, &url);
if (val == CSS_BACKGROUND_IMAGE_IMAGE && url != NULL) {
fprintf(stream, "background-image: url('%.*s') ",
(int) lwc_string_length(url),
lwc_string_data(url));
} else if (val == CSS_BACKGROUND_IMAGE_NONE) {
fprintf(stream, "background-image: none ");
}
 
/* background-position */
val = css_computed_background_position(style, &len1, &unit1,
&len2, &unit2);
if (val == CSS_BACKGROUND_POSITION_SET) {
fprintf(stream, "background-position: ");
dump_css_unit(stream, len1, unit1);
fprintf(stream, " ");
dump_css_unit(stream, len2, unit2);
fprintf(stream, " ");
}
 
/* background-repeat */
val = css_computed_background_repeat(style);
switch (val) {
case CSS_BACKGROUND_REPEAT_REPEAT_X:
fprintf(stream, "background-repeat: repeat-x ");
break;
case CSS_BACKGROUND_REPEAT_REPEAT_Y:
fprintf(stream, "background-repeat: repeat-y ");
break;
case CSS_BACKGROUND_REPEAT_REPEAT:
fprintf(stream, "background-repeat: repeat ");
break;
case CSS_BACKGROUND_REPEAT_NO_REPEAT:
fprintf(stream, "background-repeat: no-repeat ");
break;
default:
break;
}
 
/* border-collapse */
val = css_computed_border_collapse(style);
switch (val) {
case CSS_BORDER_COLLAPSE_SEPARATE:
fprintf(stream, "border-collapse: separate ");
break;
case CSS_BORDER_COLLAPSE_COLLAPSE:
fprintf(stream, "border-collapse: collapse ");
break;
default:
 
break;
}
 
/* border-spacing */
val = css_computed_border_spacing(style, &len1, &unit1, &len2, &unit2);
if (val == CSS_BORDER_SPACING_SET) {
fprintf(stream, "border-spacing: ");
dump_css_unit(stream, len1, unit1);
fprintf(stream, " ");
dump_css_unit(stream, len2, unit2);
fprintf(stream, " ");
}
 
/* border-top-color */
val = css_computed_border_top_color(style, &color);
switch (val) {
case CSS_BORDER_COLOR_COLOR:
fprintf(stream, "border-top-color: #%08x ", color);
break;
default:
break;
}
 
/* border-right-color */
val = css_computed_border_right_color(style, &color);
switch (val) {
case CSS_BORDER_COLOR_COLOR:
fprintf(stream, "border-right-color: #%08x ", color);
break;
default:
break;
}
 
/* border-bottom-color */
val = css_computed_border_bottom_color(style, &color);
switch (val) {
case CSS_BORDER_COLOR_COLOR:
fprintf(stream, "border-bottom-color: #%08x ", color);
break;
default:
break;
}
 
/* border-left-color */
val = css_computed_border_left_color(style, &color);
switch (val) {
case CSS_BORDER_COLOR_COLOR:
fprintf(stream, "border-left-color: #%08x ", color);
break;
default:
break;
}
 
/* border-top-style */
val = css_computed_border_top_style(style);
switch (val) {
case CSS_BORDER_STYLE_NONE:
fprintf(stream, "border-top-style: none ");
break;
case CSS_BORDER_STYLE_HIDDEN:
fprintf(stream, "border-top-style: hidden ");
break;
case CSS_BORDER_STYLE_DOTTED:
fprintf(stream, "border-top-style: dotted ");
break;
case CSS_BORDER_STYLE_DASHED:
fprintf(stream, "border-top-style: dashed ");
break;
case CSS_BORDER_STYLE_SOLID:
fprintf(stream, "border-top-style: solid ");
break;
case CSS_BORDER_STYLE_DOUBLE:
fprintf(stream, "border-top-style: double ");
break;
case CSS_BORDER_STYLE_GROOVE:
fprintf(stream, "border-top-style: groove ");
break;
case CSS_BORDER_STYLE_RIDGE:
fprintf(stream, "border-top-style: ridge ");
break;
case CSS_BORDER_STYLE_INSET:
fprintf(stream, "border-top-style: inset ");
break;
case CSS_BORDER_STYLE_OUTSET:
fprintf(stream, "border-top-style: outset ");
break;
default:
break;
}
 
/* border-right-style */
val = css_computed_border_right_style(style);
switch (val) {
case CSS_BORDER_STYLE_NONE:
fprintf(stream, "border-right-style: none ");
break;
case CSS_BORDER_STYLE_HIDDEN:
fprintf(stream, "border-right-style: hidden ");
break;
case CSS_BORDER_STYLE_DOTTED:
fprintf(stream, "border-right-style: dotted ");
break;
case CSS_BORDER_STYLE_DASHED:
fprintf(stream, "border-right-style: dashed ");
break;
case CSS_BORDER_STYLE_SOLID:
fprintf(stream, "border-right-style: solid ");
break;
case CSS_BORDER_STYLE_DOUBLE:
fprintf(stream, "border-right-style: double ");
break;
case CSS_BORDER_STYLE_GROOVE:
fprintf(stream, "border-right-style: groove ");
break;
case CSS_BORDER_STYLE_RIDGE:
fprintf(stream, "border-right-style: ridge ");
break;
case CSS_BORDER_STYLE_INSET:
fprintf(stream, "border-right-style: inset ");
break;
case CSS_BORDER_STYLE_OUTSET:
fprintf(stream, "border-right-style: outset ");
break;
default:
break;
}
 
/* border-bottom-style */
val = css_computed_border_bottom_style(style);
switch (val) {
case CSS_BORDER_STYLE_NONE:
fprintf(stream, "border-bottom-style: none ");
break;
case CSS_BORDER_STYLE_HIDDEN:
fprintf(stream, "border-bottom-style: hidden ");
break;
case CSS_BORDER_STYLE_DOTTED:
fprintf(stream, "border-bottom-style: dotted ");
break;
case CSS_BORDER_STYLE_DASHED:
fprintf(stream, "border-bottom-style: dashed ");
break;
case CSS_BORDER_STYLE_SOLID:
fprintf(stream, "border-bottom-style: solid ");
break;
case CSS_BORDER_STYLE_DOUBLE:
fprintf(stream, "border-bottom-style: double ");
break;
case CSS_BORDER_STYLE_GROOVE:
fprintf(stream, "border-bottom-style: groove ");
break;
case CSS_BORDER_STYLE_RIDGE:
fprintf(stream, "border-bottom-style: ridge ");
break;
case CSS_BORDER_STYLE_INSET:
fprintf(stream, "border-bottom-style: inset ");
break;
case CSS_BORDER_STYLE_OUTSET:
fprintf(stream, "border-bottom-style: outset ");
break;
default:
break;
}
 
/* border-left-style */
val = css_computed_border_left_style(style);
switch (val) {
case CSS_BORDER_STYLE_NONE:
fprintf(stream, "border-left-style: none ");
break;
case CSS_BORDER_STYLE_HIDDEN:
fprintf(stream, "border-left-style: hidden ");
break;
case CSS_BORDER_STYLE_DOTTED:
fprintf(stream, "border-left-style: dotted ");
break;
case CSS_BORDER_STYLE_DASHED:
fprintf(stream, "border-left-style: dashed ");
break;
case CSS_BORDER_STYLE_SOLID:
fprintf(stream, "border-left-style: solid ");
break;
case CSS_BORDER_STYLE_DOUBLE:
fprintf(stream, "border-left-style: double ");
break;
case CSS_BORDER_STYLE_GROOVE:
fprintf(stream, "border-left-style: groove ");
break;
case CSS_BORDER_STYLE_RIDGE:
fprintf(stream, "border-left-style: ridge ");
break;
case CSS_BORDER_STYLE_INSET:
fprintf(stream, "border-left-style: inset ");
break;
case CSS_BORDER_STYLE_OUTSET:
fprintf(stream, "border-left-style: outset ");
break;
default:
break;
}
 
/* border-top-width */
val = css_computed_border_top_width(style, &len1, &unit1);
switch (val) {
case CSS_BORDER_WIDTH_THIN:
fprintf(stream, "border-top-width: thin ");
break;
case CSS_BORDER_WIDTH_MEDIUM:
fprintf(stream, "border-top-width: medium ");
break;
case CSS_BORDER_WIDTH_THICK:
fprintf(stream, "border-top-width: thick ");
break;
case CSS_BORDER_WIDTH_WIDTH:
fprintf(stream, "border-top-width: ");
dump_css_unit(stream, len1, unit1);
fprintf(stream, " ");
break;
default:
break;
}
 
/* border-right-width */
val = css_computed_border_right_width(style, &len1, &unit1);
switch (val) {
case CSS_BORDER_WIDTH_THIN:
fprintf(stream, "border-right-width: thin ");
break;
case CSS_BORDER_WIDTH_MEDIUM:
fprintf(stream, "border-right-width: medium ");
break;
case CSS_BORDER_WIDTH_THICK:
fprintf(stream, "border-right-width: thick ");
break;
case CSS_BORDER_WIDTH_WIDTH:
fprintf(stream, "border-right-width: ");
dump_css_unit(stream, len1, unit1);
fprintf(stream, " ");
break;
default:
break;
}
 
/* border-bottom-width */
val = css_computed_border_bottom_width(style, &len1, &unit1);
switch (val) {
case CSS_BORDER_WIDTH_THIN:
fprintf(stream, "border-bottom-width: thin ");
break;
case CSS_BORDER_WIDTH_MEDIUM:
fprintf(stream, "border-bottom-width: medium ");
break;
case CSS_BORDER_WIDTH_THICK:
fprintf(stream, "border-bottom-width: thick ");
break;
case CSS_BORDER_WIDTH_WIDTH:
fprintf(stream, "border-bottom-width: ");
dump_css_unit(stream, len1, unit1);
fprintf(stream, " ");
break;
default:
break;
}
 
/* border-left-width */
val = css_computed_border_left_width(style, &len1, &unit1);
switch (val) {
case CSS_BORDER_WIDTH_THIN:
fprintf(stream, "border-left-width: thin ");
break;
case CSS_BORDER_WIDTH_MEDIUM:
fprintf(stream, "border-left-width: medium ");
break;
case CSS_BORDER_WIDTH_THICK:
fprintf(stream, "border-left-width: thick ");
break;
case CSS_BORDER_WIDTH_WIDTH:
fprintf(stream, "border-left-width: ");
dump_css_unit(stream, len1, unit1);
fprintf(stream, " ");
break;
default:
break;
}
 
/* bottom */
val = css_computed_bottom(style, &len1, &unit1);
switch (val) {
case CSS_BOTTOM_AUTO:
fprintf(stream, "bottom: auto ");
break;
case CSS_BOTTOM_SET:
fprintf(stream, "bottom: ");
dump_css_unit(stream, len1, unit1);
fprintf(stream, " ");
break;
default:
break;
}
 
/* caption-side */
val = css_computed_caption_side(style);
switch (val) {
case CSS_CAPTION_SIDE_TOP:
fprintf(stream, "caption_side: top ");
break;
case CSS_CAPTION_SIDE_BOTTOM:
fprintf(stream, "caption_side: bottom ");
break;
default:
break;
}
 
/* clear */
val = css_computed_clear(style);
switch (val) {
case CSS_CLEAR_NONE:
fprintf(stream, "clear: none ");
break;
case CSS_CLEAR_LEFT:
fprintf(stream, "clear: left ");
break;
case CSS_CLEAR_RIGHT:
fprintf(stream, "clear: right ");
break;
case CSS_CLEAR_BOTH:
fprintf(stream, "clear: both ");
break;
default:
break;
}
 
/* clip */
val = css_computed_clip(style, &rect);
switch (val) {
case CSS_CLIP_AUTO:
fprintf(stream, "clip: auto ");
break;
case CSS_CLIP_RECT:
fprintf(stream, "clip: rect( ");
 
if (rect.top_auto)
fprintf(stream, "auto");
else
dump_css_unit(stream, rect.top, rect.tunit);
fprintf(stream, ", ");
 
if (rect.right_auto)
fprintf(stream, "auto");
else
dump_css_unit(stream, rect.right, rect.runit);
fprintf(stream, ", ");
 
if (rect.bottom_auto)
fprintf(stream, "auto");
else
dump_css_unit(stream, rect.bottom, rect.bunit);
fprintf(stream, ", ");
 
if (rect.left_auto)
fprintf(stream, "auto");
else
dump_css_unit(stream, rect.left, rect.lunit);
fprintf(stream, ") ");
break;
default:
break;
}
 
/* color */
val = css_computed_color(style, &color);
if (val == CSS_COLOR_COLOR) {
fprintf(stream, "color: #%08x ", color);
}
 
/* content */
val = css_computed_content(style, &content);
switch (val) {
case CSS_CONTENT_NONE:
fprintf(stream, "content: none ");
break;
case CSS_CONTENT_NORMAL:
fprintf(stream, "content: normal ");
break;
case CSS_CONTENT_SET:
fprintf(stream, "content:");
 
while (content->type != CSS_COMPUTED_CONTENT_NONE) {
fprintf(stream, " ");
 
switch (content->type) {
case CSS_COMPUTED_CONTENT_STRING:
fprintf(stream, "\"%.*s\"",
(int) lwc_string_length(
content->data.string),
lwc_string_data(
content->data.string));
break;
case CSS_COMPUTED_CONTENT_URI:
fprintf(stream, "uri(\"%.*s\")",
(int) lwc_string_length(
content->data.uri),
lwc_string_data(
content->data.uri));
break;
case CSS_COMPUTED_CONTENT_COUNTER:
fprintf(stream, "counter(%.*s)",
(int) lwc_string_length(
content->data.counter.name),
lwc_string_data(
content->data.counter.name));
break;
case CSS_COMPUTED_CONTENT_COUNTERS:
fprintf(stream, "counters(%.*s, \"%.*s\")",
(int) lwc_string_length(
content->data.counters.name),
lwc_string_data(
content->data.counters.name),
(int) lwc_string_length(
content->data.counters.sep),
lwc_string_data(
content->data.counters.sep));
break;
case CSS_COMPUTED_CONTENT_ATTR:
fprintf(stream, "attr(%.*s)",
(int) lwc_string_length(
content->data.attr),
lwc_string_data(
content->data.attr));
break;
case CSS_COMPUTED_CONTENT_OPEN_QUOTE:
fprintf(stream, "open-quote");
break;
case CSS_COMPUTED_CONTENT_CLOSE_QUOTE:
fprintf(stream, "close-quote");
break;
case CSS_COMPUTED_CONTENT_NO_OPEN_QUOTE:
fprintf(stream, "no-open-quote");
break;
case CSS_COMPUTED_CONTENT_NO_CLOSE_QUOTE:
fprintf(stream, "no-close-quote");
break;
}
 
content++;
}
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* counter-increment */
val = css_computed_counter_increment(style, &counter);
if (counter == NULL) {
fprintf(stream, "counter-increment: none ");
} else {
fprintf(stream, "counter-increment:");
 
while (counter->name != NULL) {
fprintf(stream, " %.*s ",
(int) lwc_string_length(counter->name),
lwc_string_data(counter->name));
 
dump_css_fixed(stream, counter->value);
 
counter++;
}
 
fprintf(stream, " ");
}
 
/* counter-reset */
val = css_computed_counter_reset(style, &counter);
if (counter == NULL) {
fprintf(stream, "counter-reset: none ");
} else {
fprintf(stream, "counter-reset:");
 
while (counter->name != NULL) {
fprintf(stream, " %.*s ",
(int) lwc_string_length(counter->name),
lwc_string_data(counter->name));
 
dump_css_fixed(stream, counter->value);
 
counter++;
}
 
fprintf(stream, " ");
}
 
/* cursor */
val = css_computed_cursor(style, &string_list);
fprintf(stream, "cursor:");
 
if (string_list != NULL) {
while (*string_list != NULL) {
fprintf(stream, " url\"%.*s\")",
(int) lwc_string_length(*string_list),
lwc_string_data(*string_list));
 
string_list++;
}
}
switch (val) {
case CSS_CURSOR_AUTO:
fprintf(stream, " auto ");
break;
case CSS_CURSOR_CROSSHAIR:
fprintf(stream, " crosshair ");
break;
case CSS_CURSOR_DEFAULT:
fprintf(stream, " default ");
break;
case CSS_CURSOR_POINTER:
fprintf(stream, " pointer ");
break;
case CSS_CURSOR_MOVE:
fprintf(stream, " move ");
break;
case CSS_CURSOR_E_RESIZE:
fprintf(stream, " e-resize ");
break;
case CSS_CURSOR_NE_RESIZE:
fprintf(stream, " ne-resize ");
break;
case CSS_CURSOR_NW_RESIZE:
fprintf(stream, " nw-resize ");
break;
case CSS_CURSOR_N_RESIZE:
fprintf(stream, " n-resize ");
break;
case CSS_CURSOR_SE_RESIZE:
fprintf(stream, " se-resize ");
break;
case CSS_CURSOR_SW_RESIZE:
fprintf(stream, " sw-resize ");
break;
case CSS_CURSOR_S_RESIZE:
fprintf(stream, " s-resize ");
break;
case CSS_CURSOR_W_RESIZE:
fprintf(stream, " w-resize ");
break;
case CSS_CURSOR_TEXT:
fprintf(stream, " text ");
break;
case CSS_CURSOR_WAIT:
fprintf(stream, " wait ");
break;
case CSS_CURSOR_HELP:
fprintf(stream, " help ");
break;
case CSS_CURSOR_PROGRESS:
fprintf(stream, " progress ");
break;
default:
break;
}
 
/* direction */
val = css_computed_direction(style);
switch (val) {
case CSS_DIRECTION_LTR:
fprintf(stream, "direction: ltr ");
break;
case CSS_DIRECTION_RTL:
fprintf(stream, "direction: rtl ");
break;
default:
break;
}
 
/* display */
val = css_computed_display_static(style);
switch (val) {
case CSS_DISPLAY_INLINE:
fprintf(stream, "display: inline ");
break;
case CSS_DISPLAY_BLOCK:
fprintf(stream, "display: block ");
break;
case CSS_DISPLAY_LIST_ITEM:
fprintf(stream, "display: list-item ");
break;
case CSS_DISPLAY_RUN_IN:
fprintf(stream, "display: run-in ");
break;
case CSS_DISPLAY_INLINE_BLOCK:
fprintf(stream, "display: inline-block ");
break;
case CSS_DISPLAY_TABLE:
fprintf(stream, "display: table ");
break;
case CSS_DISPLAY_INLINE_TABLE:
fprintf(stream, "display: inline-table ");
break;
case CSS_DISPLAY_TABLE_ROW_GROUP:
fprintf(stream, "display: table-row-group ");
break;
case CSS_DISPLAY_TABLE_HEADER_GROUP:
fprintf(stream, "display: table-header-group ");
break;
case CSS_DISPLAY_TABLE_FOOTER_GROUP:
fprintf(stream, "display: table-footer-group ");
break;
case CSS_DISPLAY_TABLE_ROW:
fprintf(stream, "display: table-row ");
break;
case CSS_DISPLAY_TABLE_COLUMN_GROUP:
fprintf(stream, "display: table-column-group ");
break;
case CSS_DISPLAY_TABLE_COLUMN:
fprintf(stream, "display: table-column ");
break;
case CSS_DISPLAY_TABLE_CELL:
fprintf(stream, "display: table-cell ");
break;
case CSS_DISPLAY_TABLE_CAPTION:
fprintf(stream, "display: table-caption ");
break;
case CSS_DISPLAY_NONE:
fprintf(stream, "display: none ");
break;
default:
break;
}
 
/* empty-cells */
val = css_computed_empty_cells(style);
switch (val) {
case CSS_EMPTY_CELLS_SHOW:
fprintf(stream, "empty-cells: show ");
break;
case CSS_EMPTY_CELLS_HIDE:
fprintf(stream, "empty-cells: hide ");
break;
default:
break;
}
 
/* float */
val = css_computed_float(style);
switch (val) {
case CSS_FLOAT_LEFT:
fprintf(stream, "float: left ");
break;
case CSS_FLOAT_RIGHT:
fprintf(stream, "float: right ");
break;
case CSS_FLOAT_NONE:
fprintf(stream, "float: none ");
break;
default:
break;
}
 
/* font-family */
val = css_computed_font_family(style, &string_list);
if (val != CSS_FONT_FAMILY_INHERIT) {
fprintf(stream, "font-family:");
 
if (string_list != NULL) {
while (*string_list != NULL) {
fprintf(stream, " \"%.*s\"",
(int) lwc_string_length(*string_list),
lwc_string_data(*string_list));
 
string_list++;
}
}
switch (val) {
case CSS_FONT_FAMILY_SERIF:
fprintf(stream, " serif ");
break;
case CSS_FONT_FAMILY_SANS_SERIF:
fprintf(stream, " sans-serif ");
break;
case CSS_FONT_FAMILY_CURSIVE:
fprintf(stream, " cursive ");
break;
case CSS_FONT_FAMILY_FANTASY:
fprintf(stream, " fantasy ");
break;
case CSS_FONT_FAMILY_MONOSPACE:
fprintf(stream, " monospace ");
break;
}
}
 
/* font-size */
val = css_computed_font_size(style, &len1, &unit1);
switch (val) {
case CSS_FONT_SIZE_XX_SMALL:
fprintf(stream, "font-size: xx-small ");
break;
case CSS_FONT_SIZE_X_SMALL:
fprintf(stream, "font-size: x-small ");
break;
case CSS_FONT_SIZE_SMALL:
fprintf(stream, "font-size: small ");
break;
case CSS_FONT_SIZE_MEDIUM:
fprintf(stream, "font-size: medium ");
break;
case CSS_FONT_SIZE_LARGE:
fprintf(stream, "font-size: large ");
break;
case CSS_FONT_SIZE_X_LARGE:
fprintf(stream, "font-size: x-large ");
break;
case CSS_FONT_SIZE_XX_LARGE:
fprintf(stream, "font-size: xx-large ");
break;
case CSS_FONT_SIZE_LARGER:
fprintf(stream, "font-size: larger ");
break;
case CSS_FONT_SIZE_SMALLER:
fprintf(stream, "font-size: smaller ");
break;
case CSS_FONT_SIZE_DIMENSION:
fprintf(stream, "font-size: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* font-style */
val = css_computed_font_style(style);
switch (val) {
case CSS_FONT_STYLE_NORMAL:
fprintf(stream, "font-style: normal ");
break;
case CSS_FONT_STYLE_ITALIC:
fprintf(stream, "font-style: italic ");
break;
case CSS_FONT_STYLE_OBLIQUE:
fprintf(stream, "font-style: oblique ");
break;
default:
break;
}
 
/* font-variant */
val = css_computed_font_variant(style);
switch (val) {
case CSS_FONT_VARIANT_NORMAL:
fprintf(stream, "font-variant: normal ");
break;
case CSS_FONT_VARIANT_SMALL_CAPS:
fprintf(stream, "font-variant: small-caps ");
break;
default:
break;
}
 
/* font-weight */
val = css_computed_font_weight(style);
switch (val) {
case CSS_FONT_WEIGHT_NORMAL:
fprintf(stream, "font-weight: normal ");
break;
case CSS_FONT_WEIGHT_BOLD:
fprintf(stream, "font-weight: bold ");
break;
case CSS_FONT_WEIGHT_BOLDER:
fprintf(stream, "font-weight: bolder ");
break;
case CSS_FONT_WEIGHT_LIGHTER:
fprintf(stream, "font-weight: lighter ");
break;
case CSS_FONT_WEIGHT_100:
fprintf(stream, "font-weight: 100 ");
break;
case CSS_FONT_WEIGHT_200:
fprintf(stream, "font-weight: 200 ");
break;
case CSS_FONT_WEIGHT_300:
fprintf(stream, "font-weight: 300 ");
break;
case CSS_FONT_WEIGHT_400:
fprintf(stream, "font-weight: 400 ");
break;
case CSS_FONT_WEIGHT_500:
fprintf(stream, "font-weight: 500 ");
break;
case CSS_FONT_WEIGHT_600:
fprintf(stream, "font-weight: 600 ");
break;
case CSS_FONT_WEIGHT_700:
fprintf(stream, "font-weight: 700 ");
break;
case CSS_FONT_WEIGHT_800:
fprintf(stream, "font-weight: 800 ");
break;
case CSS_FONT_WEIGHT_900:
fprintf(stream, "font-weight: 900 ");
break;
default:
break;
}
 
/* height */
val = css_computed_height(style, &len1, &unit1);
switch (val) {
case CSS_HEIGHT_AUTO:
fprintf(stream, "height: auto ");
break;
case CSS_HEIGHT_SET:
fprintf(stream, "height: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* left */
val = css_computed_left(style, &len1, &unit1);
switch (val) {
case CSS_LEFT_AUTO:
fprintf(stream, "left: auto ");
break;
case CSS_LEFT_SET:
fprintf(stream, "left: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* letter-spacing */
val = css_computed_letter_spacing(style, &len1, &unit1);
switch (val) {
case CSS_LETTER_SPACING_NORMAL:
fprintf(stream, "letter-spacing: normal ");
break;
case CSS_LETTER_SPACING_SET:
fprintf(stream, "letter-spacing: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* line-height */
val = css_computed_line_height(style, &len1, &unit1);
switch (val) {
case CSS_LINE_HEIGHT_NORMAL:
fprintf(stream, "line-height: normal ");
break;
case CSS_LINE_HEIGHT_NUMBER:
fprintf(stream, "line-height: ");
 
dump_css_fixed(stream, len1);
 
fprintf(stream, " ");
break;
case CSS_LINE_HEIGHT_DIMENSION:
fprintf(stream, "line-height: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* list-style-image */
val = css_computed_list_style_image(style, &url);
if (url != NULL) {
fprintf(stream, "list-style-image: url('%.*s') ",
(int) lwc_string_length(url),
lwc_string_data(url));
} else if (val == CSS_LIST_STYLE_IMAGE_NONE) {
fprintf(stream, "list-style-image: none ");
}
 
/* list-style-position */
val = css_computed_list_style_position(style);
switch (val) {
case CSS_LIST_STYLE_POSITION_INSIDE:
fprintf(stream, "list-style-position: inside ");
break;
case CSS_LIST_STYLE_POSITION_OUTSIDE:
fprintf(stream, "list-style-position: outside ");
break;
default:
break;
}
 
/* list-style-type */
val = css_computed_list_style_type(style);
switch (val) {
case CSS_LIST_STYLE_TYPE_DISC:
fprintf(stream, "list-style-type: disc ");
break;
case CSS_LIST_STYLE_TYPE_CIRCLE:
fprintf(stream, "list-style-type: circle ");
break;
case CSS_LIST_STYLE_TYPE_SQUARE:
fprintf(stream, "list-style-type: square ");
break;
case CSS_LIST_STYLE_TYPE_DECIMAL:
fprintf(stream, "list-style-type: decimal ");
break;
case CSS_LIST_STYLE_TYPE_DECIMAL_LEADING_ZERO:
fprintf(stream, "list-style-type: decimal-leading-zero ");
break;
case CSS_LIST_STYLE_TYPE_LOWER_ROMAN:
fprintf(stream, "list-style-type: lower-roman ");
break;
case CSS_LIST_STYLE_TYPE_UPPER_ROMAN:
fprintf(stream, "list-style-type: upper-roman ");
break;
case CSS_LIST_STYLE_TYPE_LOWER_GREEK:
fprintf(stream, "list-style-type: lower-greek ");
break;
case CSS_LIST_STYLE_TYPE_LOWER_LATIN:
fprintf(stream, "list-style-type: lower-latin ");
break;
case CSS_LIST_STYLE_TYPE_UPPER_LATIN:
fprintf(stream, "list-style-type: upper-latin ");
break;
case CSS_LIST_STYLE_TYPE_ARMENIAN:
fprintf(stream, "list-style-type: armenian ");
break;
case CSS_LIST_STYLE_TYPE_GEORGIAN:
fprintf(stream, "list-style-type: georgian ");
break;
case CSS_LIST_STYLE_TYPE_LOWER_ALPHA:
fprintf(stream, "list-style-type: lower-alpha ");
break;
case CSS_LIST_STYLE_TYPE_UPPER_ALPHA:
fprintf(stream, "list-style-type: upper-alpha ");
break;
case CSS_LIST_STYLE_TYPE_NONE:
fprintf(stream, "list-style-type: none ");
break;
default:
break;
}
 
/* margin-top */
val = css_computed_margin_top(style, &len1, &unit1);
switch (val) {
case CSS_MARGIN_AUTO:
fprintf(stream, "margin-top: auto ");
break;
case CSS_MARGIN_SET:
fprintf(stream, "margin-top: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* margin-right */
val = css_computed_margin_right(style, &len1, &unit1);
switch (val) {
case CSS_MARGIN_AUTO:
fprintf(stream, "margin-right: auto ");
break;
case CSS_MARGIN_SET:
fprintf(stream, "margin-right: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* margin-bottom */
val = css_computed_margin_bottom(style, &len1, &unit1);
switch (val) {
case CSS_MARGIN_AUTO:
fprintf(stream, "margin-bottom: auto ");
break;
case CSS_MARGIN_SET:
fprintf(stream, "margin-bottom: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* margin-left */
val = css_computed_margin_left(style, &len1, &unit1);
switch (val) {
case CSS_MARGIN_AUTO:
fprintf(stream, "margin-left: auto ");
break;
case CSS_MARGIN_SET:
fprintf(stream, "margin-left: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* max-height */
val = css_computed_max_height(style, &len1, &unit1);
switch (val) {
case CSS_MAX_HEIGHT_NONE:
fprintf(stream, "max-height: none ");
break;
case CSS_MAX_HEIGHT_SET:
fprintf(stream, "max-height: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* max-width */
val = css_computed_max_width(style, &len1, &unit1);
switch (val) {
case CSS_MAX_WIDTH_NONE:
fprintf(stream, "max-width: none ");
break;
case CSS_MAX_WIDTH_SET:
fprintf(stream, "max-width: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* min-height */
val = css_computed_min_height(style, &len1, &unit1);
switch (val) {
case CSS_MIN_HEIGHT_SET:
fprintf(stream, "min-height: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* min-width */
val = css_computed_min_width(style, &len1, &unit1);
switch (val) {
case CSS_MIN_WIDTH_SET:
fprintf(stream, "min-width: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* opacity */
val = css_computed_opacity(style, &len1);
switch (val) {
case CSS_OPACITY_SET:
fprintf(stream, "opacity: ");
 
dump_css_fixed(stream, len1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* outline-color */
val = css_computed_outline_color(style, &color);
switch (val) {
case CSS_OUTLINE_COLOR_INVERT:
fprintf(stream, "outline-color: invert ");
break;
case CSS_OUTLINE_COLOR_COLOR:
fprintf(stream, "outline-color: #%08x ", color);
break;
default:
break;
}
 
/* outline-style */
val = css_computed_outline_style(style);
switch (val) {
case CSS_OUTLINE_STYLE_NONE:
fprintf(stream, "outline-style: none ");
break;
case CSS_OUTLINE_STYLE_DOTTED:
fprintf(stream, "outline-style: dotted ");
break;
case CSS_OUTLINE_STYLE_DASHED:
fprintf(stream, "outline-style: dashed ");
break;
case CSS_OUTLINE_STYLE_SOLID:
fprintf(stream, "outline-style: solid ");
break;
case CSS_OUTLINE_STYLE_DOUBLE:
fprintf(stream, "outline-style: double ");
break;
case CSS_OUTLINE_STYLE_GROOVE:
fprintf(stream, "outline-style: groove ");
break;
case CSS_OUTLINE_STYLE_RIDGE:
fprintf(stream, "outline-style: ridge ");
break;
case CSS_OUTLINE_STYLE_INSET:
fprintf(stream, "outline-style: inset ");
break;
case CSS_OUTLINE_STYLE_OUTSET:
fprintf(stream, "outline-style: outset ");
break;
default:
break;
}
 
/* outline-width */
val = css_computed_outline_width(style, &len1, &unit1);
switch (val) {
case CSS_OUTLINE_WIDTH_THIN:
fprintf(stream, "outline-width: thin ");
break;
case CSS_OUTLINE_WIDTH_MEDIUM:
fprintf(stream, "outline-width: medium ");
break;
case CSS_OUTLINE_WIDTH_THICK:
fprintf(stream, "outline-width: thick ");
break;
case CSS_OUTLINE_WIDTH_WIDTH:
fprintf(stream, "outline-width: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* overflow */
val = css_computed_overflow(style);
switch (val) {
case CSS_OVERFLOW_VISIBLE:
fprintf(stream, "overflow: visible ");
break;
case CSS_OVERFLOW_HIDDEN:
fprintf(stream, "overflow: hidden ");
break;
case CSS_OVERFLOW_SCROLL:
fprintf(stream, "overflow: scroll ");
break;
case CSS_OVERFLOW_AUTO:
fprintf(stream, "overflow: auto ");
break;
default:
break;
}
 
/* padding-top */
val = css_computed_padding_top(style, &len1, &unit1);
switch (val) {
case CSS_PADDING_SET:
fprintf(stream, "padding-top: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* padding-right */
val = css_computed_padding_right(style, &len1, &unit1);
switch (val) {
case CSS_PADDING_SET:
fprintf(stream, "padding-right: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* padding-bottom */
val = css_computed_padding_bottom(style, &len1, &unit1);
switch (val) {
case CSS_PADDING_SET:
fprintf(stream, "padding-bottom: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* padding-left */
val = css_computed_padding_left(style, &len1, &unit1);
switch (val) {
case CSS_PADDING_SET:
fprintf(stream, "padding-left: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* position */
val = css_computed_position(style);
switch (val) {
case CSS_POSITION_STATIC:
fprintf(stream, "position: static ");
break;
case CSS_POSITION_RELATIVE:
fprintf(stream, "position: relative ");
break;
case CSS_POSITION_ABSOLUTE:
fprintf(stream, "position: absolute ");
break;
case CSS_POSITION_FIXED:
fprintf(stream, "position: fixed ");
break;
default:
break;
}
 
/* quotes */
val = css_computed_quotes(style, &string_list);
if (val == CSS_QUOTES_STRING && string_list != NULL) {
fprintf(stream, "quotes:");
 
while (*string_list != NULL) {
fprintf(stream, " \"%.*s\"",
(int) lwc_string_length(*string_list),
lwc_string_data(*string_list));
 
string_list++;
}
 
fprintf(stream, " ");
} else {
switch (val) {
case CSS_QUOTES_NONE:
fprintf(stream, "quotes: none ");
break;
default:
break;
}
}
 
/* right */
val = css_computed_right(style, &len1, &unit1);
switch (val) {
case CSS_RIGHT_AUTO:
fprintf(stream, "right: auto ");
break;
case CSS_RIGHT_SET:
fprintf(stream, "right: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* table-layout */
val = css_computed_table_layout(style);
switch (val) {
case CSS_TABLE_LAYOUT_AUTO:
fprintf(stream, "table-layout: auto ");
break;
case CSS_TABLE_LAYOUT_FIXED:
fprintf(stream, "table-layout: fixed ");
break;
default:
break;
}
 
/* text-align */
val = css_computed_text_align(style);
switch (val) {
case CSS_TEXT_ALIGN_LEFT:
fprintf(stream, "text-align: left ");
break;
case CSS_TEXT_ALIGN_RIGHT:
fprintf(stream, "text-align: right ");
break;
case CSS_TEXT_ALIGN_CENTER:
fprintf(stream, "text-align: center ");
break;
case CSS_TEXT_ALIGN_JUSTIFY:
fprintf(stream, "text-align: justify ");
break;
case CSS_TEXT_ALIGN_DEFAULT:
fprintf(stream, "text-align: default ");
break;
case CSS_TEXT_ALIGN_LIBCSS_LEFT:
fprintf(stream, "text-align: -libcss-left ");
break;
case CSS_TEXT_ALIGN_LIBCSS_CENTER:
fprintf(stream, "text-align: -libcss-center ");
break;
case CSS_TEXT_ALIGN_LIBCSS_RIGHT:
fprintf(stream, "text-align: -libcss-right ");
break;
default:
break;
}
 
/* text-decoration */
val = css_computed_text_decoration(style);
if (val == CSS_TEXT_DECORATION_NONE) {
fprintf(stream, "text-decoration: none ");
} else {
fprintf(stream, "text-decoration:");
 
if (val & CSS_TEXT_DECORATION_BLINK) {
fprintf(stream, " blink");
}
if (val & CSS_TEXT_DECORATION_LINE_THROUGH) {
fprintf(stream, " line-through");
}
if (val & CSS_TEXT_DECORATION_OVERLINE) {
fprintf(stream, " overline");
}
if (val & CSS_TEXT_DECORATION_UNDERLINE) {
fprintf(stream, " underline");
}
 
fprintf(stream, " ");
}
 
/* text-indent */
val = css_computed_text_indent(style, &len1, &unit1);
switch (val) {
case CSS_TEXT_INDENT_SET:
fprintf(stream, "text-indent: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* text-transform */
val = css_computed_text_transform(style);
switch (val) {
case CSS_TEXT_TRANSFORM_CAPITALIZE:
fprintf(stream, "text-transform: capitalize ");
break;
case CSS_TEXT_TRANSFORM_UPPERCASE:
fprintf(stream, "text-transform: uppercase ");
break;
case CSS_TEXT_TRANSFORM_LOWERCASE:
fprintf(stream, "text-transform: lowercase ");
break;
case CSS_TEXT_TRANSFORM_NONE:
fprintf(stream, "text-transform: none ");
break;
default:
break;
}
 
/* top */
val = css_computed_top(style, &len1, &unit1);
switch (val) {
case CSS_TOP_AUTO:
fprintf(stream, "top: auto ");
break;
case CSS_TOP_SET:
fprintf(stream, "top: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* unicode-bidi */
val = css_computed_unicode_bidi(style);
switch (val) {
case CSS_UNICODE_BIDI_NORMAL:
fprintf(stream, "unicode-bidi: normal ");
break;
case CSS_UNICODE_BIDI_EMBED:
fprintf(stream, "unicode-bidi: embed ");
break;
case CSS_UNICODE_BIDI_BIDI_OVERRIDE:
fprintf(stream, "unicode-bidi: bidi-override ");
break;
default:
break;
}
 
/* vertical-align */
val = css_computed_vertical_align(style, &len1, &unit1);
switch (val) {
case CSS_VERTICAL_ALIGN_BASELINE:
fprintf(stream, "vertical-align: baseline ");
break;
case CSS_VERTICAL_ALIGN_SUB:
fprintf(stream, "vertical-align: sub ");
break;
case CSS_VERTICAL_ALIGN_SUPER:
fprintf(stream, "vertical-align: super ");
break;
case CSS_VERTICAL_ALIGN_TOP:
fprintf(stream, "vertical-align: top ");
break;
case CSS_VERTICAL_ALIGN_TEXT_TOP:
fprintf(stream, "vertical-align: text-top ");
break;
case CSS_VERTICAL_ALIGN_MIDDLE:
fprintf(stream, "vertical-align: middle ");
break;
case CSS_VERTICAL_ALIGN_BOTTOM:
fprintf(stream, "vertical-align: bottom ");
break;
case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
fprintf(stream, "vertical-align: text-bottom ");
break;
case CSS_VERTICAL_ALIGN_SET:
fprintf(stream, "vertical-align: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* visibility */
val = css_computed_visibility(style);
switch (val) {
case CSS_VISIBILITY_VISIBLE:
fprintf(stream, "visibility: visible ");
break;
case CSS_VISIBILITY_HIDDEN:
fprintf(stream, "visibility: hidden ");
break;
case CSS_VISIBILITY_COLLAPSE:
fprintf(stream, "visibility: collapse ");
break;
default:
break;
}
 
/* white-space */
val = css_computed_white_space(style);
switch (val) {
case CSS_WHITE_SPACE_NORMAL:
fprintf(stream, "white-space: normal ");
break;
case CSS_WHITE_SPACE_PRE:
fprintf(stream, "white-space: pre ");
break;
case CSS_WHITE_SPACE_NOWRAP:
fprintf(stream, "white-space: nowrap ");
break;
case CSS_WHITE_SPACE_PRE_WRAP:
fprintf(stream, "white-space: pre-wrap ");
break;
case CSS_WHITE_SPACE_PRE_LINE:
fprintf(stream, "white-space: pre-line ");
break;
default:
break;
}
 
/* width */
val = css_computed_width(style, &len1, &unit1);
switch (val) {
case CSS_WIDTH_AUTO:
fprintf(stream, "width: auto ");
break;
case CSS_WIDTH_SET:
fprintf(stream, "width: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* word-spacing */
val = css_computed_word_spacing(style, &len1, &unit1);
switch (val) {
case CSS_WORD_SPACING_NORMAL:
fprintf(stream, "word-spacing: normal ");
break;
case CSS_WORD_SPACING_SET:
fprintf(stream, "word-spacing: ");
 
dump_css_unit(stream, len1, unit1);
 
fprintf(stream, " ");
break;
default:
break;
}
 
/* z-index */
val = css_computed_z_index(style, &zindex);
switch (val) {
case CSS_Z_INDEX_AUTO:
fprintf(stream, "z-index: auto ");
break;
case CSS_Z_INDEX_SET:
fprintf(stream, "z-index: %d ", zindex);
break;
default:
break;
}
 
fprintf(stream, "}");
}
 
/******************************************************************************
* Helper functions for nscss_dump_computed_style *
******************************************************************************/
 
/**
* Dump a fixed point value to the stream in a textual form.
*
* \param stream Stream to write to
* \param f Value to write
*/
void dump_css_fixed(FILE *stream, css_fixed f)
{
#define NSCSS_ABS(x) (uint32_t)((x) < 0 ? -(x) : (x))
uint32_t uintpart = FIXTOINT(NSCSS_ABS(f));
/* + 500 to ensure round to nearest (division will truncate) */
uint32_t fracpart = ((NSCSS_ABS(f) & 0x3ff) * 1000 + 500) / (1 << 10);
#undef NSCSS_ABS
 
fprintf(stream, "%s%d.%03d", f < 0 ? "-" : "", uintpart, fracpart);
}
 
/**
* Dump a numeric value to the stream in a textual form.
*
* \param stream Stream to write to
* \param val Value to write
*/
void dump_css_number(FILE *stream, css_fixed val)
{
if (INTTOFIX(FIXTOINT(val)) == val)
fprintf(stream, "%d", FIXTOINT(val));
else
dump_css_fixed(stream, val);
}
 
/**
* Dump a dimension to the stream in a textual form.
*
* \param stream Stream to write to
* \param val Value to write
* \param unit Unit to write
*/
void dump_css_unit(FILE *stream, css_fixed val, css_unit unit)
{
dump_css_number(stream, val);
 
switch (unit) {
case CSS_UNIT_PX:
fprintf(stream, "px");
break;
case CSS_UNIT_EX:
fprintf(stream, "ex");
break;
case CSS_UNIT_EM:
fprintf(stream, "em");
break;
case CSS_UNIT_IN:
fprintf(stream, "in");
break;
case CSS_UNIT_CM:
fprintf(stream, "cm");
break;
case CSS_UNIT_MM:
fprintf(stream, "mm");
break;
case CSS_UNIT_PT:
fprintf(stream, "pt");
break;
case CSS_UNIT_PC:
fprintf(stream, "pc");
break;
case CSS_UNIT_PCT:
fprintf(stream, "%%");
break;
case CSS_UNIT_DEG:
fprintf(stream, "deg");
break;
case CSS_UNIT_GRAD:
fprintf(stream, "grad");
break;
case CSS_UNIT_RAD:
fprintf(stream, "rad");
break;
case CSS_UNIT_MS:
fprintf(stream, "ms");
break;
case CSS_UNIT_S:
fprintf(stream, "s");
break;
case CSS_UNIT_HZ:
fprintf(stream, "Hz");
break;
case CSS_UNIT_KHZ:
fprintf(stream, "kHz");
break;
}
}
 
/programs/network/netsurf/netsurf/css/dump.h
0,0 → 1,26
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_CSS_DUMP_H_
#define NETSURF_CSS_DUMP_H_
 
#include "css/css.h"
 
void nscss_dump_computed_style(FILE *stream, const css_computed_style *style);
 
#endif
/programs/network/netsurf/netsurf/css/internal.c
0,0 → 1,73
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <string.h>
 
#include "css/internal.h"
 
#include "utils/nsurl.h"
 
/**
* URL resolution callback for libcss
*
* \param pw Resolution context
* \param base Base URI
* \param rel Relative URL
* \param abs Pointer to location to receive resolved URL
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion,
* CSS_INVALID if resolution failed.
*/
css_error nscss_resolve_url(void *pw, const char *base,
lwc_string *rel, lwc_string **abs)
{
lwc_error lerror;
nserror error;
nsurl *nsbase;
nsurl *nsabs;
 
/* Create nsurl from base */
/* TODO: avoid this */
error = nsurl_create(base, &nsbase);
if (error != NSERROR_OK) {
return error == NSERROR_NOMEM ? CSS_NOMEM : CSS_INVALID;
}
 
/* Resolve URI */
error = nsurl_join(nsbase, lwc_string_data(rel), &nsabs);
if (error != NSERROR_OK) {
nsurl_unref(nsbase);
return error == NSERROR_NOMEM ? CSS_NOMEM : CSS_INVALID;
}
 
nsurl_unref(nsbase);
 
/* Intern it */
lerror = lwc_intern_string(nsurl_access(nsabs),
nsurl_length(nsabs), abs);
if (lerror != lwc_error_ok) {
*abs = NULL;
nsurl_unref(nsabs);
return lerror == lwc_error_oom ? CSS_NOMEM : CSS_INVALID;
}
 
nsurl_unref(nsabs);
 
return CSS_OK;
}
 
/programs/network/netsurf/netsurf/css/internal.h
0,0 → 1,27
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_CSS_INTERNAL_H_
#define NETSURF_CSS_INTERNAL_H_
 
#include "css/css.h"
 
css_error nscss_resolve_url(void *pw, const char *base,
lwc_string *rel, lwc_string **abs);
 
#endif
/programs/network/netsurf/netsurf/css/make.css
0,0 → 1,21
CFLAGS += -O2
NETSURF_FB_FRONTEND := sdl
NETSURF_FB_FONTLIB := internal
 
NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
 
# Default resource install path
NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
 
# Default framebuffer search path
NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
 
# freetype compiled in font serch path
NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
OBJS := css.o dump.o internal.o select.o utils.o
 
 
OUTFILE = TEST.o
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include
include $(MENUETDEV)/makefiles/Makefile_for_o_lib
/programs/network/netsurf/netsurf/css/select.c
0,0 → 1,3497
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
 
#include "content/content_protected.h"
#include "content/urldb.h"
#include "css/internal.h"
#include "css/select.h"
#include "css/utils.h"
#include "desktop/gui.h"
#include "desktop/options.h"
#include "utils/corestrings.h"
#include "utils/log.h"
#include "utils/url.h"
#include "utils/utils.h"
 
static css_error node_name(void *pw, void *node, css_qname *qname);
static css_error node_classes(void *pw, void *node,
lwc_string ***classes, uint32_t *n_classes);
static css_error node_id(void *pw, void *node, lwc_string **id);
static css_error named_ancestor_node(void *pw, void *node,
const css_qname *qname, void **ancestor);
static css_error named_parent_node(void *pw, void *node,
const css_qname *qname, void **parent);
static css_error named_sibling_node(void *pw, void *node,
const css_qname *qname, void **sibling);
static css_error named_generic_sibling_node(void *pw, void *node,
const css_qname *qname, void **sibling);
static css_error parent_node(void *pw, void *node, void **parent);
static css_error sibling_node(void *pw, void *node, void **sibling);
static css_error node_has_name(void *pw, void *node,
const css_qname *qname, bool *match);
static css_error node_has_class(void *pw, void *node,
lwc_string *name, bool *match);
static css_error node_has_id(void *pw, void *node,
lwc_string *name, bool *match);
static css_error node_has_attribute(void *pw, void *node,
const css_qname *qname, bool *match);
static css_error node_has_attribute_equal(void *pw, void *node,
const css_qname *qname, lwc_string *value,
bool *match);
static css_error node_has_attribute_dashmatch(void *pw, void *node,
const css_qname *qname, lwc_string *value,
bool *match);
static css_error node_has_attribute_includes(void *pw, void *node,
const css_qname *qname, lwc_string *value,
bool *match);
static css_error node_has_attribute_prefix(void *pw, void *node,
const css_qname *qname, lwc_string *value,
bool *match);
static css_error node_has_attribute_suffix(void *pw, void *node,
const css_qname *qname, lwc_string *value,
bool *match);
static css_error node_has_attribute_substring(void *pw, void *node,
const css_qname *qname, lwc_string *value,
bool *match);
static css_error node_is_root(void *pw, void *node, bool *match);
static css_error node_count_siblings(void *pw, void *node,
bool same_name, bool after, int32_t *count);
static css_error node_is_empty(void *pw, void *node, bool *match);
static css_error node_is_link(void *pw, void *node, bool *match);
static css_error node_is_visited(void *pw, void *node, bool *match);
static css_error node_is_hover(void *pw, void *node, bool *match);
static css_error node_is_active(void *pw, void *node, bool *match);
static css_error node_is_focus(void *pw, void *node, bool *match);
static css_error node_is_enabled(void *pw, void *node, bool *match);
static css_error node_is_disabled(void *pw, void *node, bool *match);
static css_error node_is_checked(void *pw, void *node, bool *match);
static css_error node_is_target(void *pw, void *node, bool *match);
static css_error node_is_lang(void *pw, void *node,
lwc_string *lang, bool *match);
static css_error node_presentational_hint(void *pw, void *node,
uint32_t property, css_hint *hint);
static css_error ua_default_for_property(void *pw, uint32_t property,
css_hint *hint);
 
static int cmp_colour_name(const void *a, const void *b);
static bool parse_named_colour(const char *data, css_color *result);
static bool parse_dimension(const char *data, bool strict,
css_fixed *length, css_unit *unit);
static bool parse_number(const char *data, bool non_negative, bool real,
css_fixed *value, size_t *consumed);
static bool parse_font_size(const char *size, uint8_t *val,
css_fixed *len, css_unit *unit);
 
static css_computed_style *nscss_get_initial_style(nscss_select_ctx *ctx,
css_allocator_fn, void *pw);
 
static bool isWhitespace(char c);
static bool isHex(char c);
static uint8_t charToHex(char c);
 
/**
* Selection callback table for libcss
*/
static css_select_handler selection_handler = {
CSS_SELECT_HANDLER_VERSION_1,
 
node_name,
node_classes,
node_id,
named_ancestor_node,
named_parent_node,
named_sibling_node,
named_generic_sibling_node,
parent_node,
sibling_node,
node_has_name,
node_has_class,
node_has_id,
node_has_attribute,
node_has_attribute_equal,
node_has_attribute_dashmatch,
node_has_attribute_includes,
node_has_attribute_prefix,
node_has_attribute_suffix,
node_has_attribute_substring,
node_is_root,
node_count_siblings,
node_is_empty,
node_is_link,
node_is_visited,
node_is_hover,
node_is_active,
node_is_focus,
node_is_enabled,
node_is_disabled,
node_is_checked,
node_is_target,
node_is_lang,
node_presentational_hint,
ua_default_for_property,
nscss_compute_font_size
};
 
/**
* Create an inline style
*
* \param data Source data
* \param len Length of data in bytes
* \param charset Charset of data, or NULL if unknown
* \param url URL of document containing data
* \param allow_quirks True to permit CSS parsing quirks
* \param alloc Memory allocation function
* \param pw Private word for allocator
* \return Pointer to stylesheet, or NULL on failure.
*/
css_stylesheet *nscss_create_inline_style(const uint8_t *data, size_t len,
const char *charset, const char *url, bool allow_quirks,
css_allocator_fn alloc, void *pw)
{
css_stylesheet_params params;
css_stylesheet *sheet;
css_error error;
 
params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1;
params.level = CSS_LEVEL_DEFAULT;
params.charset = charset;
params.url = url;
params.title = NULL;
params.allow_quirks = allow_quirks;
params.inline_style = true;
params.resolve = nscss_resolve_url;
params.resolve_pw = NULL;
params.import = NULL;
params.import_pw = NULL;
params.color = gui_system_colour;
params.color_pw = NULL;
params.font = NULL;
params.font_pw = NULL;
 
error = css_stylesheet_create(&params, alloc, pw, &sheet);
if (error != CSS_OK) {
LOG(("Failed creating sheet: %d", error));
return NULL;
}
 
error = css_stylesheet_append_data(sheet, data, len);
if (error != CSS_OK && error != CSS_NEEDDATA) {
LOG(("failed appending data: %d", error));
css_stylesheet_destroy(sheet);
return NULL;
}
 
error = css_stylesheet_data_done(sheet);
if (error != CSS_OK) {
LOG(("failed completing parse: %d", error));
css_stylesheet_destroy(sheet);
return NULL;
}
 
return sheet;
}
 
/**
* Get a style selection results (partial computed styles) for an element
*
* \param ctx CSS selection context
* \param n Element to select for
* \param media Permitted media types
* \param inline_style Inline style associated with element, or NULL
* \param alloc Memory allocation function
* \param pw Private word for allocator
* \return Pointer to selection results (containing partial computed styles),
* or NULL on failure
*/
css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n,
uint64_t media, const css_stylesheet *inline_style,
css_allocator_fn alloc, void *pw)
{
css_select_results *styles;
css_error error;
 
error = css_select_style(ctx->ctx, n, media, inline_style,
&selection_handler, ctx, &styles);
if (error != CSS_OK) {
return NULL;
}
 
return styles;
}
 
/**
* Get an initial style
*
* \param ctx CSS selection context
* \param alloc Memory allocation function
* \param pw Private word for allocator
* \return Pointer to partial computed style, or NULL on failure
*/
css_computed_style *nscss_get_initial_style(nscss_select_ctx *ctx,
css_allocator_fn alloc, void *pw)
{
css_computed_style *style;
css_error error;
 
error = css_computed_style_create(alloc, pw, &style);
if (error != CSS_OK)
return NULL;
 
error = css_computed_style_initialise(style, &selection_handler, ctx);
if (error != CSS_OK) {
css_computed_style_destroy(style);
return NULL;
}
 
return style;
}
 
/**
* Get a blank style
*
* \param ctx CSS selection context
* \param parent Parent style to cascade inherited properties from
* \param alloc Memory allocation function
* \param pw Private word for allocator
* \return Pointer to blank style, or NULL on failure
*/
css_computed_style *nscss_get_blank_style(nscss_select_ctx *ctx,
const css_computed_style *parent,
css_allocator_fn alloc, void *pw)
{
css_computed_style *partial;
css_error error;
 
partial = nscss_get_initial_style(ctx, alloc, pw);
if (partial == NULL)
return NULL;
 
error = css_computed_style_compose(parent, partial,
nscss_compute_font_size, NULL, partial);
if (error != CSS_OK) {
css_computed_style_destroy(partial);
return NULL;
}
 
return partial;
}
 
/**
* Font size computation callback for libcss
*
* \param pw Computation context
* \param parent Parent font size (absolute)
* \param size Font size to compute
* \return CSS_OK on success
*
* \post \a size will be an absolute font size
*/
css_error nscss_compute_font_size(void *pw, const css_hint *parent,
css_hint *size)
{
/**
* Table of font-size keyword scale factors
*
* These are multiplied by the configured default font size
* to produce an absolute size for the relevant keyword
*/
static const css_fixed factors[] = {
FLTTOFIX(0.5625), /* xx-small */
FLTTOFIX(0.6250), /* x-small */
FLTTOFIX(0.8125), /* small */
FLTTOFIX(1.0000), /* medium */
FLTTOFIX(1.1250), /* large */
FLTTOFIX(1.5000), /* x-large */
FLTTOFIX(2.0000) /* xx-large */
};
css_hint_length parent_size;
 
/* Grab parent size, defaulting to medium if none */
if (parent == NULL) {
parent_size.value = FDIV(FMUL(factors[CSS_FONT_SIZE_MEDIUM - 1],
INTTOFIX(nsoption_int(font_size))),
INTTOFIX(10));
parent_size.unit = CSS_UNIT_PT;
} else {
assert(parent->status == CSS_FONT_SIZE_DIMENSION);
assert(parent->data.length.unit != CSS_UNIT_EM);
assert(parent->data.length.unit != CSS_UNIT_EX);
assert(parent->data.length.unit != CSS_UNIT_PCT);
 
parent_size = parent->data.length;
}
 
assert(size->status != CSS_FONT_SIZE_INHERIT);
 
if (size->status < CSS_FONT_SIZE_LARGER) {
/* Keyword -- simple */
size->data.length.value = FDIV(FMUL(factors[size->status - 1],
INTTOFIX(nsoption_int(font_size))),
F_10);
size->data.length.unit = CSS_UNIT_PT;
} else if (size->status == CSS_FONT_SIZE_LARGER) {
/** \todo Step within table, if appropriate */
size->data.length.value =
FMUL(parent_size.value, FLTTOFIX(1.2));
size->data.length.unit = parent_size.unit;
} else if (size->status == CSS_FONT_SIZE_SMALLER) {
/** \todo Step within table, if appropriate */
size->data.length.value =
FDIV(parent_size.value, FLTTOFIX(1.2));
size->data.length.unit = parent_size.unit;
} else if (size->data.length.unit == CSS_UNIT_EM ||
size->data.length.unit == CSS_UNIT_EX) {
size->data.length.value =
FMUL(size->data.length.value, parent_size.value);
 
if (size->data.length.unit == CSS_UNIT_EX) {
/* 1ex = 0.6em in NetSurf */
size->data.length.value = FMUL(size->data.length.value,
FLTTOFIX(0.6));
}
 
size->data.length.unit = parent_size.unit;
} else if (size->data.length.unit == CSS_UNIT_PCT) {
size->data.length.value = FDIV(FMUL(size->data.length.value,
parent_size.value), INTTOFIX(100));
size->data.length.unit = parent_size.unit;
}
 
size->status = CSS_FONT_SIZE_DIMENSION;
 
return CSS_OK;
}
 
/**
* Parser for colours specified in attribute values.
*
* \param data Data to parse (NUL-terminated)
* \param result Pointer to location to receive resulting css_color
* \return true on success, false on invalid input
*/
bool nscss_parse_colour(const char *data, css_color *result)
{
size_t len = strlen(data);
uint8_t r, g, b;
 
/* 2 */
if (len == 0)
return false;
 
/* 3 */
if (len == SLEN("transparent") && strcasecmp(data, "transparent") == 0)
return false;
 
/* 4 */
if (parse_named_colour(data, result))
return true;
 
/** \todo Implement HTML5's utterly insane legacy colour parsing */
 
if (data[0] == '#') {
data++;
len--;
}
 
if (len == 3 && isHex(data[0]) && isHex(data[1]) && isHex(data[2])) {
r = charToHex(data[0]);
g = charToHex(data[1]);
b = charToHex(data[2]);
 
r |= (r << 4);
g |= (g << 4);
b |= (b << 4);
 
*result = (0xff << 24) | (r << 16) | (g << 8) | b;
 
return true;
} else if (len == 6 && isHex(data[0]) && isHex(data[1]) &&
isHex(data[2]) && isHex(data[3]) && isHex(data[4]) &&
isHex(data[5])) {
r = (charToHex(data[0]) << 4) | charToHex(data[1]);
g = (charToHex(data[2]) << 4) | charToHex(data[3]);
b = (charToHex(data[4]) << 4) | charToHex(data[5]);
 
*result = (0xff << 24) | (r << 16) | (g << 8) | b;
 
return true;
}
 
return false;
}
 
/******************************************************************************
* Style selection callbacks *
******************************************************************************/
 
/**
* Callback to retrieve a node's name.
*
* \param pw HTML document
* \param node DOM node
* \param qname Pointer to location to receive node name
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion.
*/
css_error node_name(void *pw, void *node, css_qname *qname)
{
dom_node *n = node;
dom_string *name;
dom_exception err;
 
err = dom_node_get_node_name(n, &name);
if (err != DOM_NO_ERR)
return CSS_NOMEM;
 
qname->ns = NULL;
 
err = dom_string_intern(name, &qname->name);
if (err != DOM_NO_ERR) {
dom_string_unref(name);
return CSS_NOMEM;
}
 
dom_string_unref(name);
 
return CSS_OK;
}
 
/**
* Callback to retrieve a node's classes.
*
* \param pw HTML document
* \param node DOM node
* \param classes Pointer to location to receive class name array
* \param n_classes Pointer to location to receive length of class name array
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion.
*
* \note The returned array will be destroyed by libcss. Therefore, it must
* be allocated using the same allocator as used by libcss during style
* selection.
*/
css_error node_classes(void *pw, void *node,
lwc_string ***classes, uint32_t *n_classes)
{
dom_node *n = node;
dom_exception err;
 
*classes = NULL;
*n_classes = 0;
 
err = dom_element_get_classes(n, classes, n_classes);
if (err != DOM_NO_ERR)
return CSS_NOMEM;
 
return CSS_OK;
}
 
/**
* Callback to retrieve a node's ID.
*
* \param pw HTML document
* \param node DOM node
* \param id Pointer to location to receive id value
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion.
*/
css_error node_id(void *pw, void *node, lwc_string **id)
{
dom_node *n = node;
dom_string *attr;
dom_exception err;
 
*id = NULL;
 
/** \todo Assumes an HTML DOM */
err = dom_html_element_get_id(n, &attr);
if (err != DOM_NO_ERR)
return CSS_NOMEM;
 
if (attr != NULL) {
err = dom_string_intern(attr, id);
if (err != DOM_NO_ERR) {
dom_string_unref(attr);
return CSS_NOMEM;
}
dom_string_unref(attr);
}
 
return CSS_OK;
}
 
/**
* Callback to find a named ancestor node.
*
* \param pw HTML document
* \param node DOM node
* \param qname Node name to search for
* \param ancestor Pointer to location to receive ancestor
* \return CSS_OK.
*
* \post \a ancestor will contain the result, or NULL if there is no match
*/
css_error named_ancestor_node(void *pw, void *node,
const css_qname *qname, void **ancestor)
{
dom_element_named_ancestor_node(node, qname->name,
(struct dom_element **)ancestor);
 
return CSS_OK;
}
 
/**
* Callback to find a named parent node
*
* \param pw HTML document
* \param node DOM node
* \param qname Node name to search for
* \param parent Pointer to location to receive parent
* \return CSS_OK.
*
* \post \a parent will contain the result, or NULL if there is no match
*/
css_error named_parent_node(void *pw, void *node,
const css_qname *qname, void **parent)
{
dom_element_named_parent_node(node, qname->name,
(struct dom_element **)parent);
 
return CSS_OK;
}
 
/**
* Callback to find a named sibling node.
*
* \param pw HTML document
* \param node DOM node
* \param qname Node name to search for
* \param sibling Pointer to location to receive sibling
* \return CSS_OK.
*
* \post \a sibling will contain the result, or NULL if there is no match
*/
css_error named_sibling_node(void *pw, void *node,
const css_qname *qname, void **sibling)
{
dom_node *n = node;
dom_node *prev;
dom_exception err;
 
*sibling = NULL;
 
/* Find sibling element */
err = dom_node_get_previous_sibling(n, &n);
if (err != DOM_NO_ERR)
return CSS_OK;
 
while (n != NULL) {
dom_node_type type;
 
err = dom_node_get_node_type(n, &type);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return CSS_OK;
}
 
if (type == DOM_ELEMENT_NODE)
break;
 
err = dom_node_get_previous_sibling(n, &prev);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return CSS_OK;
}
 
dom_node_unref(n);
n = prev;
}
 
if (n != NULL) {
dom_string *name;
 
err = dom_node_get_node_name(n, &name);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return CSS_OK;
}
 
dom_node_unref(n);
 
if (dom_string_caseless_lwc_isequal(name, qname->name)) {
*sibling = n;
}
 
dom_string_unref(name);
}
 
return CSS_OK;
}
 
/**
* Callback to find a named generic sibling node.
*
* \param pw HTML document
* \param node DOM node
* \param qname Node name to search for
* \param sibling Pointer to location to receive ancestor
* \return CSS_OK.
*
* \post \a sibling will contain the result, or NULL if there is no match
*/
css_error named_generic_sibling_node(void *pw, void *node,
const css_qname *qname, void **sibling)
{
dom_node *n = node;
dom_node *prev;
dom_exception err;
 
*sibling = NULL;
 
err = dom_node_get_previous_sibling(n, &n);
if (err != DOM_NO_ERR)
return CSS_OK;
 
while (n != NULL) {
dom_node_type type;
dom_string *name;
 
err = dom_node_get_node_type(n, &type);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return CSS_OK;
}
 
if (type == DOM_ELEMENT_NODE) {
err = dom_node_get_node_name(n, &name);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return CSS_OK;
}
 
if (dom_string_caseless_lwc_isequal(name,
qname->name)) {
dom_string_unref(name);
dom_node_unref(n);
*sibling = n;
break;
}
dom_string_unref(name);
}
 
err = dom_node_get_previous_sibling(n, &prev);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return CSS_OK;
}
 
dom_node_unref(n);
n = prev;
}
 
return CSS_OK;
}
 
/**
* Callback to retrieve the parent of a node.
*
* \param pw HTML document
* \param node DOM node
* \param parent Pointer to location to receive parent
* \return CSS_OK.
*
* \post \a parent will contain the result, or NULL if there is no match
*/
css_error parent_node(void *pw, void *node, void **parent)
{
dom_element_parent_node(node, (struct dom_element **)parent);
 
return CSS_OK;
}
 
/**
* Callback to retrieve the preceding sibling of a node.
*
* \param pw HTML document
* \param node DOM node
* \param sibling Pointer to location to receive sibling
* \return CSS_OK.
*
* \post \a sibling will contain the result, or NULL if there is no match
*/
css_error sibling_node(void *pw, void *node, void **sibling)
{
dom_node *n = node;
dom_node *prev;
dom_exception err;
 
*sibling = NULL;
 
/* Find sibling element */
err = dom_node_get_previous_sibling(n, &n);
if (err != DOM_NO_ERR)
return CSS_OK;
 
while (n != NULL) {
dom_node_type type;
 
err = dom_node_get_node_type(n, &type);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return CSS_OK;
}
 
if (type == DOM_ELEMENT_NODE)
break;
 
err = dom_node_get_previous_sibling(n, &prev);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return CSS_OK;
}
 
dom_node_unref(n);
n = prev;
}
 
if (n != NULL) {
/** \todo Sort out reference counting */
dom_node_unref(n);
 
*sibling = n;
}
 
return CSS_OK;
}
 
/**
* Callback to determine if a node has the given name.
*
* \param pw HTML document
* \param node DOM node
* \param qname Name to match
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_has_name(void *pw, void *node,
const css_qname *qname, bool *match)
{
nscss_select_ctx *ctx = pw;
dom_node *n = node;
 
if (lwc_string_isequal(qname->name, ctx->universal, match) == lwc_error_ok && *match == false) {
dom_string *name;
dom_exception err;
 
err = dom_node_get_node_name(n, &name);
if (err != DOM_NO_ERR)
return CSS_OK;
 
/* Element names are case insensitive in HTML */
*match = dom_string_caseless_lwc_isequal(name, qname->name);
 
dom_string_unref(name);
}
 
return CSS_OK;
}
 
/**
* Callback to determine if a node has the given class.
*
* \param pw HTML document
* \param node DOM node
* \param name Name to match
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_has_class(void *pw, void *node,
lwc_string *name, bool *match)
{
dom_node *n = node;
dom_exception err;
 
/** \todo: Ensure that libdom performs case-insensitive
* matching in quirks mode */
err = dom_element_has_class(n, name, match);
 
assert(err == DOM_NO_ERR);
 
return CSS_OK;
}
 
/**
* Callback to determine if a node has the given id.
*
* \param pw HTML document
* \param node DOM node
* \param name Name to match
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_has_id(void *pw, void *node,
lwc_string *name, bool *match)
{
dom_node *n = node;
dom_string *attr;
dom_exception err;
 
*match = false;
 
/** \todo Assumes an HTML DOM */
err = dom_html_element_get_id(n, &attr);
if (err != DOM_NO_ERR)
return CSS_OK;
 
if (attr != NULL) {
*match = dom_string_lwc_isequal(attr, name);
 
dom_string_unref(attr);
}
 
return CSS_OK;
}
 
/**
* Callback to determine if a node has an attribute with the given name.
*
* \param pw HTML document
* \param node DOM node
* \param qname Name to match
* \param match Pointer to location to receive result
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_has_attribute(void *pw, void *node,
const css_qname *qname, bool *match)
{
dom_node *n = node;
dom_string *name;
dom_exception err;
 
err = dom_string_create_interned(
(const uint8_t *) lwc_string_data(qname->name),
lwc_string_length(qname->name), &name);
if (err != DOM_NO_ERR)
return CSS_NOMEM;
 
err = dom_element_has_attribute(n, name, match);
if (err != DOM_NO_ERR) {
dom_string_unref(name);
return CSS_OK;
}
 
dom_string_unref(name);
 
return CSS_OK;
}
 
/**
* Callback to determine if a node has an attribute with given name and value.
*
* \param pw HTML document
* \param node DOM node
* \param qname Name to match
* \param value Value to match
* \param match Pointer to location to receive result
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_has_attribute_equal(void *pw, void *node,
const css_qname *qname, lwc_string *value,
bool *match)
{
dom_node *n = node;
dom_string *name;
dom_string *atr_val;
dom_exception err;
 
size_t vlen = lwc_string_length(value);
 
if (vlen == 0) {
*match = false;
return CSS_OK;
}
 
err = dom_string_create_interned(
(const uint8_t *) lwc_string_data(qname->name),
lwc_string_length(qname->name), &name);
if (err != DOM_NO_ERR)
return CSS_NOMEM;
 
err = dom_element_get_attribute(n, name, &atr_val);
if ((err != DOM_NO_ERR) || (atr_val == NULL)) {
dom_string_unref(name);
*match = false;
return CSS_OK;
}
 
dom_string_unref(name);
 
*match = dom_string_caseless_lwc_isequal(atr_val, value);
 
dom_string_unref(atr_val);
 
return CSS_OK;
}
 
/**
* Callback to determine if a node has an attribute with the given name whose
* value dashmatches that given.
*
* \param pw HTML document
* \param node DOM node
* \param qname Name to match
* \param value Value to match
* \param match Pointer to location to receive result
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_has_attribute_dashmatch(void *pw, void *node,
const css_qname *qname, lwc_string *value,
bool *match)
{
dom_node *n = node;
dom_string *name;
dom_string *atr_val;
dom_exception err;
 
size_t vlen = lwc_string_length(value);
 
if (vlen == 0) {
*match = false;
return CSS_OK;
}
 
err = dom_string_create_interned(
(const uint8_t *) lwc_string_data(qname->name),
lwc_string_length(qname->name), &name);
if (err != DOM_NO_ERR)
return CSS_NOMEM;
 
err = dom_element_get_attribute(n, name, &atr_val);
if ((err != DOM_NO_ERR) || (atr_val == NULL)) {
dom_string_unref(name);
*match = false;
return CSS_OK;
}
 
dom_string_unref(name);
 
/* check for exact match */
*match = dom_string_caseless_lwc_isequal(atr_val, value);
 
/* check for dashmatch */
if (*match == false) {
const char *vdata = lwc_string_data(value);
const char *data = (const char *) dom_string_data(atr_val);
size_t len = dom_string_byte_length(atr_val);
 
if (len > vlen && data[vlen] == '-' &&
strncasecmp(data, vdata, vlen) == 0) {
*match = true;
}
}
 
dom_string_unref(atr_val);
 
return CSS_OK;
}
 
/**
* Callback to determine if a node has an attribute with the given name whose
* value includes that given.
*
* \param pw HTML document
* \param node DOM node
* \param qname Name to match
* \param value Value to match
* \param match Pointer to location to receive result
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_has_attribute_includes(void *pw, void *node,
const css_qname *qname, lwc_string *value,
bool *match)
{
dom_node *n = node;
dom_string *name;
dom_string *atr_val;
dom_exception err;
size_t vlen = lwc_string_length(value);
const char *p;
const char *start;
const char *end;
 
*match = false;
 
if (vlen == 0) {
return CSS_OK;
}
 
err = dom_string_create_interned(
(const uint8_t *) lwc_string_data(qname->name),
lwc_string_length(qname->name), &name);
if (err != DOM_NO_ERR)
return CSS_NOMEM;
 
err = dom_element_get_attribute(n, name, &atr_val);
if ((err != DOM_NO_ERR) || (atr_val == NULL)) {
dom_string_unref(name);
*match = false;
return CSS_OK;
}
 
dom_string_unref(name);
 
/* check for match */
start = (const char *) dom_string_data(atr_val);
end = start + dom_string_byte_length(atr_val);
 
for (p = start; p <= end; p++) {
if (*p == ' ' || *p == '\0') {
if ((size_t) (p - start) == vlen &&
strncasecmp(start,
lwc_string_data(value),
vlen) == 0) {
*match = true;
break;
}
 
start = p + 1;
}
}
 
dom_string_unref(atr_val);
 
return CSS_OK;
}
 
/**
* Callback to determine if a node has an attribute with the given name whose
* value has the prefix given.
*
* \param pw HTML document
* \param node DOM node
* \param qname Name to match
* \param value Value to match
* \param match Pointer to location to receive result
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_has_attribute_prefix(void *pw, void *node,
const css_qname *qname, lwc_string *value,
bool *match)
{
dom_node *n = node;
dom_string *name;
dom_string *atr_val;
dom_exception err;
 
size_t vlen = lwc_string_length(value);
 
if (vlen == 0) {
*match = false;
return CSS_OK;
}
 
err = dom_string_create_interned(
(const uint8_t *) lwc_string_data(qname->name),
lwc_string_length(qname->name), &name);
if (err != DOM_NO_ERR)
return CSS_NOMEM;
 
err = dom_element_get_attribute(n, name, &atr_val);
if ((err != DOM_NO_ERR) || (atr_val == NULL)) {
dom_string_unref(name);
*match = false;
return CSS_OK;
}
 
dom_string_unref(name);
 
/* check for exact match */
*match = dom_string_caseless_lwc_isequal(atr_val, value);
 
/* check for prefix match */
if (*match == false) {
const char *data = (const char *) dom_string_data(atr_val);
size_t len = dom_string_byte_length(atr_val);
 
if ((len >= vlen) &&
(strncasecmp(data, lwc_string_data(value), vlen) == 0)) {
*match = true;
}
}
 
dom_string_unref(atr_val);
 
return CSS_OK;
}
 
/**
* Callback to determine if a node has an attribute with the given name whose
* value has the suffix given.
*
* \param pw HTML document
* \param node DOM node
* \param qname Name to match
* \param value Value to match
* \param match Pointer to location to receive result
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_has_attribute_suffix(void *pw, void *node,
const css_qname *qname, lwc_string *value,
bool *match)
{
dom_node *n = node;
dom_string *name;
dom_string *atr_val;
dom_exception err;
 
size_t vlen = lwc_string_length(value);
 
if (vlen == 0) {
*match = false;
return CSS_OK;
}
 
err = dom_string_create_interned(
(const uint8_t *) lwc_string_data(qname->name),
lwc_string_length(qname->name), &name);
if (err != DOM_NO_ERR)
return CSS_NOMEM;
 
err = dom_element_get_attribute(n, name, &atr_val);
if ((err != DOM_NO_ERR) || (atr_val == NULL)) {
dom_string_unref(name);
*match = false;
return CSS_OK;
}
 
dom_string_unref(name);
 
/* check for exact match */
*match = dom_string_caseless_lwc_isequal(atr_val, value);
 
/* check for prefix match */
if (*match == false) {
const char *data = (const char *) dom_string_data(atr_val);
size_t len = dom_string_byte_length(atr_val);
const char *start = (char *) data + len - vlen;
 
if ((len >= vlen) &&
(strncasecmp(start, lwc_string_data(value), vlen) == 0)) {
*match = true;
}
 
 
}
 
dom_string_unref(atr_val);
 
return CSS_OK;
}
 
/**
* Callback to determine if a node has an attribute with the given name whose
* value contains the substring given.
*
* \param pw HTML document
* \param node DOM node
* \param qname Name to match
* \param value Value to match
* \param match Pointer to location to receive result
* \return CSS_OK on success,
* CSS_NOMEM on memory exhaustion.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_has_attribute_substring(void *pw, void *node,
const css_qname *qname, lwc_string *value,
bool *match)
{
dom_node *n = node;
dom_string *name;
dom_string *atr_val;
dom_exception err;
 
size_t vlen = lwc_string_length(value);
 
if (vlen == 0) {
*match = false;
return CSS_OK;
}
 
err = dom_string_create_interned(
(const uint8_t *) lwc_string_data(qname->name),
lwc_string_length(qname->name), &name);
if (err != DOM_NO_ERR)
return CSS_NOMEM;
 
err = dom_element_get_attribute(n, name, &atr_val);
if ((err != DOM_NO_ERR) || (atr_val == NULL)) {
dom_string_unref(name);
*match = false;
return CSS_OK;
}
 
dom_string_unref(name);
 
/* check for exact match */
*match = dom_string_caseless_lwc_isequal(atr_val, value);
 
/* check for prefix match */
if (*match == false) {
const char *vdata = lwc_string_data(value);
const char *start = (const char *) dom_string_data(atr_val);
size_t len = dom_string_byte_length(atr_val);
const char *last_start = start + len - vlen;
 
if (len >= vlen) {
while (start <= last_start) {
if (strncasecmp(start, vdata,
vlen) == 0) {
*match = true;
break;
}
 
start++;
}
}
}
 
dom_string_unref(atr_val);
 
return CSS_OK;
}
 
/**
* Callback to determine if a node is the root node of the document.
*
* \param pw HTML document
* \param node DOM node
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_is_root(void *pw, void *node, bool *match)
{
dom_node *n = node;
dom_node *parent;
dom_node_type type;
dom_exception err;
 
err = dom_node_get_parent_node(n, &parent);
if (err != DOM_NO_ERR) {
return CSS_NOMEM;
}
 
if (parent != NULL) {
err = dom_node_get_node_type(parent, &type);
 
dom_node_unref(parent);
 
if (err != DOM_NO_ERR)
return CSS_NOMEM;
 
if (type != DOM_DOCUMENT_NODE) {
*match = false;
return CSS_OK;
}
}
*match = true;
 
return CSS_OK;
}
 
static int
node_count_siblings_check(dom_node *node,
bool check_name,
dom_string *name)
{
dom_node_type type;
int ret = 0;
dom_exception exc;
 
if (node == NULL)
return 0;
 
exc = dom_node_get_node_type(node, &type);
if ((exc != DOM_NO_ERR) || (type != DOM_ELEMENT_NODE)) {
return 0;
}
if (check_name) {
dom_string *node_name = NULL;
exc = dom_node_get_node_name(node, &node_name);
 
if ((exc == DOM_NO_ERR) && (node_name != NULL)) {
 
if (dom_string_caseless_isequal(name,
node_name)) {
ret = 1;
}
dom_string_unref(node_name);
}
} else {
ret = 1;
}
return ret;
}
/**
* Callback to count a node's siblings.
*
* \param pw HTML document
* \param node DOM node
* \param same_name Only count siblings with the same name, or all
* \param after Count anteceding instead of preceding siblings
* \param count Pointer to location to receive result
* \return CSS_OK.
*
* \post \a count will contain the number of siblings
*/
css_error node_count_siblings(void *pw, void *n, bool same_name,
bool after, int32_t *count)
{
int32_t cnt = 0;
dom_exception exc;
dom_string *node_name = NULL;
 
if (same_name) {
dom_node *node = n;
exc = dom_node_get_node_name(node, &node_name);
if ((exc != DOM_NO_ERR) || (node_name == NULL)) {
return CSS_NOMEM;
}
}
if (after) {
dom_node *node = dom_node_ref(n);
dom_node *next;
do {
exc = dom_node_get_next_sibling(node, &next);
if ((exc != DOM_NO_ERR))
break;
dom_node_unref(node);
node = next;
 
cnt += node_count_siblings_check(node, same_name, node_name);
} while (node != NULL);
} else {
dom_node *node = dom_node_ref(n);
dom_node *next;
do {
exc = dom_node_get_previous_sibling(node, &next);
if ((exc != DOM_NO_ERR))
break;
dom_node_unref(node);
node = next;
 
cnt += node_count_siblings_check(node, same_name, node_name);
 
} while (node != NULL);
}
 
if (node_name != NULL) {
dom_string_unref(node_name);
}
 
*count = cnt;
return CSS_OK;
}
 
/**
* Callback to determine if a node is empty.
*
* \param pw HTML document
* \param node DOM node
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match will contain true if the node is empty and false otherwise.
*/
css_error node_is_empty(void *pw, void *node, bool *match)
{
dom_node *n = node, *next;
dom_exception err;
*match = true;
err = dom_node_get_first_child(n, &n);
if (err != DOM_NO_ERR) {
return CSS_BADPARM;
}
while (n != NULL) {
dom_node_type ntype;
err = dom_node_get_node_type(n, &ntype);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return CSS_BADPARM;
}
if (ntype == DOM_ELEMENT_NODE ||
ntype == DOM_TEXT_NODE) {
*match = false;
dom_node_unref(n);
break;
}
err = dom_node_get_next_sibling(n, &next);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return CSS_BADPARM;
}
dom_node_unref(n);
n = next;
}
return CSS_OK;
}
 
/**
* Callback to determine if a node is a linking element.
*
* \param pw HTML document
* \param n DOM node
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_is_link(void *pw, void *n, bool *match)
{
dom_node *node = n;
dom_exception exc;
dom_string *node_name = NULL;
 
exc = dom_node_get_node_name(node, &node_name);
if ((exc != DOM_NO_ERR) || (node_name == NULL)) {
return CSS_NOMEM;
}
 
if (dom_string_caseless_lwc_isequal(node_name, corestring_lwc_a)) {
bool has_href;
exc = dom_element_has_attribute(node, corestring_dom_href,
&has_href);
if ((exc == DOM_NO_ERR) && (has_href)) {
*match = true;
} else {
*match = false;
}
} else {
*match = false;
}
dom_string_unref(node_name);
 
return CSS_OK;
}
 
/**
* Callback to determine if a node is a linking element whose target has been
* visited.
*
* \param pw HTML document
* \param node DOM node
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_is_visited(void *pw, void *node, bool *match)
{
*match = false;
 
/** \todo Implement visted check in a more performant way */
 
#ifdef SUPPORT_VISITED
nscss_select_ctx *ctx = pw;
xmlNode *n = node;
 
if (strcasecmp((const char *) n->name, "a") == 0) {
nsurl *url;
nserror error;
const struct url_data *data;
xmlChar *href = xmlGetProp(n, (const xmlChar *) "href");
 
if (href == NULL)
return CSS_OK;
 
/* Make href absolute */
/* TODO: this duplicates what we do for box->href */
error = nsurl_join(ctx->base_url, (const char *)href, &url);
 
xmlFree(href);
if (error != NSERROR_OK) {
return CSS_NOMEM;
}
 
data = urldb_get_url_data(nsurl_access(url));
 
/* Visited if in the db and has
* non-zero visit count */
if (data != NULL && data->visits > 0)
*match = true;
 
nsurl_unref(url);
}
#endif
 
return CSS_OK;
}
 
/**
* Callback to determine if a node is currently being hovered over.
*
* \param pw HTML document
* \param node DOM node
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_is_hover(void *pw, void *node, bool *match)
{
/** \todo Support hovering */
 
*match = false;
 
return CSS_OK;
}
 
/**
* Callback to determine if a node is currently activated.
*
* \param pw HTML document
* \param node DOM node
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_is_active(void *pw, void *node, bool *match)
{
/** \todo Support active nodes */
 
*match = false;
 
return CSS_OK;
}
 
/**
* Callback to determine if a node has the input focus.
*
* \param pw HTML document
* \param node DOM node
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_is_focus(void *pw, void *node, bool *match)
{
/** \todo Support focussed nodes */
 
*match = false;
 
return CSS_OK;
}
 
/**
* Callback to determine if a node is enabled.
*
* \param pw HTML document
* \param node DOM node
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match with contain true if the node is enabled and false otherwise.
*/
css_error node_is_enabled(void *pw, void *node, bool *match)
{
/** \todo Support enabled nodes */
 
*match = false;
 
return CSS_OK;
}
 
/**
* Callback to determine if a node is disabled.
*
* \param pw HTML document
* \param node DOM node
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match with contain true if the node is disabled and false otherwise.
*/
css_error node_is_disabled(void *pw, void *node, bool *match)
{
/** \todo Support disabled nodes */
 
*match = false;
 
return CSS_OK;
}
 
/**
* Callback to determine if a node is checked.
*
* \param pw HTML document
* \param node DOM node
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match with contain true if the node is checked and false otherwise.
*/
css_error node_is_checked(void *pw, void *node, bool *match)
{
/** \todo Support checked nodes */
 
*match = false;
 
return CSS_OK;
}
 
/**
* Callback to determine if a node is the target of the document URL.
*
* \param pw HTML document
* \param node DOM node
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match with contain true if the node matches and false otherwise.
*/
css_error node_is_target(void *pw, void *node, bool *match)
{
/** \todo Support target */
 
*match = false;
 
return CSS_OK;
}
 
/**
* Callback to determine if a node has the given language
*
* \param pw HTML document
* \param node DOM node
* \param lang Language specifier to match
* \param match Pointer to location to receive result
* \return CSS_OK.
*
* \post \a match will contain true if the node matches and false otherwise.
*/
css_error node_is_lang(void *pw, void *node,
lwc_string *lang, bool *match)
{
/** \todo Support languages */
 
*match = false;
 
return CSS_OK;
}
 
static css_error
node_presentational_hint_vertical_align(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_string *name;
dom_string *valign = NULL;
dom_exception err;
 
err = dom_node_get_node_name(node, &name);
if (err != DOM_NO_ERR)
return CSS_PROPERTY_NOT_SET;
 
if (dom_string_caseless_lwc_isequal(name, corestring_lwc_col) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_thead) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_tbody) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_tfoot) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_tr) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_td) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_th)) {
err = dom_element_get_attribute(node,
corestring_dom_valign, &valign);
if (err != DOM_NO_ERR || valign == NULL) {
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
 
if (dom_string_caseless_lwc_isequal(valign,
corestring_lwc_top)) {
hint->status = CSS_VERTICAL_ALIGN_TOP;
} else if (dom_string_caseless_lwc_isequal(valign,
corestring_lwc_middle)) {
hint->status = CSS_VERTICAL_ALIGN_MIDDLE;
} else if (dom_string_caseless_lwc_isequal(valign,
corestring_lwc_bottom)) {
hint->status = CSS_VERTICAL_ALIGN_BOTTOM;
} else if (dom_string_caseless_lwc_isequal(valign,
corestring_lwc_baseline)) {
hint->status = CSS_VERTICAL_ALIGN_BASELINE;
} else {
dom_string_unref(valign);
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
 
dom_string_unref(valign);
dom_string_unref(name);
 
return CSS_OK;
} else if (dom_string_caseless_lwc_isequal(name,
corestring_lwc_applet) ||
dom_string_caseless_lwc_isequal(name,
corestring_lwc_embed) ||
dom_string_caseless_lwc_isequal(name,
corestring_lwc_iframe) ||
dom_string_caseless_lwc_isequal(name,
corestring_lwc_img) ||
dom_string_caseless_lwc_isequal(name,
corestring_lwc_object)) {
/** \todo input[type=image][align=*] - $11.3.3 */
err = dom_element_get_attribute(node,
corestring_dom_align, &valign);
if (err != DOM_NO_ERR || valign == NULL) {
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
 
if (dom_string_caseless_lwc_isequal(valign,
corestring_lwc_top)) {
hint->status = CSS_VERTICAL_ALIGN_TOP;
} else if (dom_string_caseless_lwc_isequal(valign,
corestring_lwc_bottom) ||
dom_string_caseless_lwc_isequal(valign,
corestring_lwc_baseline)) {
hint->status = CSS_VERTICAL_ALIGN_BASELINE;
} else if (dom_string_caseless_lwc_isequal(valign,
corestring_lwc_texttop)) {
hint->status = CSS_VERTICAL_ALIGN_TEXT_TOP;
} else if (dom_string_caseless_lwc_isequal(valign,
corestring_lwc_absmiddle) ||
dom_string_caseless_lwc_isequal(valign,
corestring_lwc_abscenter)) {
hint->status = CSS_VERTICAL_ALIGN_MIDDLE;
} else {
dom_string_unref(valign);
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
 
dom_string_unref(valign);
dom_string_unref(name);
 
return CSS_OK;
}
 
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
 
static css_error
node_presentational_hint_text_align(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_string *name;
dom_string *align = NULL;
dom_exception err;
 
err = dom_node_get_node_name(node, &name);
if (err != DOM_NO_ERR)
return CSS_PROPERTY_NOT_SET;
 
if (dom_string_caseless_lwc_isequal(name, corestring_lwc_p) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_h1) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_h2) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_h3) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_h4) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_h5) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_h6)) {
err = dom_element_get_attribute(node,
corestring_dom_align, &align);
if (err != DOM_NO_ERR || align == NULL) {
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
 
if (dom_string_caseless_lwc_isequal(align,
corestring_lwc_left)) {
hint->status = CSS_TEXT_ALIGN_LEFT;
} else if (dom_string_caseless_lwc_isequal(align,
corestring_lwc_center)) {
hint->status = CSS_TEXT_ALIGN_CENTER;
} else if (dom_string_caseless_lwc_isequal(align,
corestring_lwc_right)) {
hint->status = CSS_TEXT_ALIGN_RIGHT;
} else if (dom_string_caseless_lwc_isequal(align,
corestring_lwc_justify)) {
hint->status = CSS_TEXT_ALIGN_JUSTIFY;
} else {
dom_string_unref(align);
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
 
dom_string_unref(align);
dom_string_unref(name);
 
return CSS_OK;
} else if (dom_string_caseless_lwc_isequal(name,
corestring_lwc_center)) {
hint->status = CSS_TEXT_ALIGN_LIBCSS_CENTER;
 
dom_string_unref(name);
 
return CSS_OK;
} else if (dom_string_caseless_lwc_isequal(name,
corestring_lwc_caption)) {
err = dom_element_get_attribute(node,
corestring_dom_align, &align);
if (err != DOM_NO_ERR) {
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
 
if (align == NULL || dom_string_caseless_lwc_isequal(align,
corestring_lwc_center)) {
hint->status = CSS_TEXT_ALIGN_LIBCSS_CENTER;
} else if (dom_string_caseless_lwc_isequal(align,
corestring_lwc_left)) {
hint->status = CSS_TEXT_ALIGN_LIBCSS_LEFT;
} else if (dom_string_caseless_lwc_isequal(align,
corestring_lwc_right)) {
hint->status = CSS_TEXT_ALIGN_LIBCSS_RIGHT;
} else if (dom_string_caseless_lwc_isequal(align,
corestring_lwc_justify)) {
hint->status = CSS_TEXT_ALIGN_JUSTIFY;
} else {
dom_string_unref(align);
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
 
if (align != NULL)
dom_string_unref(align);
dom_string_unref(name);
 
return CSS_OK;
} else if (dom_string_caseless_lwc_isequal(name,
corestring_lwc_div) ||
dom_string_caseless_lwc_isequal(name,
corestring_lwc_thead) ||
dom_string_caseless_lwc_isequal(name,
corestring_lwc_tbody) ||
dom_string_caseless_lwc_isequal(name,
corestring_lwc_tfoot) ||
dom_string_caseless_lwc_isequal(name,
corestring_lwc_tr) ||
dom_string_caseless_lwc_isequal(name,
corestring_lwc_td) ||
dom_string_caseless_lwc_isequal(name,
corestring_lwc_th)) {
err = dom_element_get_attribute(node,
corestring_dom_align, &align);
if (err != DOM_NO_ERR || align == NULL) {
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
 
if (dom_string_caseless_lwc_isequal(align,
corestring_lwc_center)) {
hint->status = CSS_TEXT_ALIGN_LIBCSS_CENTER;
} else if (dom_string_caseless_lwc_isequal(align,
corestring_lwc_left)) {
hint->status = CSS_TEXT_ALIGN_LIBCSS_LEFT;
} else if (dom_string_caseless_lwc_isequal(align,
corestring_lwc_right)) {
hint->status = CSS_TEXT_ALIGN_LIBCSS_RIGHT;
} else if (dom_string_caseless_lwc_isequal(align,
corestring_lwc_justify)) {
hint->status = CSS_TEXT_ALIGN_JUSTIFY;
} else {
dom_string_unref(align);
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
 
dom_string_unref(align);
dom_string_unref(name);
 
return CSS_OK;
} else if (dom_string_caseless_lwc_isequal(name,
corestring_lwc_table)) {
/* Tables usually reset alignment */
hint->status = CSS_TEXT_ALIGN_INHERIT_IF_NON_MAGIC;
 
dom_string_unref(name);
 
return CSS_OK;
} else {
dom_string_unref(name);
 
return CSS_PROPERTY_NOT_SET;
}
 
}
 
static css_error
node_presentational_hint_padding_trbl(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_string *name;
dom_exception exc;
dom_string *cellpadding = NULL;
exc = dom_node_get_node_name(node, &name);
if (exc != DOM_NO_ERR)
return CSS_BADPARM;
if (dom_string_caseless_lwc_isequal(name, corestring_lwc_td) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_th)) {
css_qname qs;
dom_node *tablenode = NULL;
qs.ns = NULL;
qs.name = lwc_string_ref(corestring_lwc_table);
if (named_ancestor_node(ctx, node, &qs,
(void *)&tablenode) != CSS_OK) {
/* Didn't find, or had error */
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
lwc_string_unref(qs.name);
if (tablenode != NULL) {
exc = dom_element_get_attribute(tablenode,
corestring_dom_cellpadding,
&cellpadding);
if (exc != DOM_NO_ERR) {
dom_string_unref(name);
return CSS_BADPARM;
}
}
/* No need to unref tablenode, named_ancestor_node does not
* return a reffed node to the CSS
*/
}
dom_string_unref(name);
if (cellpadding == NULL)
return CSS_PROPERTY_NOT_SET;
 
if (parse_dimension(dom_string_data(cellpadding), false,
&hint->data.length.value,
&hint->data.length.unit)) {
hint->status = CSS_PADDING_SET;
} else {
dom_string_unref(cellpadding);
return CSS_PROPERTY_NOT_SET;
}
return CSS_OK;
}
 
static css_error
node_presentational_hint_margin_rl(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint,
uint32_t property)
{
dom_string *n;
dom_exception exc;
exc = dom_node_get_node_name(node, &n);
if (exc != DOM_NO_ERR)
return CSS_BADPARM;
if (dom_string_caseless_lwc_isequal(n, corestring_lwc_img) ||
dom_string_caseless_lwc_isequal(n, corestring_lwc_applet)) {
dom_string_unref(n);
exc = dom_element_get_attribute(node,
corestring_dom_hspace, &n);
if (exc != DOM_NO_ERR) {
return CSS_BADPARM;
}
if (n == NULL)
return CSS_PROPERTY_NOT_SET;
if (parse_dimension(dom_string_data(n), false,
&hint->data.length.value,
&hint->data.length.unit)) {
hint->status = CSS_MARGIN_SET;
} else {
dom_string_unref(n);
return CSS_PROPERTY_NOT_SET;
}
dom_string_unref(n);
return CSS_OK;
} else if (dom_string_caseless_lwc_isequal(n, corestring_lwc_table) ||
dom_string_caseless_lwc_isequal(n, corestring_lwc_align)) {
dom_string_unref(n);
exc = dom_element_get_attribute(node,
corestring_dom_align, &n);
if (exc != DOM_NO_ERR) {
return CSS_BADPARM;
}
if (n == NULL)
return CSS_PROPERTY_NOT_SET;
if (dom_string_caseless_lwc_isequal(n,
corestring_lwc_center) ||
dom_string_caseless_lwc_isequal(n,
corestring_lwc_abscenter) ||
dom_string_caseless_lwc_isequal(n,
corestring_lwc_middle) ||
dom_string_caseless_lwc_isequal(n,
corestring_lwc_absmiddle)) {
hint->status = CSS_MARGIN_AUTO;
} else {
dom_string_unref(n);
return CSS_PROPERTY_NOT_SET;
}
dom_string_unref(n);
return CSS_OK;
} else if (dom_string_caseless_lwc_isequal(n, corestring_lwc_hr)) {
dom_string_unref(n);
exc = dom_element_get_attribute(node,
corestring_dom_align, &n);
if (exc != DOM_NO_ERR)
return CSS_BADPARM;
if (n == NULL)
return CSS_PROPERTY_NOT_SET;
if (dom_string_caseless_lwc_isequal(n,
corestring_lwc_left)) {
if (property == CSS_PROP_MARGIN_LEFT) {
hint->data.length.value = 0;
hint->data.length.unit = CSS_UNIT_PX;
hint->status = CSS_MARGIN_SET;
} else {
hint->status = CSS_MARGIN_AUTO;
}
} else if (dom_string_caseless_lwc_isequal(n,
corestring_lwc_center)) {
hint->status = CSS_MARGIN_AUTO;
} else if (dom_string_caseless_lwc_isequal(n,
corestring_lwc_right)) {
if (property == CSS_PROP_MARGIN_RIGHT) {
hint->data.length.value = 0;
hint->data.length.unit = CSS_UNIT_PX;
hint->status = CSS_MARGIN_SET;
} else {
hint->status = CSS_MARGIN_AUTO;
}
} else {
dom_string_unref(n);
return CSS_PROPERTY_NOT_SET;
}
dom_string_unref(n);
return CSS_OK;
}
dom_string_unref(n);
return CSS_PROPERTY_NOT_SET;
}
 
static css_error
node_presentational_hint_margin_tb(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_string *name, *vspace = NULL;
dom_exception exc;
exc = dom_node_get_node_name(node, &name);
if (exc != DOM_NO_ERR)
return CSS_BADPARM;
if (dom_string_caseless_lwc_isequal(name, corestring_lwc_img) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_applet)) {
exc = dom_element_get_attribute(node, corestring_dom_vspace,
&vspace);
if (exc != DOM_NO_ERR) {
dom_string_unref(name);
return CSS_BADPARM;
}
}
dom_string_unref(name);
if (vspace == NULL)
return CSS_PROPERTY_NOT_SET;
if (parse_dimension(dom_string_data(vspace), false,
&hint->data.length.value,
&hint->data.length.unit)) {
hint->status = CSS_MARGIN_SET;
} else {
dom_string_unref(vspace);
return CSS_PROPERTY_NOT_SET;
}
 
dom_string_unref(vspace);
 
return CSS_OK;
}
 
static css_error
node_presentational_hint_border_trbl_width(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_string *name;
dom_exception exc;
dom_string *width = NULL;
bool is_table_cell = false;
exc = dom_node_get_node_name(node, &name);
if (exc != DOM_NO_ERR)
return CSS_BADPARM;
if (dom_string_caseless_lwc_isequal(name, corestring_lwc_td) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_th)) {
css_qname qs;
dom_node *tablenode = NULL;
qs.ns = NULL;
qs.name = lwc_string_ref(corestring_lwc_table);
if (named_ancestor_node(ctx, node, &qs,
(void *)&tablenode) != CSS_OK) {
/* Didn't find, or had error */
lwc_string_unref(qs.name);
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
lwc_string_unref(qs.name);
if (tablenode != NULL) {
exc = dom_element_get_attribute(tablenode,
corestring_dom_border, &width);
if (exc != DOM_NO_ERR) {
dom_string_unref(name);
return CSS_BADPARM;
}
}
/* No need to unref tablenode, named_ancestor_node does not
* return a reffed node to the CSS
*/
is_table_cell = true;
} else if (dom_string_caseless_lwc_isequal(name,
corestring_lwc_table)) {
exc = dom_element_get_attribute(node, corestring_dom_border,
&width);
if (exc != DOM_NO_ERR) {
dom_string_unref(name);
return CSS_BADPARM;
}
}
dom_string_unref(name);
if (width == NULL)
return CSS_PROPERTY_NOT_SET;
 
if (parse_dimension(dom_string_data(width), false,
&hint->data.length.value,
&hint->data.length.unit)) {
if (is_table_cell &&
INTTOFIX(0) !=
hint->data.length.value) {
hint->data.length.value = INTTOFIX(1);
hint->data.length.unit = CSS_UNIT_PX;
}
hint->status = CSS_BORDER_WIDTH_WIDTH;
} else {
dom_string_unref(width);
return CSS_PROPERTY_NOT_SET;
}
 
dom_string_unref(width);
 
return CSS_OK;
}
 
static css_error
node_presentational_hint_border_trbl_style(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_string *name;
dom_exception exc;
 
exc = dom_node_get_node_name(node, &name);
if (exc != DOM_NO_ERR)
return CSS_BADPARM;
 
if (dom_string_caseless_lwc_isequal(name, corestring_lwc_td) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_th)) {
css_qname qs;
dom_node *tablenode = NULL;
qs.ns = NULL;
qs.name = lwc_string_ref(corestring_lwc_table);
 
if (named_ancestor_node(ctx, node, &qs,
(void *)&tablenode) != CSS_OK) {
/* Didn't find, or had error */
lwc_string_unref(qs.name);
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
lwc_string_unref(qs.name);
 
if (tablenode != NULL) {
bool has_border = false;
 
exc = dom_element_has_attribute(tablenode,
corestring_dom_border,
&has_border);
if (exc != DOM_NO_ERR) {
dom_string_unref(name);
return CSS_BADPARM;
}
 
if (has_border) {
hint->status = CSS_BORDER_STYLE_INSET;
dom_string_unref(name);
return CSS_OK;
}
}
/* No need to unref tablenode, named_ancestor_node does not
* return a reffed node to the CSS
*/
} else if (dom_string_caseless_lwc_isequal(name,
corestring_lwc_table)) {
bool has_border = false;
 
exc = dom_element_has_attribute(node,
corestring_dom_border,
&has_border);
if (exc != DOM_NO_ERR) {
dom_string_unref(name);
return CSS_BADPARM;
}
 
if (has_border) {
hint->status = CSS_BORDER_STYLE_OUTSET;
dom_string_unref(name);
return CSS_OK;
}
}
 
dom_string_unref(name);
 
return CSS_PROPERTY_NOT_SET;
}
 
static css_error
node_presentational_hint_border_trbl_color(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_string *name;
dom_string *bordercolor = NULL;
dom_exception err;
 
err = dom_node_get_node_name(node, &name);
if (err != DOM_NO_ERR)
return CSS_PROPERTY_NOT_SET;
 
if (dom_string_caseless_lwc_isequal(name, corestring_lwc_td) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_th)) {
css_qname qs;
dom_node *tablenode = NULL;
qs.ns = NULL;
qs.name = lwc_string_ref(corestring_lwc_table);
 
if (named_ancestor_node(ctx, node, &qs,
(void *)&tablenode) != CSS_OK) {
/* Didn't find, or had error */
lwc_string_unref(qs.name);
dom_string_unref(name);
return CSS_PROPERTY_NOT_SET;
}
lwc_string_unref(qs.name);
 
if (tablenode != NULL) {
err = dom_element_get_attribute(node,
corestring_dom_bordercolor,
&bordercolor);
}
/* No need to unref tablenode, named_ancestor_node does not
* return a reffed node to the CSS
*/
 
} else if (dom_string_caseless_lwc_isequal(name,
corestring_lwc_table)) {
err = dom_element_get_attribute(node,
corestring_dom_bordercolor,
&bordercolor);
}
 
dom_string_unref(name);
 
if ((err != DOM_NO_ERR) || (bordercolor == NULL)) {
return CSS_PROPERTY_NOT_SET;
}
 
if (nscss_parse_colour((const char *)dom_string_data(bordercolor),
&hint->data.color)) {
hint->status = CSS_BORDER_COLOR_COLOR;
dom_string_unref(bordercolor);
return CSS_OK;
}
 
dom_string_unref(bordercolor);
return CSS_PROPERTY_NOT_SET;
}
 
static css_error
node_presentational_hint_border_spacing(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_exception err;
dom_string *node_name = NULL;
dom_string *cellspacing = NULL;
 
err = dom_node_get_node_name(node, &node_name);
if ((err != DOM_NO_ERR) || (node_name == NULL)) {
return CSS_PROPERTY_NOT_SET;
}
 
if (!dom_string_caseless_lwc_isequal(node_name,
corestring_lwc_table)) {
dom_string_unref(node_name);
return CSS_PROPERTY_NOT_SET;
}
 
dom_string_unref(node_name);
 
err = dom_element_get_attribute(node,
corestring_dom_cellspacing, &cellspacing);
if ((err != DOM_NO_ERR) || (cellspacing == NULL)) {
return CSS_PROPERTY_NOT_SET;
}
 
 
if (parse_dimension((const char *)dom_string_data(cellspacing),
false,
&hint->data.position.h.value,
&hint->data.position.h.unit)) {
 
hint->data.position.v = hint->data.position.h;
hint->status = CSS_BORDER_SPACING_SET;
 
dom_string_unref(cellspacing);
return CSS_OK;
}
 
dom_string_unref(cellspacing);
return CSS_PROPERTY_NOT_SET;
}
 
static css_error
node_presentational_hint_width(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_string *name;
dom_string *width = NULL;
dom_exception err;
bool textarea = false;
bool input = false;
 
err = dom_node_get_node_name(node, &name);
if (err != DOM_NO_ERR)
return CSS_PROPERTY_NOT_SET;
 
if (dom_string_caseless_lwc_isequal(name, corestring_lwc_hr) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_iframe) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_img) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_object) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_table) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_td) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_th) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_applet)) {
err = dom_element_get_attribute(node,
corestring_dom_width, &width);
} else if (dom_string_caseless_lwc_isequal(name,
corestring_lwc_textarea)) {
textarea = true;
err = dom_element_get_attribute(node,
corestring_dom_cols, &width);
} else if (dom_string_caseless_lwc_isequal(name,
corestring_lwc_input)) {
input = true;
err = dom_element_get_attribute(node,
corestring_dom_size, &width);
}
 
dom_string_unref(name);
 
if ((err != DOM_NO_ERR) || (width == NULL)) {
return CSS_PROPERTY_NOT_SET;
}
 
if (parse_dimension((const char *)dom_string_data(width),
false,
&hint->data.length.value,
&hint->data.length.unit)) {
hint->status = CSS_WIDTH_SET;
dom_string_unref(width);
 
if (textarea) {
hint->data.length.unit = CSS_UNIT_EX;
}
 
if (input) {
err = dom_element_get_attribute(node,
corestring_dom_type, &width);
if (err != DOM_NO_ERR) {
return CSS_PROPERTY_NOT_SET;
}
 
if ((width == NULL) ||
dom_string_caseless_lwc_isequal(width,
corestring_lwc_text) ||
dom_string_caseless_lwc_isequal(width,
corestring_lwc_search) ||
dom_string_caseless_lwc_isequal(width,
corestring_lwc_file) ||
dom_string_caseless_lwc_isequal(width,
corestring_lwc_password)) {
hint->data.length.unit = CSS_UNIT_EX;
}
dom_string_unref(width);
}
 
return CSS_OK;
}
 
dom_string_unref(width);
return CSS_PROPERTY_NOT_SET;
 
}
 
static css_error
node_presentational_hint_height(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_string *name;
dom_string *height = NULL;
dom_exception err;
bool textarea = false;
 
err = dom_node_get_node_name(node, &name);
if (err != DOM_NO_ERR)
return CSS_PROPERTY_NOT_SET;
 
if (dom_string_caseless_lwc_isequal(name, corestring_lwc_iframe) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_td) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_th) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_tr) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_img) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_object) ||
dom_string_caseless_lwc_isequal(name, corestring_lwc_applet)) {
err = dom_element_get_attribute(node,
corestring_dom_height, &height);
} else if (dom_string_caseless_lwc_isequal(name,
corestring_lwc_textarea)) {
textarea = true;
err = dom_element_get_attribute(node,
corestring_dom_rows, &height);
}
 
dom_string_unref(name);
 
if ((err != DOM_NO_ERR) || (height == NULL)) {
return CSS_PROPERTY_NOT_SET;
}
 
if (parse_dimension((const char *)dom_string_data(height),
false,
&hint->data.length.value,
&hint->data.length.unit)) {
hint->status = CSS_HEIGHT_SET;
 
if (textarea) {
hint->data.length.unit = CSS_UNIT_EM;
}
 
dom_string_unref(height);
return CSS_OK;
}
 
dom_string_unref(height);
return CSS_PROPERTY_NOT_SET;
}
 
static css_error
node_presentational_hint_font_size(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_exception err;
dom_string *node_name = NULL;
dom_string *size;
 
err = dom_node_get_node_name(node, &node_name);
if ((err != DOM_NO_ERR) || (node_name == NULL)) {
return CSS_NOMEM;
}
 
if (!dom_string_caseless_lwc_isequal(node_name,
corestring_lwc_font)) {
dom_string_unref(node_name);
return CSS_PROPERTY_NOT_SET;
}
 
dom_string_unref(node_name);
 
err = dom_element_get_attribute(node, corestring_dom_size, &size);
if ((err != DOM_NO_ERR) || (size == NULL)) {
return CSS_PROPERTY_NOT_SET;
}
 
if (parse_font_size((const char *)dom_string_data(size),
&hint->status,
&hint->data.length.value,
&hint->data.length.unit)) {
dom_string_unref(size);
return CSS_OK;
}
 
dom_string_unref(size);
return CSS_PROPERTY_NOT_SET;
}
 
static css_error
node_presentational_hint_float(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_exception err;
dom_string *node_name = NULL;
dom_string *align;
 
err = dom_node_get_node_name(node, &node_name);
if ((err != DOM_NO_ERR) || (node_name == NULL)) {
return CSS_NOMEM;
}
 
/** \todo input[type=image][align=*] - $11.3.3 */
if (!dom_string_caseless_lwc_isequal(node_name,
corestring_lwc_applet) &&
!dom_string_caseless_lwc_isequal(node_name,
corestring_lwc_embed) &&
!dom_string_caseless_lwc_isequal(node_name,
corestring_lwc_iframe) &&
!dom_string_caseless_lwc_isequal(node_name,
corestring_lwc_img) &&
!dom_string_caseless_lwc_isequal(node_name,
corestring_lwc_object)) {
dom_string_unref(node_name);
return CSS_PROPERTY_NOT_SET;
}
 
dom_string_unref(node_name);
 
err = dom_element_get_attribute(node, corestring_dom_align, &align);
if ((err != DOM_NO_ERR) || (align == NULL)) {
return CSS_PROPERTY_NOT_SET;
}
 
if (dom_string_caseless_lwc_isequal(align,
corestring_lwc_left)) {
hint->status = CSS_FLOAT_LEFT;
dom_string_unref(align);
return CSS_OK;
} else if (dom_string_caseless_lwc_isequal(align,
corestring_lwc_right)) {
hint->status = CSS_FLOAT_RIGHT;
dom_string_unref(align);
return CSS_OK;
}
 
dom_string_unref(align);
 
return CSS_PROPERTY_NOT_SET;
}
 
static css_error
node_presentational_hint_color(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
css_error error;
dom_exception err;
dom_string *node_name = NULL;
dom_string *color;
 
err = dom_node_get_node_name(node, &node_name);
if ((err != DOM_NO_ERR) || (node_name == NULL)) {
return CSS_NOMEM;
}
 
if (dom_string_caseless_lwc_isequal(node_name, corestring_lwc_a)) {
/* find body node */
css_qname qs;
dom_node *bodynode = NULL;
bool is_visited;
 
qs.ns = NULL;
qs.name = lwc_string_ref(corestring_lwc_body);
if (named_ancestor_node(ctx, node, &qs,
(void *)&bodynode) != CSS_OK) {
/* Didn't find, or had error */
lwc_string_unref(qs.name);
dom_string_unref(node_name);
return CSS_PROPERTY_NOT_SET;
}
lwc_string_unref(qs.name);
 
/* deal with missing body ancestor */
if (bodynode == NULL) {
dom_string_unref(node_name);
return CSS_BADPARM;
}
 
error = node_is_visited(ctx, node, &is_visited);
if (error != CSS_OK)
return error;
 
if (is_visited) {
err = dom_element_get_attribute(bodynode,
corestring_dom_vlink, &color);
if ((err != DOM_NO_ERR) || (color == NULL)) {
dom_string_unref(node_name);
return CSS_PROPERTY_NOT_SET;
}
} else {
err = dom_element_get_attribute(bodynode,
corestring_dom_link, &color);
if ((err != DOM_NO_ERR) || (color == NULL)) {
dom_string_unref(node_name);
return CSS_PROPERTY_NOT_SET;
}
}
} else if (dom_string_caseless_lwc_isequal(node_name,
corestring_lwc_body)) {
err = dom_element_get_attribute(node,
corestring_dom_text, &color);
if ((err != DOM_NO_ERR) || (color == NULL)) {
dom_string_unref(node_name);
return CSS_PROPERTY_NOT_SET;
}
} else {
err = dom_element_get_attribute(node,
corestring_dom_color, &color);
if ((err != DOM_NO_ERR) || (color == NULL)) {
dom_string_unref(node_name);
return CSS_PROPERTY_NOT_SET;
}
}
 
if (!nscss_parse_colour((const char *)dom_string_data(color),
&hint->data.color)) {
dom_string_unref(node_name);
return CSS_PROPERTY_NOT_SET;
}
 
hint->status = CSS_COLOR_COLOR;
 
dom_string_unref(node_name);
 
return CSS_OK;
}
 
static css_error
node_presentational_hint_caption_side(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_exception err;
dom_string *node_name = NULL;
dom_string *align = NULL;
 
err = dom_node_get_node_name(node, &node_name);
if ((err != DOM_NO_ERR) || (node_name == NULL)) {
return CSS_PROPERTY_NOT_SET;
}
 
if (!dom_string_caseless_lwc_isequal(node_name,
corestring_lwc_caption)) {
dom_string_unref(node_name);
return CSS_PROPERTY_NOT_SET;
}
 
dom_string_unref(node_name);
 
err = dom_element_get_attribute(node, corestring_dom_align, &align);
if ((err != DOM_NO_ERR) || (align == NULL)) {
return CSS_PROPERTY_NOT_SET;
}
 
if (dom_string_caseless_lwc_isequal(align, corestring_lwc_bottom)) {
hint->status = CSS_CAPTION_SIDE_BOTTOM;
dom_string_unref(align);
return CSS_OK;
}
 
dom_string_unref(align);
 
return CSS_PROPERTY_NOT_SET;
}
 
static css_error
node_presentational_hint_background_color(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_exception err;
dom_string *bgcolor;
 
err = dom_element_get_attribute(node,
corestring_dom_bgcolor, &bgcolor);
if ((err != DOM_NO_ERR) || (bgcolor == NULL)) {
return CSS_PROPERTY_NOT_SET;
}
 
if (nscss_parse_colour((const char *)dom_string_data(bgcolor),
&hint->data.color)) {
hint->status = CSS_BACKGROUND_COLOR_COLOR;
dom_string_unref(bgcolor);
return CSS_OK;
}
 
dom_string_unref(bgcolor);
 
return CSS_PROPERTY_NOT_SET;
}
 
static css_error
node_presentational_hint_background_image(nscss_select_ctx *ctx,
dom_node *node,
css_hint *hint)
{
dom_exception err;
dom_string *atr_val;
nserror error;
nsurl *url;
lwc_string *iurl;
lwc_error lerror;
 
err = dom_element_get_attribute(node,
corestring_dom_background, &atr_val);
if ((err != DOM_NO_ERR) || (atr_val == NULL)) {
return CSS_PROPERTY_NOT_SET;
}
 
error = nsurl_join(ctx->base_url,
(const char *)dom_string_data(atr_val), &url);
 
dom_string_unref(atr_val);
 
if (error != NSERROR_OK) {
return CSS_NOMEM;
}
 
lerror = lwc_intern_string(nsurl_access(url),
nsurl_length(url), &iurl);
 
nsurl_unref(url);
 
if (lerror == lwc_error_oom) {
return CSS_NOMEM;
}
 
if (lerror == lwc_error_ok) {
hint->data.string = iurl;
hint->status = CSS_BACKGROUND_IMAGE_IMAGE;
return CSS_OK;
}
return CSS_PROPERTY_NOT_SET;
}
 
/**
* Callback to retrieve presentational hints for a node
*
* \param pw HTML document
* \param node DOM node
* \param property CSS property to retrieve
* \param hint Pointer to hint object to populate
* \return CSS_OK on success,
* CSS_PROPERTY_NOT_SET if there is no hint for the requested property,
* CSS_NOMEM on memory exhaustion.
*/
css_error node_presentational_hint(void *pw, void *node,
uint32_t property, css_hint *hint)
{
 
switch (property) {
case CSS_PROP_BACKGROUND_IMAGE:
return node_presentational_hint_background_image(pw, node, hint);
 
case CSS_PROP_BACKGROUND_COLOR:
return node_presentational_hint_background_color(pw, node, hint);
case CSS_PROP_CAPTION_SIDE:
return node_presentational_hint_caption_side(pw, node, hint);
 
case CSS_PROP_COLOR:
return node_presentational_hint_color(pw, node, hint);
 
case CSS_PROP_FLOAT:
return node_presentational_hint_float(pw, node, hint);
 
case CSS_PROP_FONT_SIZE:
return node_presentational_hint_font_size(pw, node, hint);
 
case CSS_PROP_HEIGHT:
return node_presentational_hint_height(pw, node, hint);
 
case CSS_PROP_WIDTH:
return node_presentational_hint_width(pw, node, hint);
 
case CSS_PROP_BORDER_SPACING:
return node_presentational_hint_border_spacing(pw, node, hint);
 
case CSS_PROP_BORDER_TOP_COLOR :
case CSS_PROP_BORDER_RIGHT_COLOR :
case CSS_PROP_BORDER_BOTTOM_COLOR :
case CSS_PROP_BORDER_LEFT_COLOR :
return node_presentational_hint_border_trbl_color(pw, node, hint);
 
case CSS_PROP_BORDER_TOP_STYLE :
case CSS_PROP_BORDER_RIGHT_STYLE :
case CSS_PROP_BORDER_BOTTOM_STYLE :
case CSS_PROP_BORDER_LEFT_STYLE :
return node_presentational_hint_border_trbl_style(pw, node, hint);
 
case CSS_PROP_BORDER_TOP_WIDTH :
case CSS_PROP_BORDER_RIGHT_WIDTH :
case CSS_PROP_BORDER_BOTTOM_WIDTH :
case CSS_PROP_BORDER_LEFT_WIDTH :
return node_presentational_hint_border_trbl_width(pw, node, hint);
 
case CSS_PROP_MARGIN_TOP :
case CSS_PROP_MARGIN_BOTTOM :
return node_presentational_hint_margin_tb(pw, node, hint);
 
case CSS_PROP_MARGIN_RIGHT:
case CSS_PROP_MARGIN_LEFT:
return node_presentational_hint_margin_rl(pw, node, hint, property);
 
case CSS_PROP_PADDING_TOP:
case CSS_PROP_PADDING_RIGHT :
case CSS_PROP_PADDING_BOTTOM :
case CSS_PROP_PADDING_LEFT:
return node_presentational_hint_padding_trbl(pw, node, hint);
 
case CSS_PROP_TEXT_ALIGN:
return node_presentational_hint_text_align(pw, node, hint);
 
case CSS_PROP_VERTICAL_ALIGN:
return node_presentational_hint_vertical_align(pw, node, hint);
}
 
return CSS_PROPERTY_NOT_SET;
}
 
/**
* Callback to retrieve the User-Agent defaults for a CSS property.
*
* \param pw HTML document
* \param property Property to retrieve defaults for
* \param hint Pointer to hint object to populate
* \return CSS_OK on success,
* CSS_INVALID if the property should not have a user-agent default.
*/
css_error ua_default_for_property(void *pw, uint32_t property, css_hint *hint)
{
if (property == CSS_PROP_COLOR) {
hint->data.color = 0xff000000;
hint->status = CSS_COLOR_COLOR;
} else if (property == CSS_PROP_FONT_FAMILY) {
hint->data.strings = NULL;
switch (nsoption_int(font_default)) {
case PLOT_FONT_FAMILY_SANS_SERIF:
hint->status = CSS_FONT_FAMILY_SANS_SERIF;
break;
case PLOT_FONT_FAMILY_SERIF:
hint->status = CSS_FONT_FAMILY_SERIF;
break;
case PLOT_FONT_FAMILY_MONOSPACE:
hint->status = CSS_FONT_FAMILY_MONOSPACE;
break;
case PLOT_FONT_FAMILY_CURSIVE:
hint->status = CSS_FONT_FAMILY_CURSIVE;
break;
case PLOT_FONT_FAMILY_FANTASY:
hint->status = CSS_FONT_FAMILY_FANTASY;
break;
}
} else if (property == CSS_PROP_QUOTES) {
/** \todo Not exactly useful :) */
hint->data.strings = NULL;
hint->status = CSS_QUOTES_NONE;
} else if (property == CSS_PROP_VOICE_FAMILY) {
/** \todo Fix this when we have voice-family done */
hint->data.strings = NULL;
hint->status = 0;
} else {
return CSS_INVALID;
}
 
return CSS_OK;
}
 
/**
* Mapping of colour name to CSS color
*/
struct colour_map {
const char *name;
css_color color;
};
 
/**
* Name comparator for named colour matching
*
* \param a Name to match
* \param b Colour map entry to consider
* \return 0 on match,
* < 0 if a < b,
* > 0 if b > a.
*/
int cmp_colour_name(const void *a, const void *b)
{
const char *aa = a;
const struct colour_map *bb = b;
 
return strcasecmp(aa, bb->name);
}
 
/**
* Parse a named colour
*
* \param name Name to parse
* \param result Pointer to location to receive css_color
* \return true on success, false on invalid input
*/
bool parse_named_colour(const char *name, css_color *result)
{
static const struct colour_map named_colours[] = {
{ "aliceblue", 0xfff0f8ff },
{ "antiquewhite", 0xfffaebd7 },
{ "aqua", 0xff00ffff },
{ "aquamarine", 0xff7fffd4 },
{ "azure", 0xfff0ffff },
{ "beige", 0xfff5f5dc },
{ "bisque", 0xffffe4c4 },
{ "black", 0xff000000 },
{ "blanchedalmond", 0xffffebcd },
{ "blue", 0xff0000ff },
{ "blueviolet", 0xff8a2be2 },
{ "brown", 0xffa52a2a },
{ "burlywood", 0xffdeb887 },
{ "cadetblue", 0xff5f9ea0 },
{ "chartreuse", 0xff7fff00 },
{ "chocolate", 0xffd2691e },
{ "coral", 0xffff7f50 },
{ "cornflowerblue", 0xff6495ed },
{ "cornsilk", 0xfffff8dc },
{ "crimson", 0xffdc143c },
{ "cyan", 0xff00ffff },
{ "darkblue", 0xff00008b },
{ "darkcyan", 0xff008b8b },
{ "darkgoldenrod", 0xffb8860b },
{ "darkgray", 0xffa9a9a9 },
{ "darkgreen", 0xff006400 },
{ "darkgrey", 0xffa9a9a9 },
{ "darkkhaki", 0xffbdb76b },
{ "darkmagenta", 0xff8b008b },
{ "darkolivegreen", 0xff556b2f },
{ "darkorange", 0xffff8c00 },
{ "darkorchid", 0xff9932cc },
{ "darkred", 0xff8b0000 },
{ "darksalmon", 0xffe9967a },
{ "darkseagreen", 0xff8fbc8f },
{ "darkslateblue", 0xff483d8b },
{ "darkslategray", 0xff2f4f4f },
{ "darkslategrey", 0xff2f4f4f },
{ "darkturquoise", 0xff00ced1 },
{ "darkviolet", 0xff9400d3 },
{ "deeppink", 0xffff1493 },
{ "deepskyblue", 0xff00bfff },
{ "dimgray", 0xff696969 },
{ "dimgrey", 0xff696969 },
{ "dodgerblue", 0xff1e90ff },
{ "feldspar", 0xffd19275 },
{ "firebrick", 0xffb22222 },
{ "floralwhite", 0xfffffaf0 },
{ "forestgreen", 0xff228b22 },
{ "fuchsia", 0xffff00ff },
{ "gainsboro", 0xffdcdcdc },
{ "ghostwhite", 0xfff8f8ff },
{ "gold", 0xffffd700 },
{ "goldenrod", 0xffdaa520 },
{ "gray", 0xff808080 },
{ "green", 0xff008000 },
{ "greenyellow", 0xffadff2f },
{ "grey", 0xff808080 },
{ "honeydew", 0xfff0fff0 },
{ "hotpink", 0xffff69b4 },
{ "indianred", 0xffcd5c5c },
{ "indigo", 0xff4b0082 },
{ "ivory", 0xfffffff0 },
{ "khaki", 0xfff0e68c },
{ "lavender", 0xffe6e6fa },
{ "lavenderblush", 0xfffff0f5 },
{ "lawngreen", 0xff7cfc00 },
{ "lemonchiffon", 0xfffffacd },
{ "lightblue", 0xffadd8e6 },
{ "lightcoral", 0xfff08080 },
{ "lightcyan", 0xffe0ffff },
{ "lightgoldenrodyellow", 0xfffafad2 },
{ "lightgray", 0xffd3d3d3 },
{ "lightgreen", 0xff90ee90 },
{ "lightgrey", 0xffd3d3d3 },
{ "lightpink", 0xffffb6c1 },
{ "lightsalmon", 0xffffa07a },
{ "lightseagreen", 0xff20b2aa },
{ "lightskyblue", 0xff87cefa },
{ "lightslateblue", 0xff8470ff },
{ "lightslategray", 0xff778899 },
{ "lightslategrey", 0xff778899 },
{ "lightsteelblue", 0xffb0c4de },
{ "lightyellow", 0xffffffe0 },
{ "lime", 0xff00ff00 },
{ "limegreen", 0xff32cd32 },
{ "linen", 0xfffaf0e6 },
{ "magenta", 0xffff00ff },
{ "maroon", 0xff800000 },
{ "mediumaquamarine", 0xff66cdaa },
{ "mediumblue", 0xff0000cd },
{ "mediumorchid", 0xffba55d3 },
{ "mediumpurple", 0xff9370db },
{ "mediumseagreen", 0xff3cb371 },
{ "mediumslateblue", 0xff7b68ee },
{ "mediumspringgreen", 0xff00fa9a },
{ "mediumturquoise", 0xff48d1cc },
{ "mediumvioletred", 0xffc71585 },
{ "midnightblue", 0xff191970 },
{ "mintcream", 0xfff5fffa },
{ "mistyrose", 0xffffe4e1 },
{ "moccasin", 0xffffe4b5 },
{ "navajowhite", 0xffffdead },
{ "navy", 0xff000080 },
{ "oldlace", 0xfffdf5e6 },
{ "olive", 0xff808000 },
{ "olivedrab", 0xff6b8e23 },
{ "orange", 0xffffa500 },
{ "orangered", 0xffff4500 },
{ "orchid", 0xffda70d6 },
{ "palegoldenrod", 0xffeee8aa },
{ "palegreen", 0xff98fb98 },
{ "paleturquoise", 0xffafeeee },
{ "palevioletred", 0xffdb7093 },
{ "papayawhip", 0xffffefd5 },
{ "peachpuff", 0xffffdab9 },
{ "peru", 0xffcd853f },
{ "pink", 0xffffc0cb },
{ "plum", 0xffdda0dd },
{ "powderblue", 0xffb0e0e6 },
{ "purple", 0xff800080 },
{ "red", 0xffff0000 },
{ "rosybrown", 0xffbc8f8f },
{ "royalblue", 0xff4169e1 },
{ "saddlebrown", 0xff8b4513 },
{ "salmon", 0xfffa8072 },
{ "sandybrown", 0xfff4a460 },
{ "seagreen", 0xff2e8b57 },
{ "seashell", 0xfffff5ee },
{ "sienna", 0xffa0522d },
{ "silver", 0xffc0c0c0 },
{ "skyblue", 0xff87ceeb },
{ "slateblue", 0xff6a5acd },
{ "slategray", 0xff708090 },
{ "slategrey", 0xff708090 },
{ "snow", 0xfffffafa },
{ "springgreen", 0xff00ff7f },
{ "steelblue", 0xff4682b4 },
{ "tan", 0xffd2b48c },
{ "teal", 0xff008080 },
{ "thistle", 0xffd8bfd8 },
{ "tomato", 0xffff6347 },
{ "turquoise", 0xff40e0d0 },
{ "violet", 0xffee82ee },
{ "violetred", 0xffd02090 },
{ "wheat", 0xfff5deb3 },
{ "white", 0xffffffff },
{ "whitesmoke", 0xfff5f5f5 },
{ "yellow", 0xffffff00 },
{ "yellowgreen", 0xff9acd32 }
};
const struct colour_map *entry;
 
entry = bsearch(name, named_colours,
sizeof(named_colours) / sizeof(named_colours[0]),
sizeof(named_colours[0]),
cmp_colour_name);
 
if (entry != NULL)
*result = entry->color;
 
return entry != NULL;
}
 
/**
* Parse a dimension string
*
* \param data Data to parse (NUL-terminated)
* \param strict Whether to enforce strict parsing rules
* \param length Pointer to location to receive dimension's length
* \param unit Pointer to location to receive dimension's unit
* \return true on success, false on invalid input
*/
bool parse_dimension(const char *data, bool strict, css_fixed *length,
css_unit *unit)
{
size_t len;
size_t read;
css_fixed value;
 
len = strlen(data);
 
if (parse_number(data, false, true, &value, &read) == false)
return false;
 
if (strict && value < INTTOFIX(1))
return false;
 
*length = value;
 
if (len > read && data[read] == '%')
*unit = CSS_UNIT_PCT;
else
*unit = CSS_UNIT_PX;
 
return true;
}
 
/**
* Parse a number string
*
* \param data Data to parse (NUL-terminated)
* \param maybe_negative Negative numbers permitted
* \param real Floating point numbers permitted
* \param value Pointer to location to receive numeric value
* \param consumed Pointer to location to receive number of input
* bytes consumed
* \return true on success, false on invalid input
*/
bool parse_number(const char *data, bool maybe_negative, bool real,
css_fixed *value, size_t *consumed)
{
size_t len;
const uint8_t *ptr;
int32_t intpart = 0;
int32_t fracpart = 0;
int32_t pwr = 1;
int sign = 1;
 
*consumed = 0;
 
len = strlen(data);
ptr = (const uint8_t *) data;
 
if (len == 0)
return false;
 
/* Skip leading whitespace */
while (len > 0 && isWhitespace(ptr[0])) {
len--;
ptr++;
}
 
if (len == 0)
return false;
 
/* Extract sign, if any */
if (ptr[0] == '+') {
len--;
ptr++;
} else if (ptr[0] == '-' && maybe_negative) {
sign = -1;
len--;
ptr++;
}
 
if (len == 0)
return false;
 
/* Must have a digit [0,9] */
if ('0' > ptr[0] || ptr[0] > '9')
return false;
 
/* Now extract intpart, assuming base 10 */
while (len > 0) {
/* Stop on first non-digit */
if (ptr[0] < '0' || '9' < ptr[0])
break;
 
/* Prevent overflow of 'intpart'; proper clamping below */
if (intpart < (1 << 22)) {
intpart *= 10;
intpart += ptr[0] - '0';
}
ptr++;
len--;
}
 
/* And fracpart, again, assuming base 10 */
if (real && len > 1 && ptr[0] == '.' &&
('0' <= ptr[1] && ptr[1] <= '9')) {
ptr++;
len--;
 
while (len > 0) {
if (ptr[0] < '0' || '9' < ptr[0])
break;
 
if (pwr < 1000000) {
pwr *= 10;
fracpart *= 10;
fracpart += ptr[0] - '0';
}
ptr++;
len--;
}
 
fracpart = ((1 << 10) * fracpart + pwr/2) / pwr;
if (fracpart >= (1 << 10)) {
intpart++;
fracpart &= (1 << 10) - 1;
}
}
 
if (sign > 0) {
/* If the result is larger than we can represent,
* then clamp to the maximum value we can store. */
if (intpart >= (1 << 21)) {
intpart = (1 << 21) - 1;
fracpart = (1 << 10) - 1;
}
} else {
/* If the negated result is smaller than we can represent
* then clamp to the minimum value we can store. */
if (intpart >= (1 << 21)) {
intpart = -(1 << 21);
fracpart = 0;
} else {
intpart = -intpart;
if (fracpart) {
fracpart = (1 << 10) - fracpart;
intpart--;
}
}
}
 
*value = (intpart << 10) | fracpart;
 
*consumed = ptr - (const uint8_t *) data;
 
return true;
}
 
/**
* Parse a font \@size attribute
*
* \param size Data to parse (NUL-terminated)
* \param val Pointer to location to receive enum value
* \param len Pointer to location to receive length
* \param unit Pointer to location to receive unit
* \return True on success, false on failure
*/
bool parse_font_size(const char *size, uint8_t *val,
css_fixed *len, css_unit *unit)
{
static const uint8_t size_map[] = {
CSS_FONT_SIZE_XX_SMALL,
CSS_FONT_SIZE_SMALL,
CSS_FONT_SIZE_MEDIUM,
CSS_FONT_SIZE_LARGE,
CSS_FONT_SIZE_X_LARGE,
CSS_FONT_SIZE_XX_LARGE,
CSS_FONT_SIZE_DIMENSION /* xxx-large (see below) */
};
 
const char *p = size;
char mode;
int value = 0;
 
/* Skip whitespace */
while (*p != '\0' && isWhitespace(*p))
p++;
 
mode = *p;
 
/* Skip +/- */
if (mode == '+' || mode == '-')
p++;
 
/* Need at least one digit */
if (*p < '0' || *p > '9') {
return false;
}
 
/* Consume digits, computing value */
while ('0' <= *p && *p <= '9') {
value = value * 10 + (*p - '0');
p++;
}
 
/* Resolve relative sizes */
if (mode == '+')
value += 3;
else if (mode == '-')
value = 3 - value;
 
/* Clamp to range [1,7] */
if (value < 1)
value = 1;
else if (value > 7)
value = 7;
 
if (value == 7) {
/* Manufacture xxx-large */
*len = FDIV(FMUL(INTTOFIX(3), INTTOFIX(nsoption_int(font_size))),
F_10);
} else {
/* Len is irrelevant */
*len = 0;
}
 
*unit = CSS_UNIT_PT;
*val = size_map[value - 1];
 
return true;
}
 
/******************************************************************************
* Utility functions *
******************************************************************************/
 
/**
* Determine if a given character is whitespace
*
* \param c Character to consider
* \return true if character is whitespace, false otherwise
*/
bool isWhitespace(char c)
{
return c == ' ' || c == '\t' || c == '\f' || c == '\r' || c == '\n';
}
 
/**
* Determine if a given character is a valid hex digit
*
* \param c Character to consider
* \return true if character is a valid hex digit, false otherwise
*/
bool isHex(char c)
{
return ('0' <= c && c <= '9') ||
('A' <= (c & ~0x20) && (c & ~0x20) <= 'F');
}
 
/**
* Convert a character representing a hex digit to the corresponding hex value
*
* \param c Character to convert
* \return Hex value represented by character
*
* \note This function assumes an ASCII-compatible character set
*/
uint8_t charToHex(char c)
{
/* 0-9 */
c -= '0';
 
/* A-F */
if (c > 9)
c -= 'A' - '9' - 1;
 
/* a-f */
if (c > 15)
c -= 'a' - 'A';
 
return c;
}
 
/programs/network/netsurf/netsurf/css/select.h
0,0 → 1,59
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_CSS_SELECT_H_
#define NETSURF_CSS_SELECT_H_
 
#include <stdint.h>
 
#include <dom/dom.h>
 
#include "css/css.h"
#include "utils/nsurl.h"
 
struct content;
 
/**
* Selection context
*/
typedef struct nscss_select_ctx
{
css_select_ctx *ctx;
bool quirks;
nsurl *base_url;
lwc_string *universal;
} nscss_select_ctx;
 
css_stylesheet *nscss_create_inline_style(const uint8_t *data, size_t len,
const char *charset, const char *url, bool allow_quirks,
css_allocator_fn alloc, void *pw);
 
css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n,
uint64_t media, const css_stylesheet *inline_style,
css_allocator_fn alloc, void *pw);
 
css_computed_style *nscss_get_blank_style(nscss_select_ctx *ctx,
const css_computed_style *parent,
css_allocator_fn alloc, void *pw);
 
css_error nscss_compute_font_size(void *pw, const css_hint *parent,
css_hint *size);
 
bool nscss_parse_colour(const char *data, css_color *result);
 
#endif
/programs/network/netsurf/netsurf/css/utils.c
0,0 → 1,142
/*
* Copyright 2004 James Bursa <james@netsurf-browser.org>
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <assert.h>
 
#include "css/utils.h"
 
#include "desktop/options.h"
#include "utils/log.h"
 
/** Screen DPI in fixed point units: defaults to 90, which RISC OS uses */
css_fixed nscss_screen_dpi = F_90;
 
/**
* Convert an absolute CSS length to points.
*
* \param length Length to convert
* \param unit Corresponding unit
* \return length in points
*/
css_fixed nscss_len2pt(css_fixed length, css_unit unit)
{
/* Length must not be relative */
assert(unit != CSS_UNIT_EM && unit != CSS_UNIT_EX);
 
switch (unit) {
/* We assume the screen and any other output has the same dpi */
/* 1in = DPIpx => 1px = (72/DPI)pt */
case CSS_UNIT_PX: return FDIV(FMUL(length, F_72), nscss_screen_dpi);
/* 1in = 72pt */
case CSS_UNIT_IN: return FMUL(length, F_72);
/* 1in = 2.54cm => 1cm = (72/2.54)pt */
case CSS_UNIT_CM: return FMUL(length,
FDIV(F_72, FLTTOFIX(2.54)));
/* 1in = 25.4mm => 1mm = (72/25.4)pt */
case CSS_UNIT_MM: return FMUL(length,
FDIV(F_72, FLTTOFIX(25.4)));
case CSS_UNIT_PT: return length;
/* 1pc = 12pt */
case CSS_UNIT_PC: return FMUL(length, INTTOFIX(12));
default: break;
}
 
return 0;
}
 
 
/**
* Convert a CSS length to pixels.
*
* \param length Length to convert
* \param unit Corresponding unit
* \param style Computed style applying to length. May be NULL if unit is
* neither em nor ex
* \return length in pixels
*/
css_fixed nscss_len2px(css_fixed length, css_unit unit,
const css_computed_style *style)
{
/* We assume the screen and any other output has the same dpi */
css_fixed px_per_unit;
 
assert(style != NULL || (unit != CSS_UNIT_EM && unit != CSS_UNIT_EX));
 
switch (unit) {
case CSS_UNIT_EM:
case CSS_UNIT_EX:
{
css_fixed font_size = 0;
css_unit font_unit = CSS_UNIT_PT;
 
css_computed_font_size(style, &font_size, &font_unit);
 
/* Convert to points */
font_size = nscss_len2pt(font_size, font_unit);
 
/* Clamp to configured minimum */
if (font_size < FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)) {
font_size = FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10);
}
 
/* Convert to pixels (manually, to maximise precision)
* 1in = 72pt => 1pt = (DPI/72)px */
px_per_unit = FDIV(FMUL(font_size, nscss_screen_dpi), F_72);
 
/* Scale ex units: we use a fixed ratio of 1ex = 0.6em */
if (unit == CSS_UNIT_EX)
px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.6));
}
break;
case CSS_UNIT_PX:
px_per_unit = F_1;
break;
/* 1in = DPIpx */
case CSS_UNIT_IN:
px_per_unit = nscss_screen_dpi;
break;
/* 1in = 2.54cm => 1cm = (DPI/2.54)px */
case CSS_UNIT_CM:
px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(2.54));
break;
/* 1in = 25.4mm => 1mm = (DPI/25.4)px */
case CSS_UNIT_MM:
px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(25.4));
break;
/* 1in = 72pt => 1pt = (DPI/72)px */
case CSS_UNIT_PT:
px_per_unit = FDIV(nscss_screen_dpi, F_72);
break;
/* 1pc = 12pt => 1in = 6pc => 1pc = (DPI/6)px */
case CSS_UNIT_PC:
px_per_unit = FDIV(nscss_screen_dpi, INTTOFIX(6));
break;
default:
px_per_unit = 0;
break;
}
 
/* Ensure we round px_per_unit to the nearest whole number of pixels:
* the use of FIXTOINT() below will truncate. */
px_per_unit += F_0_5;
 
/* Calculate total number of pixels */
return FMUL(length, TRUNCATEFIX(px_per_unit));
}
 
/programs/network/netsurf/netsurf/css/utils.h
0,0 → 1,55
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_CSS_UTILS_H_
#define NETSURF_CSS_UTILS_H_
 
#include "css/css.h"
#include "desktop/plot_style.h"
 
/* DPI of the screen, in fixed point units */
extern css_fixed nscss_screen_dpi;
 
/**
* Convert a CSS color to a NetSurf colour primitive
*
* ARGB -> (1-A)BGR
*
* \param color The CSS color to convert
* \return Corresponding NetSurf colour primitive
*/
#define nscss_color_to_ns(color) \
(0xff000000 - ((color) & 0xff000000)) | \
(((color) & 0xff0000) >> 16) | \
((color) & 0xff00) | \
(((color) & 0xff) << 16)
 
/**
* Determine if a CSS color primitive is transparent
*
* \param color The CSS color to consider
* \return True if the color is transparent, false otherwise
*/
#define nscss_color_is_transparent(color) \
(((color) >> 24) == 0)
 
css_fixed nscss_len2pt(css_fixed length, css_unit unit);
css_fixed nscss_len2px(css_fixed length, css_unit unit,
const css_computed_style *style);
 
#endif
/programs/network/netsurf/netsurf/desktop/401login.h
0,0 → 1,31
/*
* Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_DESKTOP_401LOGIN_H
#define NETSURF_DESKTOP_401LOGIN_H
 
#include <stdbool.h>
 
#include "utils/config.h"
#include "utils/nsurl.h"
#include "utils/errors.h"
 
void gui_401login_open(nsurl *url, const char *realm,
nserror (*cb)(bool proceed, void *pw), void *cbpw);
 
#endif
/programs/network/netsurf/netsurf/desktop/browser.c
0,0 → 1,2958
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk>
* Copyright 2004 John Tytgat <joty@netsurf-browser.org>
* Copyright 2006 Richard Wilson <info@tinct.net>
* Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Browser window creation and manipulation (implementation).
*/
 
#include <assert.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <math.h>
 
#include "curl/curl.h"
#include "utils/config.h"
#include "content/content.h"
#include "content/fetch.h"
#include "content/hlcache.h"
#include "content/urldb.h"
#include "desktop/401login.h"
#include "desktop/browser_private.h"
#include "desktop/download.h"
#include "desktop/frames.h"
#include "desktop/history_core.h"
#include "desktop/hotlist.h"
#include "desktop/gui.h"
#include "desktop/knockout.h"
#include "desktop/options.h"
#include "desktop/scrollbar.h"
#include "desktop/selection.h"
#include "desktop/textinput.h"
#include "desktop/plotters.h"
 
#include "javascript/js.h"
 
#include "render/form.h"
#include "render/textplain.h"
#include "render/html.h"
#include "render/box.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/nsurl.h"
#include "utils/schedule.h"
#include "utils/url.h"
#include "utils/utils.h"
#include "utils/utf8.h"
 
/** one or more windows require a reformat */
bool browser_reformat_pending;
 
/** maximum frame depth */
#define FRAME_DEPTH 8
 
static nserror browser_window_callback(hlcache_handle *c,
const hlcache_event *event, void *pw);
static void browser_window_refresh(void *p);
static bool browser_window_check_throbber(struct browser_window *bw);
static void browser_window_convert_to_download(struct browser_window *bw,
llcache_handle *stream);
static void browser_window_start_throbber(struct browser_window *bw);
static void browser_window_stop_throbber(struct browser_window *bw);
static void browser_window_destroy_children(struct browser_window *bw);
static void browser_window_destroy_internal(struct browser_window *bw);
static void browser_window_set_scale_internal(struct browser_window *bw,
float scale);
static void browser_window_find_target_internal(struct browser_window *bw,
const char *target, int depth, struct browser_window *page,
int *rdepth, struct browser_window **bw_target);
static void browser_window_mouse_drag_end(struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
 
 
/**
* Get position of scrollbar widget within browser window.
*
* \param bw The browser window
* \param horizontal Whether to get position of horizontal scrollbar
* \param x Updated to x-coord of top left of scrollbar widget
* \param y Updated to y-coord of top left of scrollbar widget
*/
 
static inline void browser_window_get_scrollbar_pos(struct browser_window *bw,
bool horizontal, int *x, int *y)
{
if (horizontal) {
*x = 0;
*y = bw->height - SCROLLBAR_WIDTH;
} else {
*x = bw->width - SCROLLBAR_WIDTH;
*y = 0;
}
}
 
 
/**
* Get browser window scrollbar widget length
*
* \param bw The browser window
* \param horizontal Whether to get length of horizontal scrollbar
* \return the scrollbar's length
*/
 
static inline int browser_window_get_scrollbar_len(struct browser_window *bw,
bool horizontal)
{
if (horizontal)
return bw->width - (bw->scroll_y != NULL ? SCROLLBAR_WIDTH : 0);
else
return bw->height;
}
 
/* exported interface, documented in browser.h */
bool browser_window_redraw(struct browser_window *bw, int x, int y,
const struct rect *clip, const struct redraw_context *ctx)
{
struct redraw_context new_ctx = *ctx;
int width = 0;
int height = 0;
bool plot_ok = true;
content_type content_type;
struct content_redraw_data data;
struct rect content_clip;
 
if (bw == NULL) {
LOG(("NULL browser window"));
return false;
}
 
if (bw->current_content == NULL && bw->children == NULL) {
/* Browser window has no content, render blank fill */
ctx->plot->clip(clip);
return ctx->plot->rectangle(clip->x0, clip->y0,
clip->x1, clip->y1,
plot_style_fill_white);
}
 
/* Browser window has content OR children (frames) */
 
if ((bw->window != NULL) &&
(ctx->plot->option_knockout)) {
/* Root browser window: start knockout */
knockout_plot_start(ctx, &new_ctx);
}
 
new_ctx.plot->clip(clip);
 
/* Handle redraw of any browser window children */
if (bw->children) {
struct browser_window *child;
int cur_child;
int children = bw->rows * bw->cols;
 
if (bw->window != NULL)
/* Root browser window; start with blank fill */
plot_ok &= new_ctx.plot->rectangle(clip->x0, clip->y0,
clip->x1, clip->y1,
plot_style_fill_white);
 
/* Loop through all children of bw */
for (cur_child = 0; cur_child < children; cur_child++) {
/* Set current child */
child = &bw->children[cur_child];
 
/* Get frame edge box in global coordinates */
content_clip.x0 = (x + child->x) * child->scale;
content_clip.y0 = (y + child->y) * child->scale;
content_clip.x1 = content_clip.x0 +
child->width * child->scale;
content_clip.y1 = content_clip.y0 +
child->height * child->scale;
 
/* Intersect it with clip rectangle */
if (content_clip.x0 < clip->x0)
content_clip.x0 = clip->x0;
if (content_clip.y0 < clip->y0)
content_clip.y0 = clip->y0;
if (clip->x1 < content_clip.x1)
content_clip.x1 = clip->x1;
if (clip->y1 < content_clip.y1)
content_clip.y1 = clip->y1;
 
/* Skip this frame if it lies outside clip rectangle */
if (content_clip.x0 >= content_clip.x1 ||
content_clip.y0 >= content_clip.y1)
continue;
 
/* Redraw frame */
plot_ok &= browser_window_redraw(child,
x + child->x, y + child->y,
&content_clip, &new_ctx);
}
 
/* Nothing else to redraw for browser windows with children;
* cleanup and return */
if (bw->window != NULL && ctx->plot->option_knockout) {
/* Root browser window: knockout end */
knockout_plot_end();
}
 
return plot_ok;
}
 
/* Handle browser windows with content to redraw */
 
content_type = content_get_type(bw->current_content);
if (content_type != CONTENT_HTML && content_type != CONTENT_TEXTPLAIN) {
/* Set render area according to scale */
width = content_get_width(bw->current_content) * bw->scale;
height = content_get_height(bw->current_content) * bw->scale;
 
/* Non-HTML may not fill viewport to extents, so plot white
* background fill */
plot_ok &= new_ctx.plot->rectangle(clip->x0, clip->y0,
clip->x1, clip->y1, plot_style_fill_white);
}
 
/* Set up content redraw data */
data.x = x - scrollbar_get_offset(bw->scroll_x);
data.y = y - scrollbar_get_offset(bw->scroll_y);
data.width = width;
data.height = height;
 
data.background_colour = 0xFFFFFF;
data.scale = bw->scale;
data.repeat_x = false;
data.repeat_y = false;
 
content_clip = *clip;
 
if (!bw->window) {
int x0 = x * bw->scale;
int y0 = y * bw->scale;
int x1 = (x + bw->width - ((bw->scroll_y != NULL) ?
SCROLLBAR_WIDTH : 0)) * bw->scale;
int y1 = (y + bw->height - ((bw->scroll_x != NULL) ?
SCROLLBAR_WIDTH : 0)) * bw->scale;
 
if (content_clip.x0 < x0) content_clip.x0 = x0;
if (content_clip.y0 < y0) content_clip.y0 = y0;
if (x1 < content_clip.x1) content_clip.x1 = x1;
if (y1 < content_clip.y1) content_clip.y1 = y1;
}
/* Render the content */
plot_ok &= content_redraw(bw->current_content, &data,
&content_clip, &new_ctx);
 
/* Back to full clip rect */
new_ctx.plot->clip(clip);
 
if (!bw->window) {
/* Render scrollbars */
int off_x, off_y;
if (bw->scroll_x != NULL) {
browser_window_get_scrollbar_pos(bw, true,
&off_x, &off_y);
plot_ok &= scrollbar_redraw(bw->scroll_x,
x + off_x, y + off_y, clip,
bw->scale, &new_ctx);
}
if (bw->scroll_y != NULL) {
browser_window_get_scrollbar_pos(bw, false,
&off_x, &off_y);
plot_ok &= scrollbar_redraw(bw->scroll_y,
x + off_x, y + off_y, clip,
bw->scale, &new_ctx);
}
}
if (bw->window != NULL && ctx->plot->option_knockout) {
/* Root browser window: end knockout */
knockout_plot_end();
}
 
return plot_ok;
}
 
/* exported interface, documented in browser.h */
bool browser_window_redraw_ready(struct browser_window *bw)
{
if (bw == NULL) {
LOG(("NULL browser window"));
return false;
} else if (bw->current_content != NULL) {
/* Can't render locked contents */
return !content_is_locked(bw->current_content);
}
 
return true;
}
 
/* exported interface, documented in browser.h */
void browser_window_update_extent(struct browser_window *bw)
{
if (bw->window != NULL)
/* Front end window */
gui_window_update_extent(bw->window);
else
/* Core-managed browser window */
browser_window_handle_scrollbars(bw);
}
 
/* exported interface, documented in browser.h */
void browser_window_get_position(struct browser_window *bw, bool root,
int *pos_x, int *pos_y)
{
*pos_x = 0;
*pos_y = 0;
 
assert(bw != NULL);
 
while (bw) {
switch (bw->browser_window_type) {
 
case BROWSER_WINDOW_FRAMESET:
*pos_x += bw->x * bw->scale;
*pos_y += bw->y * bw->scale;
break;
 
case BROWSER_WINDOW_NORMAL:
/* There is no offset to the root browser window */
break;
 
case BROWSER_WINDOW_FRAME:
/* Iframe and Frame handling is identical;
* fall though */
case BROWSER_WINDOW_IFRAME:
*pos_x += (bw->x - scrollbar_get_offset(bw->scroll_x)) *
bw->scale;
*pos_y += (bw->y - scrollbar_get_offset(bw->scroll_y)) *
bw->scale;
break;
}
 
bw = bw->parent;
 
if (!root) {
/* return if we just wanted the position in the parent
* browser window. */
return;
}
}
}
 
 
/* exported interface, documented in browser.h */
void browser_window_set_position(struct browser_window *bw, int x, int y)
{
assert(bw != NULL);
 
if (bw->window == NULL) {
/* Core managed browser window */
bw->x = x;
bw->y = y;
} else {
LOG(("Asked to set position of front end window."));
assert(0);
}
}
 
/* exported interface, documented in browser.h */
void browser_window_set_drag_type(struct browser_window *bw,
browser_drag_type type, const struct rect *rect)
{
struct browser_window *top_bw = browser_window_get_root(bw);
gui_drag_type gtype;
 
bw->drag_type = type;
 
if (type == DRAGGING_NONE) {
top_bw->drag_window = NULL;
} else {
top_bw->drag_window = bw;
 
switch (type) {
case DRAGGING_SCR_X:
case DRAGGING_SCR_Y:
case DRAGGING_CONTENT_SCROLLBAR:
gtype = GDRAGGING_SCROLLBAR;
break;
default:
gtype = GDRAGGING_OTHER;
break;
}
 
gui_window_drag_start(top_bw->window, gtype, rect);
}
}
 
/* exported interface, documented in browser.h */
browser_drag_type browser_window_get_drag_type(struct browser_window *bw)
{
return bw->drag_type;
}
 
/* exported interface, documented in browser.h */
struct browser_window * browser_window_get_root(struct browser_window *bw)
{
while (bw && bw->parent) {
bw = bw->parent;
}
return bw;
}
 
/* exported interface, documented in browser.h */
bool browser_window_has_selection(struct browser_window *bw)
{
assert(bw->window);
 
if (bw->cur_sel != NULL && selection_defined(bw->cur_sel)) {
return true;
} else {
return false;
}
}
 
/* exported interface, documented in browser.h */
void browser_window_set_selection(struct browser_window *bw,
struct selection *s)
{
assert(bw->window);
 
if (bw->cur_sel != s && bw->cur_sel != NULL) {
/* Clear any existing selection */
selection_clear(bw->cur_sel, true);
}
 
/* Replace current selection pointer */
if (s == NULL && bw->current_content != NULL) {
bw->cur_sel = content_get_selection(bw->current_content);
} else {
bw->cur_sel = s;
}
}
 
/* exported interface, documented in browser.h */
struct selection *browser_window_get_selection(struct browser_window *bw)
{
assert(bw->window);
 
return bw->cur_sel;
}
 
/* exported interface, documented in browser.h */
void browser_window_scroll_visible(struct browser_window *bw,
const struct rect *rect)
{
assert(bw != NULL);
 
if (bw->window != NULL) {
/* Front end window */
gui_window_scroll_visible(bw->window,
rect->x0, rect->y0, rect->x1, rect->y1);
} else {
/* Core managed browser window */
if (bw->scroll_x != NULL)
scrollbar_set(bw->scroll_x, rect->x0, false);
if (bw->scroll_y != NULL)
scrollbar_set(bw->scroll_y, rect->y0, false);
}
}
 
/* exported interface, documented in browser.h */
void browser_window_set_scroll(struct browser_window *bw, int x, int y)
{
if (bw->window != NULL) {
gui_window_set_scroll(bw->window, x, y);
} else {
if (bw->scroll_x != NULL)
scrollbar_set(bw->scroll_x, x, false);
if (bw->scroll_y != NULL)
scrollbar_set(bw->scroll_y, y, false);
}
}
 
/**
* Internal helper for browser_window_get_contextual_content
*/
static void browser_window__get_contextual_content(struct browser_window *bw,
int x, int y, struct contextual_content *data)
{
/* Handle (i)frame scroll offset (core-managed browser windows only) */
x += scrollbar_get_offset(bw->scroll_x);
y += scrollbar_get_offset(bw->scroll_y);
 
if (bw->children) {
/* Browser window has children, so pass request on to
* appropriate child */
struct browser_window *bwc;
int cur_child;
int children = bw->rows * bw->cols;
 
/* Loop through all children of bw */
for (cur_child = 0; cur_child < children; cur_child++) {
/* Set current child */
bwc = &bw->children[cur_child];
 
/* Skip this frame if (x, y) coord lies outside */
if (x < bwc->x || bwc->x + bwc->width < x ||
y < bwc->y || bwc->y + bwc->height < y)
continue;
 
/* Pass request into this child */
browser_window__get_contextual_content(bwc,
(x - bwc->x), (y - bwc->y), data);
return;
}
 
/* Coordinate not contained by any frame */
return;
}
 
if (bw->current_content == NULL)
/* No content; nothing to set */
return;
 
/* Pass request to content */
content_get_contextual_content(bw->current_content, x, y, data);
data->main = bw->current_content;
}
 
/* exported interface, documented in browser.h */
void browser_window_get_contextual_content(struct browser_window *bw,
int x, int y, struct contextual_content *data)
{
data->link_url = NULL;
data->object = NULL;
data->main = NULL;
data->form_features = CTX_FORM_NONE;
 
browser_window__get_contextual_content(bw, x, y, data);
}
 
/* exported interface, documented in browser.h */
bool browser_window_scroll_at_point(struct browser_window *bw,
int x, int y, int scrx, int scry)
{
bool handled_scroll = false;
assert(bw != NULL);
 
/* Handle (i)frame scroll offset (core-managed browser windows only) */
x += scrollbar_get_offset(bw->scroll_x);
y += scrollbar_get_offset(bw->scroll_y);
 
if (bw->children) {
/* Browser window has children, so pass request on to
* appropriate child */
struct browser_window *bwc;
int cur_child;
int children = bw->rows * bw->cols;
 
/* Loop through all children of bw */
for (cur_child = 0; cur_child < children; cur_child++) {
/* Set current child */
bwc = &bw->children[cur_child];
 
/* Skip this frame if (x, y) coord lies outside */
if (x < bwc->x || bwc->x + bwc->width < x ||
y < bwc->y || bwc->y + bwc->height < y)
continue;
 
/* Pass request into this child */
return browser_window_scroll_at_point(bwc,
(x - bwc->x), (y - bwc->y),
scrx, scry);
}
}
 
/* Try to scroll any current content */
if (bw->current_content != NULL && content_scroll_at_point(
bw->current_content, x, y, scrx, scry) == true)
/* Scroll handled by current content */
return true;
 
/* Try to scroll this window, if scroll not already handled */
if (handled_scroll == false) {
if (bw->scroll_y && scrollbar_scroll(bw->scroll_y, scry))
handled_scroll = true;
 
if (bw->scroll_x && scrollbar_scroll(bw->scroll_x, scrx))
handled_scroll = true;
}
 
return handled_scroll;
}
 
/* exported interface, documented in browser.h */
bool browser_window_drop_file_at_point(struct browser_window *bw,
int x, int y, char *file)
{
assert(bw != NULL);
 
/* Handle (i)frame scroll offset (core-managed browser windows only) */
x += scrollbar_get_offset(bw->scroll_x);
y += scrollbar_get_offset(bw->scroll_y);
 
if (bw->children) {
/* Browser window has children, so pass request on to
* appropriate child */
struct browser_window *bwc;
int cur_child;
int children = bw->rows * bw->cols;
 
/* Loop through all children of bw */
for (cur_child = 0; cur_child < children; cur_child++) {
/* Set current child */
bwc = &bw->children[cur_child];
 
/* Skip this frame if (x, y) coord lies outside */
if (x < bwc->x || bwc->x + bwc->width < x ||
y < bwc->y || bwc->y + bwc->height < y)
continue;
 
/* Pass request into this child */
return browser_window_drop_file_at_point(bwc,
(x - bwc->x), (y - bwc->y),
file);
}
}
 
/* Pass file drop on to any content */
if (bw->current_content != NULL)
return content_drop_file_at_point(bw->current_content,
x, y, file);
 
return false;
}
 
/* exported interface, documented in browser.h */
void browser_window_debug_dump(struct browser_window *bw, FILE *f)
{
if (bw->current_content != NULL)
content_debug_dump(bw->current_content, f);
}
 
 
/**
* Create and open a new root browser window with the given page.
*
* \param url URL to start fetching in the new window (copied)
* \param clone The browser window to clone
* \param referer The referring uri (copied), or 0 if none
* \param history_add add to history
* \param new_tab create a new tab
* \return new browser window or NULL on error
*/
 
struct browser_window *browser_window_create(const char *url,
struct browser_window *clone,
const char *referer, bool history_add, bool new_tab)
{
struct browser_window *bw;
struct browser_window *top;
 
LOG(("start bwc"));
assert(clone || history_add);
 
if ((bw = calloc(1, sizeof *bw)) == NULL) {
warn_user("NoMemory", 0);
return NULL;
}
 
LOG(("new js..."));
 
bw->jsctx = js_newcontext();
 
LOG(("start bw init common"));
/* Initialise common parts */
browser_window_initialise_common(bw, clone);
 
LOG(("set props"));
/* window characteristics */
bw->browser_window_type = BROWSER_WINDOW_NORMAL;
bw->scrolling = SCROLLING_YES;
bw->border = true;
bw->no_resize = true;
LOG(("wallclock!!!"));
bw->last_action = wallclock();
bw->focus = bw;
 
/* gui window */
/* from the front end's pov, it clones the top level browser window,
* so find that. */
LOG(("get root"));
top = browser_window_get_root(clone);
 
LOG(("start bw gui create"));
 
bw->window = gui_create_browser_window(bw, top, new_tab);
 
if (bw->window == NULL) {
LOG(("destroy window"));
browser_window_destroy(bw);
return NULL;
}
 
LOG(("url?"));
if (url) {
LOG(("bw go go go"));
browser_window_go(bw, url, referer, history_add);
}
 
LOG(("success bwc"));
return bw;
}
 
 
/**
* Initialise common parts of a browser window
*
* \param bw The window to initialise
* \param clone The window to clone, or NULL if none
*/
void browser_window_initialise_common(struct browser_window *bw,
struct browser_window *clone)
{
LOG(("bwc init common IN"));
assert(bw);
 
LOG(("check clone..."));
 
if (!clone){
bw->history = history_create();
LOG(("hist create"));
}
else {
bw->history = history_clone(clone->history);
LOG(("hist clone"));}
 
 
LOG(("winchar"));
/* window characteristics */
bw->cur_sel = NULL;
bw->cur_search = NULL;
bw->refresh_interval = -1;
 
bw->reformat_pending = false;
bw->drag_type = DRAGGING_NONE;
LOG(("nsoption int scale"));
bw->scale = (float) nsoption_int(scale) / 100.0;
 
 
bw->scroll_x = NULL;
bw->scroll_y = NULL;
 
bw->focus = NULL;
 
/* initialise status text cache */
bw->status_text = NULL;
bw->status_text_len = 0;
bw->status_match = 0;
bw->status_miss = 0;
LOG(("fine bwc init OK"));
 
}
 
 
/**
* Start fetching a page in a browser window.
*
* \param bw browser window
* \param url URL to start fetching (copied)
* \param referer the referring uri (copied), or 0 if none
* \param history_add Add to history
*
* Any existing fetches in the window are aborted.
*/
 
void browser_window_go(struct browser_window *bw, const char *url,
const char *referer, bool history_add)
{
/* All fetches passing through here are verifiable
* (i.e are the result of user action) */
browser_window_go_post(bw, url, 0, 0, history_add, referer,
false, true, NULL);
}
 
 
/**
* Start a download of the given URL from a browser window.
*
* \param bw browser window
* \param url URL to start downloading (copied)
* \param referer the referring uri (copied), or 0 if none
*/
 
void browser_window_download(struct browser_window *bw, const char *url,
const char *referer)
{
browser_window_go_post(bw, url, 0, 0, false, referer,
true, true, NULL);
}
 
 
/**
* Start fetching a page in a browser window.
*
* \param bw browser window
* \param url URL to start fetching (copied)
* \param referer the referring uri (copied), or 0 if none
* \param history_add add to history
* \param parent parent handle
*
* Any existing fetches in the window are aborted.
*/
 
void browser_window_go_unverifiable(struct browser_window *bw,
const char *url, const char *referer, bool history_add,
hlcache_handle *parent)
{
/* All fetches passing through here are unverifiable
* (i.e are not the result of user action) */
browser_window_go_post(bw, url, 0, 0, history_add, referer,
false, false, parent);
}
 
/**
* Start fetching a page in a browser window, POSTing form data.
*
* \param bw browser window
* \param url URL to start fetching (copied)
* \param post_urlenc url encoded post data, or 0 if none
* \param post_multipart multipart post data, or 0 if none
* \param add_to_history add to window history
* \param referer the referring uri (copied), or 0 if none
* \param download download, rather than render the uri
* \param verifiable this transaction is verifiable
* \param parent Parent content, or NULL
*
* Any existing fetches in the window are aborted.
*
* If post_urlenc and post_multipart are 0 the url is fetched using GET.
*
* The page is not added to the window history if add_to_history is false.
* This should be used when returning to a page in the window history.
*/
 
void browser_window_go_post(struct browser_window *bw, const char *url,
char *post_urlenc,
struct fetch_multipart_data *post_multipart,
bool add_to_history, const char *referer, bool download,
bool verifiable, hlcache_handle *parent)
{
LOG(("GO POST"));
hlcache_handle *c;
int depth = 0;
struct browser_window *cur;
uint32_t fetch_flags = 0;
bool fetch_is_post = (post_urlenc != NULL || post_multipart != NULL);
llcache_post_data post;
hlcache_child_context child;
nserror error;
 
nsurl *nsref = NULL;
nsurl *nsurl;
 
LOG(("bw %p, url %s", bw, url));
assert(bw);
assert(url);
 
/* don't allow massively nested framesets */
for (cur = bw; cur->parent; cur = cur->parent)
depth++;
if (depth > FRAME_DEPTH) {
LOG(("frame depth too high."));
return;
}
 
/* Set up retrieval parameters */
if (verifiable)
fetch_flags |= LLCACHE_RETRIEVE_VERIFIABLE;
 
if (post_multipart != NULL) {
post.type = LLCACHE_POST_MULTIPART;
post.data.multipart = post_multipart;
} else if (post_urlenc != NULL) {
post.type = LLCACHE_POST_URL_ENCODED;
post.data.urlenc = post_urlenc;
}
 
if (parent != NULL && content_get_type(parent) == CONTENT_HTML) {
child.charset = html_get_encoding(parent);
child.quirks = content_get_quirks(parent);
}
 
error = nsurl_create(url, &nsurl);
if (error != NSERROR_OK) {
return;
}
 
if (referer != NULL) {
error = nsurl_create(referer, &nsref);
if (error != NSERROR_OK) {
nsurl_unref(nsurl);
return;
}
}
 
/* Get download out of the way */
if (download) {
llcache_handle *l;
struct browser_window *root;
 
root = browser_window_get_root(bw);
assert(root != NULL);
 
fetch_flags |= LLCACHE_RETRIEVE_FORCE_FETCH;
fetch_flags |= LLCACHE_RETRIEVE_STREAM_DATA;
 
error = llcache_handle_retrieve(nsurl, fetch_flags, nsref,
fetch_is_post ? &post : NULL,
NULL, NULL, &l);
if (error == NSERROR_NO_FETCH_HANDLER) {
gui_launch_url(nsurl_access(nsurl));
} else if (error != NSERROR_OK) {
LOG(("Failed to fetch download: %d", error));
} else {
error = download_context_create(l, root->window);
if (error != NSERROR_OK) {
LOG(("Failed creating download context: %d",
error));
llcache_handle_abort(l);
llcache_handle_release(l);
}
}
 
nsurl_unref(nsurl);
if (nsref != NULL)
nsurl_unref(nsref);
 
return;
}
 
if (bw->frag_id != NULL)
lwc_string_unref(bw->frag_id);
bw->frag_id = NULL;
 
if (nsurl_has_component(nsurl, NSURL_FRAGMENT)) {
bool same_url = false;
 
bw->frag_id = nsurl_get_component(nsurl, NSURL_FRAGMENT);
 
/* Compare new URL with existing one (ignoring fragments) */
if (bw->current_content != NULL &&
hlcache_handle_get_url(bw->current_content) != NULL) {
same_url = nsurl_compare(nsurl,
hlcache_handle_get_url(bw->current_content),
NSURL_COMPLETE);
}
 
/* if we're simply moving to another ID on the same page,
* don't bother to fetch, just update the window.
*/
if (same_url && fetch_is_post == false &&
nsurl_has_component(nsurl, NSURL_QUERY) ==
false) {
nsurl_unref(nsurl);
if (nsref != NULL)
nsurl_unref(nsref);
if (add_to_history)
history_add(bw->history, bw->current_content,
bw->frag_id == NULL ? NULL :
lwc_string_data(bw->frag_id));
browser_window_update(bw, false);
if (bw->current_content != NULL) {
browser_window_refresh_url_bar(bw,
hlcache_handle_get_url(bw->current_content),
bw->frag_id);
}
return;
}
}
 
browser_window_stop(bw);
browser_window_remove_caret(bw);
browser_window_destroy_children(bw);
 
LOG(("Loading '%s'", nsurl_access(nsurl)));
 
LOG(("Set status loading"));
browser_window_set_status(bw, messages_get("Loading"));
bw->history_add = add_to_history;
 
/* Verifiable fetches may trigger a download */
if (verifiable)
fetch_flags |= HLCACHE_RETRIEVE_MAY_DOWNLOAD;
 
 
LOG(("hlcache retr"));
error = hlcache_handle_retrieve(nsurl,
fetch_flags | HLCACHE_RETRIEVE_SNIFF_TYPE,
nsref,
fetch_is_post ? &post : NULL,
browser_window_callback, bw,
parent != NULL ? &child : NULL,
CONTENT_ANY, &c);
 
switch (error) {
case NSERROR_NO_FETCH_HANDLER: /* no handler for this type */
LOG(("no fetcher"));
gui_launch_url(nsurl_access(nsurl));
nsurl_unref(nsurl);
if (nsref != NULL)
nsurl_unref(nsref);
break;
 
case NSERROR_OK:
LOG(("generic error"));
bw->loading_content = c;
browser_window_start_throbber(bw);
browser_window_refresh_url_bar(bw, nsurl, NULL);
 
nsurl_unref(nsurl);
if (nsref != NULL)
nsurl_unref(nsref);
break;
 
default: /* assume out of memory */
LOG(("SUKAAA don't know why"));
/* TODO: fix all fetcher errors being reported as OOM? */
nsurl_unref(nsurl);
if (nsref != NULL)
nsurl_unref(nsref);
browser_window_set_status(bw, messages_get("NoMemory"));
warn_user("NoMemory", 0);
 
}
 
LOG(("record time"));
/* Record time */
bw->last_action = wallclock();
LOG(("That's fine"));
}
 
 
 
/**
* Callback for fetchcache() for browser window favicon fetches.
*/
 
static nserror browser_window_favicon_callback(hlcache_handle *c,
const hlcache_event *event, void *pw)
{
struct browser_window *bw = pw;
 
switch (event->type) {
case CONTENT_MSG_DONE:
if (bw->current_favicon != NULL) {
content_status status =
content_get_status(bw->current_favicon);
 
if ((status == CONTENT_STATUS_READY) ||
(status == CONTENT_STATUS_DONE))
content_close(bw->current_favicon);
 
hlcache_handle_release(bw->current_favicon);
}
 
bw->current_favicon = c;
bw->loading_favicon = NULL;
 
/* content_get_bitmap on the hlcache_handle should give
* us the favicon bitmap at this point
*/
gui_window_set_icon(bw->window, c);
break;
 
case CONTENT_MSG_ERROR:
 
/* clean up after ourselves */
if (c == bw->loading_favicon)
bw->loading_favicon = NULL;
else if (c == bw->current_favicon) {
bw->current_favicon = NULL;
}
 
hlcache_handle_release(c);
 
if (bw->failed_favicon == false) {
nsurl *nsref = NULL;
nsurl *nsurl;
nserror error;
 
bw->failed_favicon = true;
 
error = nsurl_create("resource:favicon.ico", &nsurl);
if (error != NSERROR_OK) {
LOG(("Unable to create default location url"));
} else {
 
hlcache_handle_retrieve(nsurl,
HLCACHE_RETRIEVE_SNIFF_TYPE,
nsref, NULL,
browser_window_favicon_callback,
bw, NULL, CONTENT_IMAGE,
&bw->loading_favicon);
 
nsurl_unref(nsurl);
}
 
}
break;
 
default:
break;
}
return NSERROR_OK;
}
 
static void browser_window_update_favicon(hlcache_handle *c,
struct browser_window *bw, struct content_rfc5988_link *link)
{
lwc_string *icon_str;
nsurl *nsref = NULL;
nsurl *nsurl;
nserror error;
 
assert(c != NULL);
assert(bw !=NULL);
 
if (bw->window == NULL)
/* Not top-level browser window; not interested */
return;
/* already fetching the favicon - use that */
if (bw->loading_favicon != NULL)
return;
 
bw->failed_favicon = false;
 
if (link == NULL) {
/* look for favicon metadata link */
if (lwc_intern_string("icon", SLEN("icon"),
&icon_str) == lwc_error_ok) {
link = content_find_rfc5988_link(c, icon_str);
lwc_string_unref(icon_str);
}
}
 
if (link == NULL) {
if (lwc_intern_string("shortcut icon", SLEN("shortcut icon"),
&icon_str) == lwc_error_ok) {
link = content_find_rfc5988_link(c, icon_str);
lwc_string_unref(icon_str);
}
}
 
if (link == NULL) {
lwc_string *scheme;
bool speculative_default = false;
 
nsurl = hlcache_handle_get_url(c);
 
scheme = nsurl_get_component(nsurl, NSURL_SCHEME);
 
/* If the document was fetched over http(s), then speculate
* that there's a favicon living at /favicon.ico */
if ((lwc_string_length(scheme) == SLEN("HTTP") &&
strcasecmp(lwc_string_data(scheme),
"http") == 0) ||
(lwc_string_length(scheme) == SLEN("HTTPS") &&
strcasecmp(lwc_string_data(scheme),
"https") == 0)) {
speculative_default = true;
}
 
lwc_string_unref(scheme);
 
if (speculative_default) {
/* no favicon via link, try for the default location */
error = nsurl_join(nsurl, "/favicon.ico", &nsurl);
} else {
bw->failed_favicon = true;
error = nsurl_create("resource:favicon.ico", &nsurl);
}
if (error != NSERROR_OK) {
LOG(("Unable to create default location url"));
return;
}
} else {
nsurl = nsurl_ref(link->href);
}
 
if (link == NULL) {
LOG(("fetching general favicon from '%s'",
nsurl_access(nsurl)));
} else {
LOG(("fetching favicon rel:%s '%s'",
lwc_string_data(link->rel),
nsurl_access(nsurl)));
}
 
hlcache_handle_retrieve(nsurl, HLCACHE_RETRIEVE_SNIFF_TYPE,
nsref, NULL, browser_window_favicon_callback,
bw, NULL, CONTENT_IMAGE, &bw->loading_favicon);
 
nsurl_unref(nsurl);
}
 
/** window callback errorcode handling */
static void
browser_window_callback_errorcode(hlcache_handle *c,
struct browser_window *bw,
nserror code)
{
const char* message;
 
message = messages_get_errorcode(code);
 
browser_window_set_status(bw, message);
 
/* Only warn the user about errors in top-level windows */
if (bw->browser_window_type == BROWSER_WINDOW_NORMAL) {
warn_user(message, 0);
}
 
if (c == bw->loading_content) {
bw->loading_content = NULL;
} else if (c == bw->current_content) {
bw->current_content = NULL;
browser_window_remove_caret(bw);
}
 
hlcache_handle_release(c);
 
browser_window_stop_throbber(bw);
}
 
/**
* Callback for fetchcache() for browser window fetches.
*/
 
nserror browser_window_callback(hlcache_handle *c,
const hlcache_event *event, void *pw)
{
struct browser_window *bw = pw;
 
switch (event->type) {
case CONTENT_MSG_DOWNLOAD:
assert(bw->loading_content == c);
 
browser_window_convert_to_download(bw, event->data.download);
 
if (bw->current_content != NULL) {
browser_window_refresh_url_bar(bw,
hlcache_handle_get_url(bw->current_content),
bw->frag_id);
}
break;
 
case CONTENT_MSG_LOADING:
assert(bw->loading_content == c);
 
#ifdef WITH_THEME_INSTALL
if (content_get_type(c) == CONTENT_THEME) {
theme_install_start(c);
bw->loading_content = NULL;
browser_window_stop_throbber(bw);
} else
#endif
{
bw->refresh_interval = -1;
browser_window_set_status(bw,
content_get_status_message(c));
}
break;
 
case CONTENT_MSG_READY:
{
int width, height;
 
assert(bw->loading_content == c);
 
if (bw->current_content != NULL) {
content_status status =
content_get_status(bw->current_content);
 
if (status == CONTENT_STATUS_READY ||
status == CONTENT_STATUS_DONE)
content_close(bw->current_content);
 
hlcache_handle_release(bw->current_content);
}
 
bw->current_content = c;
bw->loading_content = NULL;
 
/* Format the new content to the correct dimensions */
browser_window_get_dimensions(bw, &width, &height, true);
content_reformat(c, false, width, height);
 
browser_window_remove_caret(bw);
 
if (bw->window)
gui_window_new_content(bw->window);
 
browser_window_refresh_url_bar(bw,
hlcache_handle_get_url(bw->current_content),
bw->frag_id);
 
/* new content; set scroll_to_top */
browser_window_update(bw, true);
content_open(c, bw, 0, 0);
browser_window_set_status(bw, content_get_status_message(c));
 
/* history */
if (bw->history_add && bw->history) {
nsurl *url = hlcache_handle_get_url(c);
 
history_add(bw->history, c, bw->frag_id == NULL ? NULL :
lwc_string_data(bw->frag_id));
if (urldb_add_url(url)) {
urldb_set_url_title(url, content_get_title(c));
urldb_update_url_visit_data(url);
urldb_set_url_content_type(url,
content_get_type(c));
/* This is safe as we've just added the URL */
global_history_add(urldb_get_url(url));
}
}
 
if (bw->window != NULL) {
browser_window_set_selection(bw,
content_get_selection(c));
}
 
/* frames */
if (content_get_type(c) == CONTENT_HTML &&
html_get_frameset(c) != NULL)
browser_window_create_frameset(bw,
html_get_frameset(c));
if (content_get_type(c) == CONTENT_HTML &&
html_get_iframe(c) != NULL)
browser_window_create_iframes(bw, html_get_iframe(c));
}
break;
 
case CONTENT_MSG_DONE:
assert(bw->current_content == c);
 
if (bw->window == NULL) {
/* Updated browser window's scrollbars.
* TODO: do this before CONTENT_MSG_DONE */
browser_window_reformat(bw, true,
bw->width, bw->height);
browser_window_handle_scrollbars(bw);
}
 
browser_window_update(bw, false);
browser_window_set_status(bw, content_get_status_message(c));
browser_window_stop_throbber(bw);
browser_window_update_favicon(c, bw, NULL);
 
history_update(bw->history, c);
hotlist_visited(c);
 
if (bw->refresh_interval != -1)
schedule(bw->refresh_interval,
browser_window_refresh, bw);
break;
 
case CONTENT_MSG_ERRORCODE:
browser_window_callback_errorcode(c, bw, event->data.errorcode);
break;
 
case CONTENT_MSG_ERROR:
browser_window_set_status(bw, event->data.error);
 
/* Only warn the user about errors in top-level windows */
if (bw->browser_window_type == BROWSER_WINDOW_NORMAL)
warn_user(event->data.error, 0);
 
if (c == bw->loading_content)
bw->loading_content = NULL;
else if (c == bw->current_content) {
bw->current_content = NULL;
browser_window_remove_caret(bw);
}
 
hlcache_handle_release(c);
 
browser_window_stop_throbber(bw);
break;
 
case CONTENT_MSG_STATUS:
if (event->data.explicit_status_text == NULL) {
/* Object content's status text updated */
const char *status = NULL;
if (bw->loading_content != NULL)
/* Give preference to any loading content */
status = content_get_status_message(
bw->loading_content);
 
if (status == NULL)
status = content_get_status_message(c);
 
if (status != NULL)
browser_window_set_status(bw, status);
} else {
/* Object content wants to set explicit message */
browser_window_set_status(bw,
event->data.explicit_status_text);
}
break;
 
case CONTENT_MSG_REFORMAT:
if (c == bw->current_content &&
content_get_type(c) == CONTENT_HTML) {
/* reposition frames */
if (html_get_frameset(c) != NULL)
browser_window_recalculate_frameset(bw);
/* reflow iframe positions */
if (html_get_iframe(c) != NULL)
browser_window_recalculate_iframes(bw);
}
 
if (bw->move_callback)
bw->move_callback(bw, bw->caret_p1, bw->caret_p2);
 
if (!(event->data.background)) {
/* Reformatted content should be redrawn */
browser_window_update(bw, false);
}
break;
 
case CONTENT_MSG_REDRAW:
{
struct rect rect = {
.x0 = event->data.redraw.x,
.y0 = event->data.redraw.y,
.x1 = event->data.redraw.x + event->data.redraw.width,
.y1 = event->data.redraw.y + event->data.redraw.height
};
 
browser_window_update_box(bw, &rect);
}
break;
 
case CONTENT_MSG_REFRESH:
bw->refresh_interval = event->data.delay * 100;
break;
case CONTENT_MSG_LINK: /* content has an rfc5988 link element */
{
lwc_string *icon_str;
lwc_string *shortcut_icon_str;
bool icon_match = false;
bool shortcut_icon_match = false;
 
if (lwc_intern_string("icon", SLEN("icon"),
&icon_str) == lwc_error_ok) {
if (lwc_string_caseless_isequal(
event->data.rfc5988_link->rel,
icon_str, &icon_match) != lwc_error_ok) {
icon_match = false;
}
lwc_string_unref(icon_str);
}
 
if (lwc_intern_string("shortcut icon", SLEN("shortcut icon"),
&shortcut_icon_str) == lwc_error_ok) {
if (lwc_string_caseless_isequal(
event->data.rfc5988_link->rel,
shortcut_icon_str,
&shortcut_icon_match) != lwc_error_ok) {
shortcut_icon_match = false;
}
lwc_string_unref(shortcut_icon_str);
}
 
if (icon_match || shortcut_icon_match) {
/* it's a favicon perhaps start a fetch for it */
browser_window_update_favicon(c, bw,
event->data.rfc5988_link);
}
}
break;
 
case CONTENT_MSG_GETCTX:
/* only the content object created by the browser
* window requires a new global compartment object
*/
assert(bw->loading_content == c);
if (js_newcompartment(bw->jsctx,
bw,
hlcache_handle_get_content(c)) != NULL) {
*(event->data.jscontext) = bw->jsctx;
}
break;
 
case CONTENT_MSG_SCROLL:
/* Content wants to be scrolled */
if (bw->current_content != c)
break;
 
if (event->data.scroll.area) {
struct rect rect = {
.x0 = event->data.scroll.x0,
.y0 = event->data.scroll.y0,
.x1 = event->data.scroll.x1,
.y1 = event->data.scroll.y1
};
browser_window_scroll_visible(bw, &rect);
} else {
browser_window_set_scroll(bw,
event->data.scroll.x0,
event->data.scroll.y0);
}
 
break;
 
case CONTENT_MSG_DRAGSAVE:
{
/* Content wants drag save of a content */
struct browser_window *root = browser_window_get_root(bw);
hlcache_handle *save = event->data.dragsave.content;
 
if (save == NULL) {
save = c;
}
 
switch(event->data.dragsave.type) {
case CONTENT_SAVE_ORIG:
gui_drag_save_object(GUI_SAVE_OBJECT_ORIG, save,
root->window);
break;
case CONTENT_SAVE_NATIVE:
gui_drag_save_object(GUI_SAVE_OBJECT_NATIVE, save,
root->window);
break;
case CONTENT_SAVE_COMPLETE:
gui_drag_save_object(GUI_SAVE_COMPLETE, save,
root->window);
break;
case CONTENT_SAVE_SOURCE:
gui_drag_save_object(GUI_SAVE_SOURCE, save,
root->window);
break;
}
}
break;
 
case CONTENT_MSG_SAVELINK:
{
/* Content wants a link to be saved */
struct browser_window *root = browser_window_get_root(bw);
gui_window_save_link(root->window,
event->data.savelink.url,
event->data.savelink.title);
}
break;
 
case CONTENT_MSG_POINTER:
/* Content wants to have specific mouse pointer */
browser_window_set_pointer(bw, event->data.pointer);
break;
 
default:
assert(0);
}
 
return NSERROR_OK;
}
 
 
/*
* Get the dimensions of the area a browser window occupies
*
* \param bw The browser window to get dimensions of
* \param width Updated to the browser window viewport width
* \param height Updated to the browser window viewport height
* \param scaled Whether we want the height with scale applied
*/
 
void browser_window_get_dimensions(struct browser_window *bw,
int *width, int *height, bool scaled)
{
assert(bw);
 
if (bw->window == NULL) {
/* Core managed browser window */
*width = bw->width;
*height = bw->height;
} else {
/* Front end window */
gui_window_get_dimensions(bw->window, width, height, scaled);
}
}
 
 
/*
* Set the dimensions of the area a browser window occupies
*
* \param bw The browser window to set dimensions of
* \param width Width in pixels
* \param height Height in pixels
*/
 
void browser_window_set_dimensions(struct browser_window *bw,
int width, int height)
{
assert(bw);
 
if (bw->window == NULL) {
/* Core managed browser window */
bw->width = width;
bw->height = height;
} else {
LOG(("Asked to set dimensions of front end window."));
assert(0);
}
}
 
 
/**
* Transfer the loading_content to a new download window.
*/
 
void browser_window_convert_to_download(struct browser_window *bw,
llcache_handle *stream)
{
struct browser_window *root = browser_window_get_root(bw);
nserror error;
 
assert(root != NULL);
 
error = download_context_create(stream, root->window);
if (error != NSERROR_OK) {
llcache_handle_abort(stream);
llcache_handle_release(stream);
}
 
/* remove content from browser window */
hlcache_handle_release(bw->loading_content);
bw->loading_content = NULL;
 
browser_window_stop_throbber(bw);
}
 
 
/**
* Handle meta http-equiv refresh time elapsing by loading a new page.
*
* \param p browser window to refresh with new page
*/
 
void browser_window_refresh(void *p)
{
struct browser_window *bw = p;
bool history_add = true;
const char *url;
const char *refresh;
 
assert(bw->current_content != NULL &&
(content_get_status(bw->current_content) ==
CONTENT_STATUS_READY ||
content_get_status(bw->current_content) ==
CONTENT_STATUS_DONE));
 
/* Ignore if the refresh URL has gone
* (may happen if a fetch error occurred) */
refresh = nsurl_access(content_get_refresh_url(bw->current_content));
if (refresh == NULL)
return;
 
/* mark this content as invalid so it gets flushed from the cache */
content_invalidate_reuse_data(bw->current_content);
 
url = nsurl_access(hlcache_handle_get_url(bw->current_content));
if (url != NULL && strcmp(url, refresh) == 0)
history_add = false;
 
/* Treat an (almost) immediate refresh in a top-level browser window as
* if it were an HTTP redirect, and thus make the resulting fetch
* verifiable.
*
* See fetchcache.c for why redirected fetches should be verifiable at
* all.
*/
if (bw->refresh_interval <= 100 && bw->parent == NULL) {
browser_window_go(bw, refresh, url, history_add);
} else {
browser_window_go_unverifiable(bw, refresh, url, history_add,
bw->current_content);
}
}
 
 
/**
* Start the busy indicator.
*
* \param bw browser window
*/
 
void browser_window_start_throbber(struct browser_window *bw)
{
bw->throbbing = true;
 
while (bw->parent)
bw = bw->parent;
 
gui_window_start_throbber(bw->window);
}
 
 
/**
* Stop the busy indicator.
*
* \param bw browser window
*/
 
void browser_window_stop_throbber(struct browser_window *bw)
{
bw->throbbing = false;
 
while (bw->parent)
bw = bw->parent;
 
if (!browser_window_check_throbber(bw))
gui_window_stop_throbber(bw->window);
}
 
bool browser_window_check_throbber(struct browser_window *bw)
{
int children, index;
 
if (bw->throbbing)
return true;
 
if (bw->children) {
children = bw->rows * bw->cols;
for (index = 0; index < children; index++) {
if (browser_window_check_throbber(&bw->children[index]))
return true;
}
}
if (bw->iframes) {
for (index = 0; index < bw->iframe_count; index++) {
if (browser_window_check_throbber(&bw->iframes[index]))
return true;
}
}
return false;
}
 
/**
* Redraw browser window, set extent to content, and update title.
*
* \param bw browser_window
* \param scroll_to_top move view to top of page
*/
 
void browser_window_update(struct browser_window *bw, bool scroll_to_top)
{
int x, y;
 
if (bw->current_content == NULL)
return;
 
switch (bw->browser_window_type) {
 
case BROWSER_WINDOW_NORMAL:
/* Root browser window, constituting a front end window/tab */
gui_window_set_title(bw->window,
content_get_title(bw->current_content));
 
browser_window_update_extent(bw);
 
if (scroll_to_top)
browser_window_set_scroll(bw, 0, 0);
 
/* if frag_id exists, then try to scroll to it */
/** @todo don't do this if the user has scrolled */
if (bw->frag_id && html_get_id_offset(bw->current_content,
bw->frag_id, &x, &y)) {
browser_window_set_scroll(bw, x, y);
}
 
gui_window_redraw_window(bw->window);
 
break;
 
case BROWSER_WINDOW_IFRAME:
/* Internal iframe browser window */
assert(bw->parent != NULL);
assert(bw->parent->current_content != NULL);
 
browser_window_update_extent(bw);
 
if (scroll_to_top)
browser_window_set_scroll(bw, 0, 0);
 
/* if frag_id exists, then try to scroll to it */
/** @todo don't do this if the user has scrolled */
if (bw->frag_id && html_get_id_offset(bw->current_content,
bw->frag_id, &x, &y)) {
browser_window_set_scroll(bw, x, y);
}
 
html_redraw_a_box(bw->parent->current_content, bw->box);
break;
 
case BROWSER_WINDOW_FRAME:
{
struct rect rect;
browser_window_update_extent(bw);
 
if (scroll_to_top)
browser_window_set_scroll(bw, 0, 0);
 
/* if frag_id exists, then try to scroll to it */
/** @todo don't do this if the user has scrolled */
if (bw->frag_id && html_get_id_offset(bw->current_content,
bw->frag_id, &x, &y)) {
browser_window_set_scroll(bw, x, y);
}
 
rect.x0 = scrollbar_get_offset(bw->scroll_x);
rect.y0 = scrollbar_get_offset(bw->scroll_y);
rect.x1 = rect.x0 + bw->width;
rect.y1 = rect.y0 + bw->height;
 
browser_window_update_box(bw, &rect);
}
break;
 
default:
case BROWSER_WINDOW_FRAMESET:
/* Nothing to do */
break;
}
}
 
 
void browser_window_update_box(struct browser_window *bw, struct rect *rect)
{
int pos_x;
int pos_y;
struct browser_window *top;
 
assert(bw);
 
if (bw->window != NULL) {
/* Front end window */
gui_window_update_box(bw->window, rect);
} else {
/* Core managed browser window */
browser_window_get_position(bw, true, &pos_x, &pos_y);
 
top = browser_window_get_root(bw);
 
rect->x0 += pos_x / bw->scale;
rect->y0 += pos_y / bw->scale;
rect->x1 += pos_x / bw->scale;
rect->y1 += pos_y / bw->scale;
 
gui_window_update_box(top->window, rect);
}
}
 
 
/**
* Stop all fetching activity in a browser window.
*
* \param bw browser window
*/
 
void browser_window_stop(struct browser_window *bw)
{
int children, index;
 
if (bw->loading_content != NULL) {
hlcache_handle_abort(bw->loading_content);
hlcache_handle_release(bw->loading_content);
bw->loading_content = NULL;
}
 
if (bw->current_content != NULL && content_get_status(
bw->current_content) != CONTENT_STATUS_DONE) {
nserror error;
assert(content_get_status(bw->current_content) ==
CONTENT_STATUS_READY);
error = hlcache_handle_abort(bw->current_content);
assert(error == NSERROR_OK);
}
 
schedule_remove(browser_window_refresh, bw);
 
if (bw->children) {
children = bw->rows * bw->cols;
for (index = 0; index < children; index++)
browser_window_stop(&bw->children[index]);
}
if (bw->iframes) {
children = bw->iframe_count;
for (index = 0; index < children; index++)
browser_window_stop(&bw->iframes[index]);
}
 
if (bw->current_content != NULL) {
browser_window_refresh_url_bar(bw,
hlcache_handle_get_url(bw->current_content),
bw->frag_id);
}
 
browser_window_stop_throbber(bw);
}
 
 
/**
* Reload the page in a browser window.
*
* \param bw browser window
* \param all whether to reload all objects associated with the page
*/
 
void browser_window_reload(struct browser_window *bw, bool all)
{
hlcache_handle *c;
unsigned int i;
 
if (bw->current_content == NULL || bw->loading_content != NULL)
return;
 
if (all && content_get_type(bw->current_content) == CONTENT_HTML) {
struct html_stylesheet *sheets;
struct content_html_object *object;
unsigned int count;
 
c = bw->current_content;
 
/* invalidate objects */
object = html_get_objects(c, &count);
 
for (; object != NULL; object = object->next) {
if (object->content != NULL)
content_invalidate_reuse_data(object->content);
}
 
/* invalidate stylesheets */
sheets = html_get_stylesheets(c, &count);
 
for (i = STYLESHEET_START; i != count; i++) {
if (sheets[i].type == HTML_STYLESHEET_EXTERNAL &&
sheets[i].data.external != NULL) {
content_invalidate_reuse_data(
sheets[i].data.external);
}
}
}
 
content_invalidate_reuse_data(bw->current_content);
 
browser_window_go(bw, nsurl_access(
hlcache_handle_get_url(bw->current_content)), 0, false);
}
 
 
/**
* Change the status bar of a browser window.
*
* \param bw browser window
* \param text new status text (copied)
*/
 
void browser_window_set_status(struct browser_window *bw, const char *text)
{
int text_len;
/* find topmost window */
while (bw->parent)
bw = bw->parent;
 
if ((bw->status_text != NULL) &&
(strcmp(text, bw->status_text) == 0)) {
/* status text is unchanged */
bw->status_match++;
return;
}
 
/* status text is changed */
text_len = strlen(text);
 
if ((bw->status_text == NULL) || (bw->status_text_len < text_len)) {
/* no current string allocation or it is not long enough */
free(bw->status_text);
bw->status_text = strdup(text);
bw->status_text_len = text_len;
} else {
/* current allocation has enough space */
memcpy(bw->status_text, text, text_len + 1);
}
 
bw->status_miss++;
gui_window_set_status(bw->window, bw->status_text);
}
 
 
/**
* Change the shape of the mouse pointer
*
* \param bw Browser window to set shape in
* \param shape The pointer shape to use
*/
 
void browser_window_set_pointer(struct browser_window *bw,
browser_pointer_shape shape)
{
struct browser_window *root = browser_window_get_root(bw);
gui_pointer_shape gui_shape;
bool loading;
 
assert(root);
assert(root->window);
 
loading = (bw->loading_content != NULL || (bw->current_content &&
content_get_status(bw->current_content) ==
CONTENT_STATUS_READY));
 
if (wallclock() - bw->last_action < 100 && loading) {
/* If loading and less than 1 second since last link followed,
* force progress indicator pointer */
gui_shape = GUI_POINTER_PROGRESS;
 
} else if (shape == BROWSER_POINTER_AUTO) {
/* Up to browser window to decide */
if (loading)
gui_shape = GUI_POINTER_PROGRESS;
else
gui_shape = GUI_POINTER_DEFAULT;
 
} else {
/* Use what we were told */
gui_shape = (gui_pointer_shape)shape;
}
 
gui_window_set_pointer(root->window, gui_shape);
}
 
 
/**
* Close and destroy a browser window.
*
* \param bw browser window
*/
 
void browser_window_destroy(struct browser_window *bw)
{
/* can't destoy child windows on their own */
assert(!bw->parent);
 
/* destroy */
browser_window_destroy_internal(bw);
free(bw);
}
 
 
/**
* Close and destroy all child browser window.
*
* \param bw browser window
*/
 
void browser_window_destroy_children(struct browser_window *bw)
{
int i;
 
if (bw->children) {
for (i = 0; i < (bw->rows * bw->cols); i++)
browser_window_destroy_internal(&bw->children[i]);
free(bw->children);
bw->children = NULL;
bw->rows = 0;
bw->cols = 0;
}
if (bw->iframes) {
for (i = 0; i < bw->iframe_count; i++)
browser_window_destroy_internal(&bw->iframes[i]);
free(bw->iframes);
bw->iframes = NULL;
bw->iframe_count = 0;
}
}
 
 
/**
* Release all memory associated with a browser window.
*
* \param bw browser window
*/
 
void browser_window_destroy_internal(struct browser_window *bw)
{
assert(bw);
 
LOG(("Destroying window"));
 
if (bw->children != NULL || bw->iframes != NULL)
browser_window_destroy_children(bw);
 
schedule_remove(browser_window_refresh, bw);
 
/* If this brower window is not the root window, and has focus, unset
* the root browser window's focus pointer. */
if (!bw->window) {
struct browser_window *top = browser_window_get_root(bw);
 
if (top->focus == bw)
top->focus = top;
 
if (bw->current_content != NULL &&
top->cur_sel == content_get_selection(
bw->current_content)) {
browser_window_set_selection(top, NULL);
}
}
 
/* Destroying a search context causes it to redraw any deselected,
* content areas, so do this first */
browser_window_search_destroy_context(bw);
 
/* Destruction order is important: we must ensure that the frontend
* destroys any window(s) associated with this browser window before
* we attempt any destructive cleanup.
*/
 
if (bw->window) {
/* Only the root window has a GUI window */
gui_window_destroy(bw->window);
}
 
if (bw->loading_content != NULL) {
hlcache_handle_abort(bw->loading_content);
hlcache_handle_release(bw->loading_content);
bw->loading_content = NULL;
}
 
if (bw->current_content != NULL) {
content_status status = content_get_status(bw->current_content);
if (status == CONTENT_STATUS_READY ||
status == CONTENT_STATUS_DONE)
content_close(bw->current_content);
 
hlcache_handle_release(bw->current_content);
bw->current_content = NULL;
}
 
if (bw->loading_favicon != NULL) {
hlcache_handle_abort(bw->loading_favicon);
hlcache_handle_release(bw->loading_favicon);
bw->loading_favicon = NULL;
}
 
if (bw->current_favicon != NULL) {
content_status status = content_get_status(bw->current_favicon);
 
if (status == CONTENT_STATUS_READY ||
status == CONTENT_STATUS_DONE)
content_close(bw->current_favicon);
 
hlcache_handle_release(bw->current_favicon);
bw->current_favicon = NULL;
}
 
if (bw->box != NULL) {
bw->box->iframe = NULL;
bw->box = NULL;
}
 
if (bw->jsctx != NULL) {
js_destroycontext(bw->jsctx);
}
 
/* These simply free memory, so are safe here */
 
if (bw->frag_id != NULL)
lwc_string_unref(bw->frag_id);
 
history_destroy(bw->history);
 
free(bw->name);
free(bw->status_text);
bw->status_text = NULL;
LOG(("Status text cache match:miss %d:%d",
bw->status_match, bw->status_miss));
}
 
 
/**
* Reformat a browser window contents to a new width or height.
*
* \param bw the browser window to reformat
* \param width new width
* \param height new height
*/
 
void browser_window_reformat(struct browser_window *bw, bool background,
int width, int height)
{
hlcache_handle *c = bw->current_content;
 
if (c == NULL)
return;
 
if (bw->browser_window_type != BROWSER_WINDOW_IFRAME) {
/* Iframe dimensions are already scaled in parent's layout */
width /= bw->scale;
height /= bw->scale;
}
 
if (bw->window == NULL) {
/* Core managed browser window; subtract scrollbar width */
width -= bw->scroll_y ? SCROLLBAR_WIDTH : 0;
height -= bw->scroll_x ? SCROLLBAR_WIDTH : 0;
 
width = width > 0 ? width : 0;
height = height > 0 ? height : 0;
}
 
content_reformat(c, background, width, height);
}
 
 
/**
* Sets the scale of a browser window
*
* \param bw The browser window to scale
* \param scale The new scale
* \param all Scale all windows in the tree (ie work up aswell as down)
*/
 
void browser_window_set_scale(struct browser_window *bw, float scale, bool all)
{
while (bw->parent && all)
bw = bw->parent;
 
browser_window_set_scale_internal(bw, scale);
 
if (bw->parent)
bw = bw->parent;
 
browser_window_recalculate_frameset(bw);
}
 
void browser_window_set_scale_internal(struct browser_window *bw, float scale)
{
int i;
hlcache_handle *c;
 
if (fabs(bw->scale-scale) < 0.0001)
return;
 
bw->scale = scale;
c = bw->current_content;
 
if (c != NULL) {
if (content_can_reformat(c) == false) {
browser_window_update(bw, false);
} else {
bw->reformat_pending = true;
browser_reformat_pending = true;
}
}
 
for (i = 0; i < (bw->cols * bw->rows); i++)
browser_window_set_scale_internal(&bw->children[i], scale);
for (i = 0; i < bw->iframe_count; i++)
browser_window_set_scale_internal(&bw->iframes[i], scale);
}
 
 
/**
* Gets the scale of a browser window
*
* \param bw The browser window to scale
* \return
*/
 
float browser_window_get_scale(struct browser_window *bw)
{
return bw->scale;
}
 
 
/**
* Update URL bar for a given browser window to given URL
*
* \param bw Browser window to update URL bar for.
* \param url URL for content displayed by bw, excluding any fragment.
* \param frag Additional fragment. May be NULL if none.
*/
 
void browser_window_refresh_url_bar(struct browser_window *bw, nsurl *url,
lwc_string *frag)
{
assert(bw);
assert(url);
 
if (bw->parent != NULL) {
/* Not root window; don't set a URL in GUI URL bar */
return;
}
 
if (frag == NULL) {
/* With no fragment, we may as well pass url straight through
* saving a malloc, copy, free cycle.
*/
gui_window_set_url(bw->window, nsurl_access(url));
} else {
nsurl *display_url;
nserror error;
 
error = nsurl_refragment(url, frag, &display_url);
if (error != NSERROR_OK) {
warn_user("NoMemory", 0);
return;
}
 
gui_window_set_url(bw->window, nsurl_access(display_url));
nsurl_unref(display_url);
}
}
 
/**
* Locate a browser window in the specified stack according.
*
* \param bw the browser_window to search all relatives of
* \param target the target to locate
* \param mouse The current mouse state
* \return The browser window the mouse is in
*/
 
struct browser_window *browser_window_find_target(struct browser_window *bw,
const char *target, browser_mouse_state mouse)
{
struct browser_window *bw_target;
struct browser_window *top;
hlcache_handle *c;
int rdepth;
 
/* use the base target if we don't have one */
c = bw->current_content;
if (target == NULL && c != NULL && content_get_type(c) == CONTENT_HTML)
target = html_get_base_target(c);
if (target == NULL)
target = TARGET_SELF;
 
/* allow the simple case of target="_blank" to be ignored if requested
*/
if ((!(mouse & BROWSER_MOUSE_CLICK_2)) &&
(!((mouse & BROWSER_MOUSE_CLICK_2) &&
(mouse & BROWSER_MOUSE_MOD_2))) &&
(!nsoption_bool(target_blank))) {
/* not a mouse button 2 click
* not a mouse button 1 click with ctrl pressed
* configured to ignore target="_blank" */
if ((target == TARGET_BLANK) || (!strcasecmp(target, "_blank")))
return bw;
}
 
/* handle reserved keywords */
if (((nsoption_bool(button_2_tab)) &&
(mouse & BROWSER_MOUSE_CLICK_2))||
((!nsoption_bool(button_2_tab)) &&
((mouse & BROWSER_MOUSE_CLICK_1) &&
(mouse & BROWSER_MOUSE_MOD_2))) ||
((nsoption_bool(button_2_tab)) &&
((target == TARGET_BLANK) ||
(!strcasecmp(target, "_blank"))))) {
/* open in new tab if:
* - button_2 opens in new tab and button_2 was pressed
* OR
* - button_2 doesn't open in new tabs and button_1 was
* pressed with ctrl held
* OR
* - button_2 opens in new tab and the link target is "_blank"
*/
bw_target = browser_window_create(NULL, bw, NULL, false, true);
if (!bw_target)
return bw;
return bw_target;
} else if (((!nsoption_bool(button_2_tab)) &&
(mouse & BROWSER_MOUSE_CLICK_2)) ||
((nsoption_bool(button_2_tab)) &&
((mouse & BROWSER_MOUSE_CLICK_1) &&
(mouse & BROWSER_MOUSE_MOD_2))) ||
((!nsoption_bool(button_2_tab)) &&
((target == TARGET_BLANK) ||
(!strcasecmp(target, "_blank"))))) {
/* open in new window if:
* - button_2 doesn't open in new tabs and button_2 was pressed
* OR
* - button_2 opens in new tab and button_1 was pressed with
* ctrl held
* OR
* - button_2 doesn't open in new tabs and the link target is
* "_blank"
*/
bw_target = browser_window_create(NULL, bw, NULL, false, false);
if (!bw_target)
return bw;
return bw_target;
} else if ((target == TARGET_SELF) || (!strcasecmp(target, "_self"))) {
return bw;
} else if ((target == TARGET_PARENT) ||
(!strcasecmp(target, "_parent"))) {
if (bw->parent)
return bw->parent;
return bw;
} else if ((target == TARGET_TOP) || (!strcasecmp(target, "_top"))) {
while (bw->parent)
bw = bw->parent;
return bw;
}
 
/* find frame according to B.8, ie using the following priorities:
*
* 1) current frame
* 2) closest to front
*/
rdepth = -1;
bw_target = NULL;
for (top = bw; top->parent; top = top->parent);
browser_window_find_target_internal(top, target, 0, bw, &rdepth,
&bw_target);
if (bw_target)
return bw_target;
 
/* we require a new window using the target name */
if (!nsoption_bool(target_blank))
return bw;
 
bw_target = browser_window_create(NULL, bw, NULL, false, false);
if (!bw_target)
return bw;
 
/* frame names should begin with an alphabetic character (a-z,A-Z),
* however in practice you get things such as '_new' and '2left'. The
* only real effect this has is when giving out names as it can be
* assumed that an author intended '_new' to create a new nameless
* window (ie '_blank') whereas in the case of '2left' the intention
* was for a new named window. As such we merely special case windows
* that begin with an underscore. */
if (target[0] != '_') {
bw_target->name = strdup(target);
if (!bw_target->name)
warn_user("NoMemory", 0);
}
return bw_target;
}
 
void browser_window_find_target_internal(struct browser_window *bw,
const char *target, int depth, struct browser_window *page,
int *rdepth, struct browser_window **bw_target)
{
int i;
 
if ((bw->name) && (!strcasecmp(bw->name, target))) {
if ((bw == page) || (depth > *rdepth)) {
*rdepth = depth;
*bw_target = bw;
}
}
 
if ((!bw->children) && (!bw->iframes))
return;
 
depth++;
 
if (bw->children != NULL) {
for (i = 0; i < (bw->cols * bw->rows); i++) {
if ((bw->children[i].name) &&
(!strcasecmp(bw->children[i].name,
target))) {
if ((page == &bw->children[i]) ||
(depth > *rdepth)) {
*rdepth = depth;
*bw_target = &bw->children[i];
}
}
if (bw->children[i].children)
browser_window_find_target_internal(
&bw->children[i],
target, depth, page,
rdepth, bw_target);
}
}
 
if (bw->iframes != NULL) {
for (i = 0; i < bw->iframe_count; i++)
browser_window_find_target_internal(&bw->iframes[i],
target, depth, page, rdepth, bw_target);
}
}
 
 
/**
* Handle non-click mouse action in a browser window. (drag ends, movements)
*
* \param bw browser window
* \param mouse state of mouse buttons and modifier keys
* \param x coordinate of mouse
* \param y coordinate of mouse
*/
 
void browser_window_mouse_track(struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
hlcache_handle *c = bw->current_content;
const char *status = NULL;
browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT;
 
if (bw->window != NULL && bw->drag_window && bw != bw->drag_window) {
/* This is the root browser window and there's an active drag
* in a sub window.
* Pass the mouse action straight on to that bw. */
struct browser_window *drag_bw = bw->drag_window;
int off_x = 0;
int off_y = 0;
 
browser_window_get_position(drag_bw, true, &off_x, &off_y);
 
if (drag_bw->browser_window_type == BROWSER_WINDOW_FRAME) {
browser_window_mouse_track(drag_bw, mouse,
x - off_x, y - off_y);
 
} else if (drag_bw->browser_window_type ==
BROWSER_WINDOW_IFRAME) {
browser_window_mouse_track(drag_bw, mouse,
x - off_x / bw->scale,
y - off_y / bw->scale);
}
return;
}
 
if (bw->children) {
/* Browser window has children (frames) */
struct browser_window *child;
int cur_child;
int children = bw->rows * bw->cols;
 
for (cur_child = 0; cur_child < children; cur_child++) {
 
child = &bw->children[cur_child];
 
if (x < child->x || y < child->y ||
child->x + child->width < x ||
child->y + child->height < y) {
/* Click not in this child */
continue;
}
 
/* It's this child that contains the mouse; pass
* mouse action on to child */
browser_window_mouse_track(child, mouse,
x - child->x + scrollbar_get_offset(
child->scroll_x),
y - child->y + scrollbar_get_offset(
child->scroll_y));
 
/* Mouse action was for this child, we're done */
return;
}
 
/* Odd if we reached here, but nothing else can use the click
* when there are children. */
return;
}
 
if (c == NULL && bw->drag_type != DRAGGING_FRAME)
return;
 
if (bw->drag_type != DRAGGING_NONE && !mouse) {
browser_window_mouse_drag_end(bw, mouse, x, y);
}
 
/* Browser window's horizontal scrollbar */
if (bw->scroll_x != NULL && bw->drag_type != DRAGGING_SCR_Y) {
int scr_x, scr_y;
browser_window_get_scrollbar_pos(bw, true, &scr_x, &scr_y);
scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
 
if ((scr_x > 0 && scr_x < browser_window_get_scrollbar_len(bw,
true) &&
scr_y > 0 && scr_y < SCROLLBAR_WIDTH &&
bw->drag_type == DRAGGING_NONE) ||
bw->drag_type == DRAGGING_SCR_X) {
/* Start a scrollbar drag, or continue existing drag */
status = scrollbar_mouse_action(bw->scroll_x, mouse,
scr_x, scr_y);
pointer = BROWSER_POINTER_DEFAULT;
 
if (status != NULL)
browser_window_set_status(bw, status);
 
browser_window_set_pointer(bw, pointer);
return;
}
}
 
/* Browser window's vertical scrollbar */
if (bw->scroll_y != NULL) {
int scr_x, scr_y;
browser_window_get_scrollbar_pos(bw, false, &scr_x, &scr_y);
scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
 
if ((scr_y > 0 && scr_y < browser_window_get_scrollbar_len(bw,
false) &&
scr_x > 0 && scr_x < SCROLLBAR_WIDTH &&
bw->drag_type == DRAGGING_NONE) ||
bw->drag_type == DRAGGING_SCR_Y) {
/* Start a scrollbar drag, or continue existing drag */
status = scrollbar_mouse_action(bw->scroll_y, mouse,
scr_x, scr_y);
pointer = BROWSER_POINTER_DEFAULT;
 
if (status != NULL)
browser_window_set_status(bw, status);
 
browser_window_set_pointer(bw, pointer);
return;
}
}
 
if (bw->drag_type == DRAGGING_FRAME) {
browser_window_resize_frame(bw, bw->x + x, bw->y + y);
} else if (bw->drag_type == DRAGGING_PAGE_SCROLL) {
/* mouse movement since drag started */
int scrollx = bw->drag_start_x - x;
int scrolly = bw->drag_start_y - y;
 
/* new scroll offsets */
scrollx += bw->drag_start_scroll_x;
scrolly += bw->drag_start_scroll_y;
 
bw->drag_start_scroll_x = scrollx;
bw->drag_start_scroll_y = scrolly;
 
browser_window_set_scroll(bw, scrollx, scrolly);
} else {
assert(c != NULL);
content_mouse_track(c, bw, mouse, x, y);
}
}
 
 
/**
* Handle mouse clicks in a browser window.
*
* \param bw browser window
* \param mouse state of mouse buttons and modifier keys
* \param x coordinate of mouse
* \param y coordinate of mouse
*/
 
void browser_window_mouse_click(struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
hlcache_handle *c = bw->current_content;
const char *status = NULL;
browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT;
 
if (bw->children) {
/* Browser window has children (frames) */
struct browser_window *child;
int cur_child;
int children = bw->rows * bw->cols;
 
for (cur_child = 0; cur_child < children; cur_child++) {
 
child = &bw->children[cur_child];
 
if (x < child->x || y < child->y ||
child->x + child->width < x ||
child->y + child->height < y) {
/* Click not in this child */
continue;
}
 
/* It's this child that contains the click; pass it
* on to child. */
browser_window_mouse_click(child, mouse,
x - child->x + scrollbar_get_offset(
child->scroll_x),
y - child->y + scrollbar_get_offset(
child->scroll_y));
 
/* Mouse action was for this child, we're done */
return;
}
 
return;
}
 
if (!c)
return;
 
if (bw->scroll_x != NULL) {
int scr_x, scr_y;
browser_window_get_scrollbar_pos(bw, true, &scr_x, &scr_y);
scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
 
if (scr_x > 0 && scr_x < browser_window_get_scrollbar_len(bw,
true) &&
scr_y > 0 && scr_y < SCROLLBAR_WIDTH) {
status = scrollbar_mouse_action(bw->scroll_x, mouse,
scr_x, scr_y);
pointer = BROWSER_POINTER_DEFAULT;
 
if (status != NULL)
browser_window_set_status(bw, status);
 
browser_window_set_pointer(bw, pointer);
return;
}
}
 
if (bw->scroll_y != NULL) {
int scr_x, scr_y;
browser_window_get_scrollbar_pos(bw, false, &scr_x, &scr_y);
scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
 
if (scr_y > 0 && scr_y < browser_window_get_scrollbar_len(bw,
false) &&
scr_x > 0 && scr_x < SCROLLBAR_WIDTH) {
status = scrollbar_mouse_action(bw->scroll_y, mouse,
scr_x, scr_y);
pointer = BROWSER_POINTER_DEFAULT;
 
if (status != NULL)
browser_window_set_status(bw, status);
 
browser_window_set_pointer(bw, pointer);
return;
}
}
 
switch (content_get_type(c)) {
case CONTENT_HTML:
case CONTENT_TEXTPLAIN:
content_mouse_action(c, bw, mouse, x, y);
break;
default:
if (mouse & BROWSER_MOUSE_MOD_2) {
if (mouse & BROWSER_MOUSE_DRAG_2)
gui_drag_save_object(GUI_SAVE_OBJECT_NATIVE, c,
bw->window);
else if (mouse & BROWSER_MOUSE_DRAG_1)
gui_drag_save_object(GUI_SAVE_OBJECT_ORIG, c,
bw->window);
}
else if (mouse & (BROWSER_MOUSE_DRAG_1 |
BROWSER_MOUSE_DRAG_2)) {
browser_window_page_drag_start(bw, x, y);
browser_window_set_pointer(bw, BROWSER_POINTER_MOVE);
}
break;
}
}
 
 
/**
* Handles the end of a drag operation in a browser window.
*
* \param bw browser window
* \param mouse state of mouse buttons and modifier keys
* \param x coordinate of mouse
* \param y coordinate of mouse
*
* TODO: Remove this function, once these things are associated with content,
* rather than bw.
*/
 
void browser_window_mouse_drag_end(struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
int scr_x, scr_y;
 
switch (bw->drag_type) {
case DRAGGING_SELECTION:
case DRAGGING_OTHER:
case DRAGGING_CONTENT_SCROLLBAR:
/* Drag handled by content handler */
break;
 
case DRAGGING_SCR_X:
 
browser_window_get_scrollbar_pos(bw, true, &scr_x, &scr_y);
 
scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
 
scrollbar_mouse_drag_end(bw->scroll_x, mouse, scr_x, scr_y);
 
bw->drag_type = DRAGGING_NONE;
break;
 
case DRAGGING_SCR_Y:
 
browser_window_get_scrollbar_pos(bw, false, &scr_x, &scr_y);
 
scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
 
scrollbar_mouse_drag_end(bw->scroll_y, mouse, scr_x, scr_y);
 
bw->drag_type = DRAGGING_NONE;
break;
 
default:
browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);
break;
}
}
 
 
/**
* Redraw a rectangular region of a browser window
*
* \param bw browser window to be redrawn
* \param x x co-ord of top-left
* \param y y co-ord of top-left
* \param width width of rectangle
* \param height height of rectangle
*/
 
void browser_window_redraw_rect(struct browser_window *bw, int x, int y,
int width, int height)
{
content_request_redraw(bw->current_content, x, y, width, height);
}
 
 
/**
* Start drag scrolling the contents of the browser window
*
* \param bw browser window
* \param x x ordinate of initial mouse position
* \param y y ordinate
*/
 
void browser_window_page_drag_start(struct browser_window *bw, int x, int y)
{
browser_window_set_drag_type(bw, DRAGGING_PAGE_SCROLL, NULL);
 
bw->drag_start_x = x;
bw->drag_start_y = y;
 
if (bw->window != NULL) {
/* Front end window */
gui_window_get_scroll(bw->window, &bw->drag_start_scroll_x,
&bw->drag_start_scroll_y);
 
gui_window_scroll_start(bw->window);
} else {
/* Core managed browser window */
bw->drag_start_scroll_x = scrollbar_get_offset(bw->scroll_x);
bw->drag_start_scroll_y = scrollbar_get_offset(bw->scroll_y);
}
}
 
 
/**
* Check availability of Back action for a given browser window
*
* \param bw browser window
* \return true if Back action is available
*/
 
bool browser_window_back_available(struct browser_window *bw)
{
return (bw && bw->history && history_back_available(bw->history));
}
 
 
/**
* Check availability of Forward action for a given browser window
*
* \param bw browser window
* \return true if Forward action is available
*/
 
bool browser_window_forward_available(struct browser_window *bw)
{
return (bw && bw->history && history_forward_available(bw->history));
}
 
 
/**
* Check availability of Reload action for a given browser window
*
* \param bw browser window
* \return true if Reload action is available
*/
 
bool browser_window_reload_available(struct browser_window *bw)
{
return (bw && bw->current_content && !bw->loading_content);
}
 
 
/**
* Check availability of Stop action for a given browser window
*
* \param bw browser window
* \return true if Stop action is available
*/
 
bool browser_window_stop_available(struct browser_window *bw)
{
return (bw && (bw->loading_content ||
(bw->current_content &&
(content_get_status(bw->current_content) !=
CONTENT_STATUS_DONE))));
}
/programs/network/netsurf/netsurf/desktop/browser.h
0,0 → 1,334
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Browser window creation and manipulation (interface).
*/
 
#ifndef _NETSURF_DESKTOP_BROWSER_H_
#define _NETSURF_DESKTOP_BROWSER_H_
 
#include <stdbool.h>
 
#include "content/content.h"
#include "desktop/frame_types.h"
#include "desktop/gui.h"
#include "desktop/mouse.h"
#include "utils/types.h"
 
 
struct browser_window;
struct hlcache_handle;
struct gui_window;
struct history;
struct selection;
struct fetch_multipart_data;
 
typedef bool (*browser_caret_callback)(struct browser_window *bw, uint32_t key,
void *p1, void *p2);
typedef void (*browser_move_callback)(struct browser_window *bw,
void *p1, void *p2);
typedef bool (*browser_paste_callback)(struct browser_window *bw,
const char *utf8, unsigned utf8_len, bool last,
void *p1, void *p2);
 
 
typedef enum {
DRAGGING_NONE,
DRAGGING_SELECTION,
DRAGGING_PAGE_SCROLL,
DRAGGING_FRAME,
DRAGGING_SCR_X,
DRAGGING_SCR_Y,
DRAGGING_CONTENT_SCROLLBAR,
DRAGGING_OTHER
} browser_drag_type;
 
 
extern bool browser_reformat_pending;
 
struct browser_window * browser_window_create(const char *url,
struct browser_window *clone, const char *referrer,
bool history_add, bool new_tab);
void browser_window_initialise_common(struct browser_window *bw,
struct browser_window *clone);
void browser_window_go(struct browser_window *bw, const char *url,
const char *referrer, bool history_add);
void browser_window_go_post(struct browser_window *bw,
const char *url, char *post_urlenc,
struct fetch_multipart_data *post_multipart,
bool add_to_history, const char *referer, bool download,
bool verifiable, struct hlcache_handle *parent);
void browser_window_go_unverifiable(struct browser_window *bw,
const char *url, const char *referrer, bool history_add,
struct hlcache_handle *parent);
void browser_window_get_dimensions(struct browser_window *bw,
int *width, int *height, bool scaled);
void browser_window_set_dimensions(struct browser_window *bw,
int width, int height);
void browser_window_download(struct browser_window *bw,
const char *url, const char *referrer);
void browser_window_update(struct browser_window *bw, bool scroll_to_top);
void browser_window_update_box(struct browser_window *bw, struct rect *rect);
void browser_window_stop(struct browser_window *bw);
void browser_window_reload(struct browser_window *bw, bool all);
void browser_window_destroy(struct browser_window *bw);
void browser_window_reformat(struct browser_window *bw, bool background,
int width, int height);
void browser_window_set_scale(struct browser_window *bw, float scale, bool all);
float browser_window_get_scale(struct browser_window *bw);
 
/**
* Get access to any content, link URLs and objects (images) currently
* at the given (x, y) coordinates.
*
* \param bw browser window to look inside
* \param x x-coordinate of point of interest
* \param y y-coordinate of point of interest
* \param data pointer to contextual_content struct. Its fields are updated
* with pointers to any relevent content, or set to NULL if none.
*/
void browser_window_get_contextual_content(struct browser_window *bw,
int x, int y, struct contextual_content *data);
 
/**
* Send a scroll request to a browser window at a particular point. The
* 'deepest' scrollable object which can be scrolled in the requested
* direction at the given point will consume the scroll.
*
* \param bw browser window to look inside
* \param x x-coordinate of point of interest
* \param y y-coordinate of point of interest
* \param scrx number of px try to scroll something in x direction
* \param scry number of px try to scroll something in y direction
* \return true iff scroll request has been consumed
*/
bool browser_window_scroll_at_point(struct browser_window *bw,
int x, int y, int scrx, int scry);
 
/**
* Drop a file onto a browser window at a particular point, or determine if a
* file may be dropped onto the content at given point.
*
* \param bw browser window to look inside
* \param x x-coordinate of point of interest
* \param y y-coordinate of point of interest
* \param file path to file to be dropped, or NULL to know if drop allowed
* \return true iff file drop has been handled, or if drop possible (NULL file)
*/
bool browser_window_drop_file_at_point(struct browser_window *bw,
int x, int y, char *file);
 
void browser_window_refresh_url_bar(struct browser_window *bw, nsurl *url,
lwc_string *frag);
 
void browser_window_mouse_click(struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
void browser_window_mouse_track(struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
struct browser_window *browser_window_find_target(
struct browser_window *bw, const char *target,
browser_mouse_state mouse);
 
void browser_select_menu_callback(void *client_data,
int x, int y, int width, int height);
 
void browser_window_redraw_rect(struct browser_window *bw, int x, int y,
int width, int height);
 
void browser_window_set_status(struct browser_window *bw, const char *text);
void browser_window_set_pointer(struct browser_window *bw,
browser_pointer_shape shape);
void browser_window_page_drag_start(struct browser_window *bw, int x, int y);
 
bool browser_window_back_available(struct browser_window *bw);
bool browser_window_forward_available(struct browser_window *bw);
bool browser_window_reload_available(struct browser_window *bw);
bool browser_window_stop_available(struct browser_window *bw);
 
 
/* In desktop/textinput.c */
void browser_window_place_caret(struct browser_window *bw,
int x, int y, int height,
browser_caret_callback caret_cb,
browser_paste_callback paste_cb,
browser_move_callback move_cb,
void *p1, void *p2);
void browser_window_remove_caret(struct browser_window *bw);
bool browser_window_key_press(struct browser_window *bw, uint32_t key);
bool browser_window_paste_text(struct browser_window *bw, const char *utf8,
unsigned utf8_len, bool last);
 
 
/**
* Redraw an area of a window
*
* Calls the redraw function for the content,
*
* \param bw The window to redraw
* \param x coordinate for top-left of redraw
* \param y coordinate for top-left of redraw
* \param clip clip rectangle coordinates
* \param ctx redraw context
* \return true if successful, false otherwise
*
* The clip rectangle is guaranteed to be filled to its extents, so there is
* no need to render a solid background first.
*
* x, y and clip are coordinates from the top left of the canvas area.
*
* The top left corner of the clip rectangle is (x0, y0) and
* the bottom right corner of the clip rectangle is (x1, y1).
* Units for x, y and clip are pixels.
*/
bool browser_window_redraw(struct browser_window *bw, int x, int y,
const struct rect *clip, const struct redraw_context *ctx);
 
/**
* Check whether browser window is ready for redraw
*
* \param bw The window to redraw
* \return true if browser window is ready for redraw
*/
bool browser_window_redraw_ready(struct browser_window *bw);
 
/*
* Update the extent of the inside of a browser window to that of the current
* content
*
* \param bw browser_window to update the extent of
*/
void browser_window_update_extent(struct browser_window *bw);
 
/*
* Get the position of the current browser window with respect to the root or
* parent browser window
*
* \param bw browser window to get the position of
* \param root true if we want position wrt root bw, false if wrt parent bw
* \param pos_x updated to x position of bw
* \param pos_y updated to y position of bw
*/
void browser_window_get_position(struct browser_window *bw, bool root,
int *pos_x, int *pos_y);
 
/*
* Set the position of the current browser window with respect to the parent
* browser window
*
* \param bw browser window to set the position of
* \param x x position of bw
* \param y y position of bw
*/
void browser_window_set_position(struct browser_window *bw, int x, int y);
 
/*
* Scroll the browser window to display the passed area
*
* \param bw browser window to scroll
* \param rect area to display
*/
void browser_window_scroll_visible(struct browser_window *bw,
const struct rect *rect);
 
/**
* Set scroll offsets for a browser window.
*
* \param bw The browser window
* \param x The x scroll offset to set
* \param y The y scroll offset to set
*
* TODO -- Do we really need this and browser_window_scroll_visible?
* Ditto for gui_window_* variants.
*/
void browser_window_set_scroll(struct browser_window *bw, int x, int y);
 
/*
* Set drag type for a browser window, and inform front end
*
* \param bw browser window to set the type of the current drag for
* \param type drag type
* \param rect area pointer may be confined to, during drag, or NULL
*/
void browser_window_set_drag_type(struct browser_window *bw,
browser_drag_type type, const struct rect *rect);
 
/*
* Get type of any current drag for a browser window
*
* \param bw browser window to set the type of the current drag for
* \return drag type
*/
browser_drag_type browser_window_get_drag_type(struct browser_window *bw);
 
/*
* Get the root level browser window
*
* \param bw browser window to set the type of the current drag for
* \return root browser window
*/
struct browser_window * browser_window_get_root(struct browser_window *bw);
 
/**
* Check whether browser window contains a selection
*
* \param bw The browser window
* \return true if browser window contains a selection
*/
bool browser_window_has_selection(struct browser_window *bw);
 
/**
* Set pointer to current selection. Clears any existing selection.
*
* \param bw The browser window
* \param s The new selection
*/
void browser_window_set_selection(struct browser_window *bw,
struct selection *s);
 
/**
* Get the current selection context from a root browser window
*
* \param bw The browser window
* \return the selection context, or NULL
*/
struct selection *browser_window_get_selection(struct browser_window *bw);
 
 
/**
* Dump debug info concerning the browser window's contents to file
*
* \param bw The browser window
* \param f The file to dump to
*/
void browser_window_debug_dump(struct browser_window *bw, FILE *f);
 
 
/* In platform specific hotlist.c. */
void hotlist_visited(struct hlcache_handle *c);
 
/* In platform specific global_history.c. */
void global_history_add(nsurl *url);
 
/* In platform specific theme_install.c. */
#ifdef WITH_THEME_INSTALL
void theme_install_start(struct hlcache_handle *c);
#endif
 
#endif
/programs/network/netsurf/netsurf/desktop/browser_private.h
0,0 → 1,177
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Browser window private structure.
*/
 
#ifndef _NETSURF_DESKTOP_BROWSER_PRIVATE_H_
#define _NETSURF_DESKTOP_BROWSER_PRIVATE_H_
 
#include <stdbool.h>
 
#include "desktop/browser.h"
 
 
struct box;
struct hlcache_handle;
struct gui_window;
struct history;
struct selection;
 
/** Browser window data. */
struct browser_window {
/** Page currently displayed, or 0. Must have status READY or DONE. */
struct hlcache_handle *current_content;
/** Page being loaded, or 0. */
struct hlcache_handle *loading_content;
 
/** Page Favicon */
struct hlcache_handle *current_favicon;
/** handle for favicon which we started loading early */
struct hlcache_handle *loading_favicon;
/** favicon fetch already failed - prevents infinite error looping */
bool failed_favicon;
 
/** Window history structure. */
struct history *history;
 
/** Handler for keyboard input, or 0. */
browser_caret_callback caret_callback;
/** Handler for pasting text, or 0. */
browser_paste_callback paste_callback;
/** Handler for repositioning caret, or 0. */
browser_move_callback move_callback;
 
/** User parameters for caret_callback, paste_callback, and
* move_callback */
void *caret_p1;
void *caret_p2;
 
/** Platform specific window data. */
struct gui_window *window;
 
/** Busy indicator is active. */
bool throbbing;
/** Add loading_content to the window history when it loads. */
bool history_add;
 
/** Fragment identifier for current_content. */
lwc_string *frag_id;
 
/** Current drag status. */
browser_drag_type drag_type;
 
/** Current drag's browser window, when not in root bw. */
struct browser_window *drag_window;
 
/** Mouse position at start of current scroll drag. */
int drag_start_x;
int drag_start_y;
/** Scroll offsets at start of current scroll draw. */
int drag_start_scroll_x;
int drag_start_scroll_y;
/** Frame resize directions for current frame resize drag. */
unsigned int drag_resize_left : 1;
unsigned int drag_resize_right : 1;
unsigned int drag_resize_up : 1;
unsigned int drag_resize_down : 1;
 
/** Current fetch is download */
bool download;
 
/** Refresh interval (-1 if undefined) */
int refresh_interval;
 
/** Window has been resized, and content needs reformatting. */
bool reformat_pending;
 
/** Window dimensions */
int x;
int y;
int width;
int height;
 
struct scrollbar *scroll_x; /**< Horizontal scroll. */
struct scrollbar *scroll_y; /**< Vertical scroll. */
 
/** scale of window contents */
float scale;
 
/** Window characteristics */
enum {
BROWSER_WINDOW_NORMAL,
BROWSER_WINDOW_IFRAME,
BROWSER_WINDOW_FRAME,
BROWSER_WINDOW_FRAMESET,
} browser_window_type;
 
/** frameset characteristics */
int rows;
int cols;
 
/** frame dimensions */
struct frame_dimension frame_width;
struct frame_dimension frame_height;
int margin_width;
int margin_height;
 
/** frame name for targetting */
char *name;
 
/** frame characteristics */
bool no_resize;
frame_scrolling scrolling;
bool border;
colour border_colour;
 
/** iframe parent box */
struct box *box;
 
/** [cols * rows] children */
struct browser_window *children;
struct browser_window *parent;
 
/** [iframe_count] iframes */
int iframe_count;
struct browser_window *iframes;
 
/** browser window child of root browser window which has input focus */
struct browser_window *focus;
 
/** Last time a link was followed in this window */
unsigned int last_action;
 
/** Current selection, or NULL if none */
struct selection *cur_sel;
 
/** Current context for free text search, or NULL if none */
struct search_context *cur_search;
 
/** current javascript context */
struct jscontext *jsctx;
 
/** cache of the currently displayed status text. */
char *status_text; /**< Current status bar text. */
int status_text_len; /**< Length of the browser_window::status_text buffer. */
int status_match; /**< Number of times an idempotent status-set operation was performed. */
int status_miss; /**< Number of times status was really updated. */
};
 
#endif
/programs/network/netsurf/netsurf/desktop/cookies.c
0,0 → 1,543
/*
* Copyright 2006 Richard Wilson <info@tinct.net>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Cookies (implementation).
*/
 
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "content/content.h"
#include "content/hlcache.h"
#include "content/urldb.h"
#include "desktop/cookies.h"
#include "desktop/options.h"
#include "desktop/tree.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/schedule.h"
#include "utils/url.h"
#include "utils/utils.h"
 
/** Flags for each type of cookie tree node. */
enum tree_element_cookie {
TREE_ELEMENT_PERSISTENT = 0x01,
TREE_ELEMENT_VERSION = 0x02,
TREE_ELEMENT_SECURE = 0x03,
TREE_ELEMENT_LAST_USED = 0x04,
TREE_ELEMENT_EXPIRES = 0x05,
TREE_ELEMENT_PATH = 0x06,
TREE_ELEMENT_DOMAIN = 0x07,
TREE_ELEMENT_COMMENT = 0x08,
TREE_ELEMENT_VALUE = 0x09,
};
 
static struct tree *cookies_tree;
static struct node *cookies_tree_root;
static bool user_delete;
static hlcache_handle *folder_icon;
static hlcache_handle *cookie_icon;
 
 
/**
* Find an entry in the cookie tree
*
* \param node the node to check the children of
* \param title The title to find
* \return Pointer to node, or NULL if not found
*/
static struct node *cookies_find(struct node *node, const char *title)
{
struct node *search;
struct node_element *element;
 
assert(node !=NULL);
 
for (search = tree_node_get_child(node); search;
search = tree_node_get_next(search)) {
element = tree_node_find_element(search, TREE_ELEMENT_TITLE,
NULL);
if (strcmp(title, tree_node_element_get_text(element)) == 0)
return search;
}
return NULL;
}
 
/**
* Callback for all cookie tree nodes.
*/
static node_callback_resp cookies_node_callback(void *user_data, struct node_msg_data *msg_data)
{
struct node *node = msg_data->node;
struct node_element *domain, *path;
const char *domain_t, *path_t, *name_t;
char *space;
bool is_folder = tree_node_is_folder(node);
 
/* we don't remove any icons here */
if (msg_data->msg == NODE_DELETE_ELEMENT_IMG)
return NODE_CALLBACK_HANDLED;
 
/* let the tree handle events other than text data removal */
if (msg_data->msg != NODE_DELETE_ELEMENT_TXT)
return NODE_CALLBACK_NOT_HANDLED;
 
/* check if it's a domain folder */
if (is_folder)
return NODE_CALLBACK_NOT_HANDLED;
 
switch (msg_data->flag) {
case TREE_ELEMENT_TITLE:
if (!user_delete)
break;
/* get the rest of the cookie data */
domain = tree_node_find_element(node,
TREE_ELEMENT_DOMAIN, NULL);
path = tree_node_find_element(node, TREE_ELEMENT_PATH,
NULL);
 
if ((domain != NULL) &&
(path != NULL)) {
domain_t = tree_node_element_get_text(domain) +
strlen(messages_get(
"TreeDomain")) - 4;
space = strchr(domain_t, ' ');
if (space != NULL)
*space = '\0';
path_t = tree_node_element_get_text(path) +
strlen(messages_get("TreePath"))
- 4;
space = strchr(path_t, ' ');
if (space != NULL)
*space = '\0';
name_t = msg_data->data.text;
urldb_delete_cookie(domain_t, path_t, name_t);
}
break;
default:
break;
}
 
free(msg_data->data.text);
 
return NODE_CALLBACK_HANDLED;
}
 
 
/**
* Updates a tree entry for a cookie.
*
* All information is copied from the cookie_data, and as such can
* be edited and should be freed.
*
* \param node The node to update
* \param data The cookie data to use
* \return true if node updated, or false for failure
*/
static bool cookies_update_cookie_node(struct node *node,
const struct cookie_data *data)
{
struct node_element *element;
char buffer[32];
 
assert(data != NULL);
 
/* update the value text */
element = tree_node_find_element(node, TREE_ELEMENT_VALUE, NULL);
tree_update_element_text(cookies_tree,
element,
messages_get_buff("TreeValue",
data->value != NULL ?
data->value :
messages_get("TreeUnused")));
 
 
/* update the comment text */
if ((data->comment != NULL) &&
(strcmp(data->comment, "") != 0)) {
element = tree_node_find_element(node, TREE_ELEMENT_COMMENT, NULL);
tree_update_element_text(cookies_tree,
element,
messages_get_buff("TreeComment",
data->comment));
}
 
/* update domain text */
element = tree_node_find_element(node, TREE_ELEMENT_DOMAIN, element);
tree_update_element_text(cookies_tree,
element,
messages_get_buff("TreeDomain",
data->domain,
data->domain_from_set ?
messages_get("TreeHeaders") :
""));
 
/* update path text */
element = tree_node_find_element(node, TREE_ELEMENT_PATH, element);
tree_update_element_text(cookies_tree,
element,
messages_get_buff("TreePath", data->path,
data->path_from_set ?
messages_get("TreeHeaders") :
""));
 
/* update expiry text */
element = tree_node_find_element(node, TREE_ELEMENT_EXPIRES, element);
tree_update_element_text(cookies_tree,
element,
messages_get_buff("TreeExpires",
(data->expires > 0)
? (data->expires == 1)
? messages_get("TreeSession")
: ctime(&data->expires)
: messages_get("TreeUnknown")));
 
/* update last used text */
element = tree_node_find_element(node, TREE_ELEMENT_LAST_USED, element);
tree_update_element_text(cookies_tree,
element,
messages_get_buff("TreeLastUsed",
(data->last_used > 0) ?
ctime(&data->last_used) :
messages_get("TreeUnknown")));
 
/* update secure text */
element = tree_node_find_element(node, TREE_ELEMENT_SECURE, element);
tree_update_element_text(cookies_tree,
element,
messages_get_buff("TreeSecure",
data->secure ?
messages_get("Yes") :
messages_get("No")));
 
/* update version text */
element = tree_node_find_element(node, TREE_ELEMENT_VERSION, element);
snprintf(buffer, sizeof(buffer), "TreeVersion%i", data->version);
tree_update_element_text(cookies_tree,
element,
messages_get_buff("TreeVersion",
messages_get(buffer)));
 
/* update persistant text */
element = tree_node_find_element(node, TREE_ELEMENT_PERSISTENT, element);
tree_update_element_text(cookies_tree,
element,
messages_get_buff("TreePersistent",
data->no_destroy ?
messages_get("Yes") :
messages_get("No")));
 
return true;
}
 
/**
* Creates an empty tree entry for a cookie, and links it into the tree.
*
* All information is copied from the cookie_data, and as such can
* be edited and should be freed.
*
* \param parent the node to link to
* \param data the cookie data to use
* \return the node created, or NULL for failure
*/
static struct node *cookies_create_cookie_node(struct node *parent,
const struct cookie_data *data)
{
struct node *node;
char *name;
 
name = strdup(data->name);
if (name == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
return NULL;
}
 
node = tree_create_leaf_node(cookies_tree, NULL, name,
false, false, false);
if (node == NULL) {
free(name);
return NULL;
}
 
tree_set_node_user_callback(node, cookies_node_callback, NULL);
 
tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_PERSISTENT, false);
 
tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_VERSION, false);
 
tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_SECURE, false);
 
tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_LAST_USED, false);
 
tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_EXPIRES, false);
 
tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_PATH, false);
 
tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_DOMAIN, false);
 
if ((data->comment) && (strcmp(data->comment, "")))
tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_COMMENT, false);
tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_VALUE, false);
tree_set_node_icon(cookies_tree, node, cookie_icon);
 
if (!cookies_update_cookie_node(node, data))
{
tree_delete_node(NULL, node, false);
return NULL;
}
 
tree_link_node(cookies_tree, parent, node, false);
return node;
}
 
 
/**
* Called when scheduled event gets fired. Actually performs the update.
*/
static void cookies_schedule_callback(const void *scheduled_data)
{
const struct cookie_data *data = scheduled_data;
struct node *node = NULL;
struct node *cookie_node = NULL;
char *domain_cp;
 
assert(data != NULL);
 
node = cookies_find(cookies_tree_root, data->domain);
 
if (node == NULL) {
domain_cp = strdup(data->domain);
if (domain_cp == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
return;
}
/* ownership of domain_cp passed to tree, if node creation
* does not fail */
node = tree_create_folder_node(cookies_tree,
cookies_tree_root, domain_cp,
false, false, false);
if (node != NULL) {
tree_set_node_user_callback(node, cookies_node_callback,
NULL);
tree_set_node_icon(cookies_tree, node, folder_icon);
 
} else {
free(domain_cp);
}
}
 
if (node == NULL)
return;
 
cookie_node = cookies_find(node, data->name);
if (cookie_node == NULL)
cookies_create_cookie_node(node, data);
else
cookies_update_cookie_node(cookie_node, data);
 
return;
}
 
/**
* Initialises cookies tree.
*
* \param data user data for the callbacks
* \param start_redraw callback function called before every redraw
* \param end_redraw callback function called after every redraw
* \return true on success, false on memory exhaustion
*/
bool cookies_initialise(struct tree *tree, const char* folder_icon_name, const char* cookie_icon_name)
{
 
if (tree == NULL)
return false;
 
folder_icon = tree_load_icon(folder_icon_name);
cookie_icon = tree_load_icon(cookie_icon_name);
 
/* Create an empty tree */
cookies_tree = tree;
cookies_tree_root = tree_get_root(cookies_tree);
 
user_delete = false;
urldb_iterate_cookies(cookies_schedule_update);
tree_set_node_expanded(cookies_tree, cookies_tree_root,
false, true, true);
 
return true;
}
 
 
/**
* Get flags with which the cookies tree should be created;
*
* \return the flags
*/
unsigned int cookies_get_tree_flags(void)
{
return TREE_DELETE_EMPTY_DIRS;
}
 
 
/* exported interface documented in cookies.h */
bool cookies_schedule_update(const struct cookie_data *data)
{
assert(data != NULL);
assert(user_delete == false);
 
if (cookies_tree_root != NULL)
cookies_schedule_callback(data);
 
return true;
}
 
 
/* exported interface documented in cookies.h */
void cookies_remove(const struct cookie_data *data)
{
assert(data != NULL);
 
if (cookies_tree_root != NULL)
cookies_schedule_callback(data);
}
 
 
/**
* Free memory and release all other resources.
*/
void cookies_cleanup(void)
{
hlcache_handle_release(folder_icon);
hlcache_handle_release(cookie_icon);
}
 
/* Actions to be connected to front end specific toolbars */
 
/**
* Delete nodes which are currently selected.
*/
void cookies_delete_selected(void)
{
user_delete = true;
tree_delete_selected_nodes(cookies_tree, cookies_tree_root);
user_delete = false;
}
 
/**
* Delete all nodes.
*/
void cookies_delete_all(void)
{
bool needs_redraw = tree_get_redraw(cookies_tree);
if (needs_redraw)
tree_set_redraw(cookies_tree, false);
 
user_delete = true;
tree_set_node_selected(cookies_tree, cookies_tree_root, true, true);
tree_delete_selected_nodes(cookies_tree, cookies_tree_root);
user_delete = false;
 
if (needs_redraw)
tree_set_redraw(cookies_tree, true);
}
 
/**
* Select all nodes in the tree.
*/
void cookies_select_all(void)
{
tree_set_node_selected(cookies_tree, cookies_tree_root, true, true);
}
 
/**
* Unselect all nodes.
*/
void cookies_clear_selection(void)
{
tree_set_node_selected(cookies_tree, cookies_tree_root, true, false);
}
 
/**
* Expand both domain and cookie nodes.
*/
void cookies_expand_all(void)
{
tree_set_node_expanded(cookies_tree, cookies_tree_root,
true, true, true);
}
 
/**
* Expand domain nodes only.
*/
void cookies_expand_domains(void)
{
tree_set_node_expanded(cookies_tree, cookies_tree_root,
true, true, false);
}
 
/**
* Expand cookie nodes only.
*/
void cookies_expand_cookies(void)
{
tree_set_node_expanded(cookies_tree, cookies_tree_root,
true, false, true);
}
 
/**
* Collapse both domain and cookie nodes.
*/
void cookies_collapse_all(void)
{
tree_set_node_expanded(cookies_tree, cookies_tree_root,
false, true, true);
}
 
/**
* Collapse domain nodes only.
*/
void cookies_collapse_domains(void)
{
tree_set_node_expanded(cookies_tree, cookies_tree_root,
false, true, false);
}
 
/**
* Collapse cookie nodes only.
*/
void cookies_collapse_cookies(void)
{
tree_set_node_expanded(cookies_tree, cookies_tree_root,
false, false, true);
}
/programs/network/netsurf/netsurf/desktop/cookies.h
0,0 → 1,66
/*
* Copyright 2006 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Cookies (interface).
*/
 
#ifndef _NETSURF_DESKTOP_COOKIES_H_
#define _NETSURF_DESKTOP_COOKIES_H_
 
#include <stdbool.h>
 
#include "desktop/tree.h"
 
struct cookie_data;
 
bool cookies_initialise(struct tree *tree, const char* folder_icon_name, const char* cookie_icon_name);
unsigned int cookies_get_tree_flags(void);
 
/**
* Perform cookie updates and addition. The update is only scheduled here.
* The actual update is performed in the callback function.
*
* \param data Data of cookie being updated.
* \return true (for urldb_iterate_entries)
*/
bool cookies_schedule_update(const struct cookie_data *data);
 
/**
* Remove a cookie from the active set.
* The cookie is to be removed from the active set and no futher
* references made to the cookie data.
*
* \param data Data of cookie being removed.
*/
void cookies_remove(const struct cookie_data *data);
 
void cookies_cleanup(void);
 
void cookies_delete_selected(void);
void cookies_delete_all(void);
void cookies_select_all(void);
void cookies_clear_selection(void);
void cookies_expand_all(void);
void cookies_expand_domains(void);
void cookies_expand_cookies(void);
void cookies_collapse_all(void);
void cookies_collapse_domains(void);
void cookies_collapse_cookies(void);
 
#endif
/programs/network/netsurf/netsurf/desktop/download.c
0,0 → 1,312
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/**
* \file desktop/download.c
* \brief Core download context implementation
*/
 
#include <assert.h>
#include <stdlib.h>
 
#include "content/llcache.h"
#include "desktop/download.h"
#include "desktop/gui.h"
#include "utils/http.h"
#include "utils/url.h"
#include "utils/utils.h"
 
/**
* A context for a download
*/
struct download_context {
llcache_handle *llcache; /**< Low-level cache handle */
struct gui_window *parent; /**< Parent window */
 
lwc_string *mime_type; /**< MIME type of download */
unsigned long total_length; /**< Length of data, in bytes */
char *filename; /**< Suggested filename */
 
struct gui_download_window *window; /**< GUI download window */
};
 
/**
* Parse a filename parameter value
*
* \param filename Value to parse
* \return Sanitised filename, or NULL on memory exhaustion
*/
static char *download_parse_filename(const char *filename)
{
const char *slash = strrchr(filename, '/');
 
if (slash != NULL)
slash++;
else
slash = filename;
 
return strdup(slash);
}
 
/**
* Compute a default filename for a download
*
* \param url URL of item being fetched
* \return Default filename, or NULL on memory exhaustion
*/
static char *download_default_filename(const char *url)
{
char *nice;
 
if (url_nice(url, &nice, false) == URL_FUNC_OK)
return nice;
 
return NULL;
}
 
/**
* Process fetch headers for a download context.
* Extracts MIME type, total length, and creates gui_download_window
*
* \param ctx Context to process
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror download_context_process_headers(download_context *ctx)
{
const char *http_header;
http_content_type *content_type;
unsigned long length;
nserror error;
 
/* Retrieve and parse Content-Type */
http_header = llcache_handle_get_header(ctx->llcache, "Content-Type");
if (http_header == NULL)
http_header = "text/plain";
 
error = http_parse_content_type(http_header, &content_type);
if (error != NSERROR_OK)
return error;
 
/* Retrieve and parse Content-Length */
http_header = llcache_handle_get_header(ctx->llcache, "Content-Length");
if (http_header == NULL)
length = 0;
else
length = strtoul(http_header, NULL, 10);
 
/* Retrieve and parse Content-Disposition */
http_header = llcache_handle_get_header(ctx->llcache,
"Content-Disposition");
if (http_header != NULL) {
lwc_string *filename;
lwc_string *filename_value;
http_content_disposition *disposition;
 
if (lwc_intern_string("filename", SLEN("filename"),
&filename) != lwc_error_ok) {
http_content_type_destroy(content_type);
return NSERROR_NOMEM;
}
 
error = http_parse_content_disposition(http_header,
&disposition);
if (error != NSERROR_OK) {
lwc_string_unref(filename);
http_content_type_destroy(content_type);
return error;
}
 
error = http_parameter_list_find_item(disposition->parameters,
filename, &filename_value);
if (error == NSERROR_OK) {
ctx->filename = download_parse_filename(
lwc_string_data(filename_value));
lwc_string_unref(filename_value);
}
 
http_content_disposition_destroy(disposition);
lwc_string_unref(filename);
}
 
ctx->mime_type = lwc_string_ref(content_type->media_type);
ctx->total_length = length;
if (ctx->filename == NULL) {
ctx->filename = download_default_filename(
nsurl_access(
llcache_handle_get_url(ctx->llcache)));
}
 
http_content_type_destroy(content_type);
 
if (ctx->filename == NULL) {
lwc_string_unref(ctx->mime_type);
ctx->mime_type = NULL;
return NSERROR_NOMEM;
}
 
/* Create the frontend window */
ctx->window = gui_download_window_create(ctx, ctx->parent);
if (ctx->window == NULL) {
free(ctx->filename);
ctx->filename = NULL;
lwc_string_unref(ctx->mime_type);
ctx->mime_type = NULL;
return NSERROR_NOMEM;
}
 
return NSERROR_OK;
}
 
/**
* Callback for low-level cache events
*
* \param handle Low-level cache handle
* \param event Event object
* \param pw Our context
* \return NSERROR_OK on success, appropriate error otherwise
*/
static nserror download_callback(llcache_handle *handle,
const llcache_event *event, void *pw)
{
download_context *ctx = pw;
nserror error = NSERROR_OK;
 
switch (event->type) {
case LLCACHE_EVENT_HAD_HEADERS:
error = download_context_process_headers(ctx);
if (error != NSERROR_OK) {
llcache_handle_abort(handle);
download_context_destroy(ctx);
}
 
break;
 
case LLCACHE_EVENT_HAD_DATA:
/* If we didn't know up-front that this fetch was for download,
* then we won't receive the HAD_HEADERS event. Catch up now.
*/
if (ctx->window == NULL) {
error = download_context_process_headers(ctx);
if (error != NSERROR_OK) {
llcache_handle_abort(handle);
download_context_destroy(ctx);
}
}
 
if (error == NSERROR_OK) {
/** \todo Lose ugly cast */
error = gui_download_window_data(ctx->window,
(char *) event->data.data.buf,
event->data.data.len);
if (error != NSERROR_OK)
llcache_handle_abort(handle);
}
 
break;
 
case LLCACHE_EVENT_DONE:
/* There may be no associated window if there was no data or headers */
if (ctx->window != NULL)
gui_download_window_done(ctx->window);
else
download_context_destroy(ctx);
 
break;
 
case LLCACHE_EVENT_ERROR:
if (ctx->window != NULL)
gui_download_window_error(ctx->window, event->data.msg);
else
download_context_destroy(ctx);
 
break;
 
case LLCACHE_EVENT_PROGRESS:
break;
}
 
return error;
}
 
/* See download.h for documentation */
nserror download_context_create(llcache_handle *llcache,
struct gui_window *parent)
{
download_context *ctx;
 
ctx = malloc(sizeof(*ctx));
if (ctx == NULL)
return NSERROR_NOMEM;
 
ctx->llcache = llcache;
ctx->parent = parent;
ctx->mime_type = NULL;
ctx->total_length = 0;
ctx->filename = NULL;
ctx->window = NULL;
 
llcache_handle_change_callback(llcache, download_callback, ctx);
 
return NSERROR_OK;
}
 
/* See download.h for documentation */
void download_context_destroy(download_context *ctx)
{
llcache_handle_release(ctx->llcache);
 
if (ctx->mime_type != NULL)
lwc_string_unref(ctx->mime_type);
 
free(ctx->filename);
 
/* Window is not owned by us, so don't attempt to destroy it */
 
free(ctx);
}
 
/* See download.h for documentation */
void download_context_abort(download_context *ctx)
{
llcache_handle_abort(ctx->llcache);
}
 
/* See download.h for documentation */
const char *download_context_get_url(const download_context *ctx)
{
return nsurl_access(llcache_handle_get_url(ctx->llcache));
}
 
/* See download.h for documentation */
const char *download_context_get_mime_type(const download_context *ctx)
{
return lwc_string_data(ctx->mime_type);
}
 
/* See download.h for documentation */
unsigned long download_context_get_total_length(const download_context *ctx)
{
return ctx->total_length;
}
 
/* See download.h for documentation */
const char *download_context_get_filename(const download_context *ctx)
{
return ctx->filename;
}
 
/programs/network/netsurf/netsurf/desktop/download.h
0,0 → 1,99
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/**
* \file desktop/download.h
* \brief Core download context (interface)
*/
 
#ifndef NETSURF_DESKTOP_DOWNLOAD_H_
#define NETSURF_DESKTOP_DOWNLOAD_H_
 
#include "utils/errors.h"
 
struct gui_window;
struct llcache_handle;
 
/** Type of a download context */
typedef struct download_context download_context;
 
/**
* Create a download context
*
* \param llcache Low-level cache handle for download
* \param parent Parent window, for UI
* \return NSERROR_OK on success, appropriate error otherwise
*
* This must only be called by the core browser window fetch infrastructure.
* Ownership of the download context object created is passed to the frontend.
*/
nserror download_context_create(struct llcache_handle *llcache,
struct gui_window *parent);
 
/**
* Destroy a download context
*
* \param ctx Context to destroy
*
* Called by the frontend when it has finished with a download context
*/
void download_context_destroy(download_context *ctx);
 
/**
* Abort a download fetch
*
* \param ctx Context to abort
*
* Called by the frontend to abort a download.
* The context must be destroyed independently.
*/
void download_context_abort(download_context *ctx);
 
/**
* Retrieve the URL for a download
*
* \param ctx Context to retrieve URL from
* \return URL string
*/
const char *download_context_get_url(const download_context *ctx);
 
/**
* Retrieve the MIME type for a download
*
* \param ctx Context to retrieve MIME type from
* \return MIME type string
*/
const char *download_context_get_mime_type(const download_context *ctx);
 
/**
* Retrieve total byte length of download
*
* \param ctx Context to retrieve byte length from
* \return Total length, in bytes, or 0 if unknown
*/
unsigned long download_context_get_total_length(const download_context *ctx);
 
/**
* Retrieve the filename for a download
*
* \param ctx Context to retrieve filename from
* \return Filename string
*/
const char *download_context_get_filename(const download_context *ctx);
 
#endif
/programs/network/netsurf/netsurf/desktop/frame_types.h
0,0 → 1,45
/*
* Copyright 2011 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Browser window creation and manipulation (interface).
*/
 
#ifndef _NETSURF_DESKTOP_FRAME_TYPES_H_
#define _NETSURF_DESKTOP_FRAME_TYPES_H_
 
struct frame_dimension {
float value;
enum {
FRAME_DIMENSION_PIXELS, /* '100', '200' */
FRAME_DIMENSION_PERCENT, /* '5%', '20%' */
FRAME_DIMENSION_RELATIVE /* '*', '2*' */
} unit;
};
 
typedef enum {
SCROLLING_AUTO,
SCROLLING_YES,
SCROLLING_NO
} frame_scrolling;
 
/* Handy struct names */
struct content_html_iframe;
struct content_html_frames;
 
#endif
/programs/network/netsurf/netsurf/desktop/frames.c
0,0 → 1,943
/*
* Copyright 2006 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Frame and frameset creation and manipulation (implementation).
*/
 
#include <assert.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include "utils/config.h"
#include "content/hlcache.h"
#include "desktop/browser_private.h"
#include "desktop/frames.h"
#include "desktop/history_core.h"
#include "desktop/gui.h"
#include "desktop/scrollbar.h"
#include "desktop/selection.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
#include "render/html.h"
#include "render/box.h"
 
/** maximum frame resize margin */
#define FRAME_RESIZE 6
 
static bool browser_window_resolve_frame_dimension(struct browser_window *bw,
struct browser_window *sibling, int x, int y, bool width,
bool height);
 
 
/**
* Callback for (i)frame scrollbars.
*/
void browser_window_scroll_callback(void *client_data,
struct scrollbar_msg_data *scrollbar_data)
{
struct browser_window *bw = client_data;
 
switch(scrollbar_data->msg) {
case SCROLLBAR_MSG_MOVED:
if (bw->browser_window_type == BROWSER_WINDOW_IFRAME) {
html_redraw_a_box(bw->parent->current_content, bw->box);
} else {
struct rect rect;
 
rect.x0 = scrollbar_get_offset(bw->scroll_x);
rect.y0 = scrollbar_get_offset(bw->scroll_y);
rect.x1 = rect.x0 + bw->width;
rect.y1 = rect.y0 + bw->height;
 
browser_window_update_box(bw, &rect);
}
break;
case SCROLLBAR_MSG_SCROLL_START:
{
struct rect rect = {
.x0 = scrollbar_data->x0,
.y0 = scrollbar_data->y0,
.x1 = scrollbar_data->x1,
.y1 = scrollbar_data->y1
};
 
if (scrollbar_is_horizontal(scrollbar_data->scrollbar))
browser_window_set_drag_type(bw, DRAGGING_SCR_X, &rect);
else
browser_window_set_drag_type(bw, DRAGGING_SCR_Y, &rect);
}
break;
case SCROLLBAR_MSG_SCROLL_FINISHED:
browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);
 
browser_window_set_pointer(bw, BROWSER_POINTER_DEFAULT);
break;
}
}
 
/* exported interface, documented in browser.h */
void browser_window_handle_scrollbars(struct browser_window *bw)
{
hlcache_handle *h = bw->current_content;
bool scroll_x;
bool scroll_y;
int c_width = 0;
int c_height = 0;
 
assert(!bw->window); /* Core-handled windows only */
 
if (h != NULL) {
c_width = content_get_width(h);
c_height = content_get_height(h);
}
 
if (bw->scrolling == SCROLLING_YES) {
scroll_x = true;
scroll_y = true;
} else if (bw->scrolling == SCROLLING_AUTO &&
bw->current_content) {
int bw_width = bw->width;
int bw_height = bw->height;
 
/* subtract existing scrollbar width */
bw_width -= bw->scroll_y ? SCROLLBAR_WIDTH : 0;
bw_height -= bw->scroll_x ? SCROLLBAR_WIDTH : 0;
 
scroll_y = (c_height > bw_height) ? true : false;
scroll_x = (c_width > bw_width) ? true : false;
} else {
/* No scrollbars */
scroll_x = false;
scroll_y = false;
}
 
if (!scroll_x && bw->scroll_x != NULL) {
scrollbar_destroy(bw->scroll_x);
bw->scroll_x = NULL;
}
 
if (!scroll_y && bw->scroll_y != NULL) {
scrollbar_destroy(bw->scroll_y);
bw->scroll_y = NULL;
}
 
if (scroll_y) {
int length = bw->height;
int visible = bw->height - (scroll_x ? SCROLLBAR_WIDTH : 0);
 
if (bw->scroll_y == NULL) {
/* create vertical scrollbar */
if (!scrollbar_create(false, length, c_height, visible,
bw, browser_window_scroll_callback,
&(bw->scroll_y)))
return;
} else {
/* update vertical scrollbar */
scrollbar_set_extents(bw->scroll_y, length,
visible, c_height);
}
}
 
if (scroll_x) {
int length = bw->width - (scroll_y ? SCROLLBAR_WIDTH : 0);
int visible = length;
 
if (bw->scroll_x == NULL) {
/* create horizontal scrollbar */
if (!scrollbar_create(true, length, c_width, visible,
bw, browser_window_scroll_callback,
&(bw->scroll_x)))
return;
} else {
/* update horizontal scrollbar */
scrollbar_set_extents(bw->scroll_x, length,
visible, c_width);
}
}
 
if (scroll_x && scroll_y)
scrollbar_make_pair(bw->scroll_x, bw->scroll_y);
}
 
 
/**
* Create and open a iframes for a browser window.
*
* \param bw The browser window to create iframes for
* \param iframe The iframes to create
*/
 
void browser_window_create_iframes(struct browser_window *bw,
struct content_html_iframe *iframe)
{
struct browser_window *window;
struct content_html_iframe *cur;
struct rect rect;
int iframes = 0;
int index;
 
for (cur = iframe; cur; cur = cur->next)
iframes++;
bw->iframes = calloc(iframes, sizeof(*bw));
if (!bw->iframes)
return;
bw->iframe_count = iframes;
 
index = 0;
for (cur = iframe; cur; cur = cur->next) {
window = &(bw->iframes[index++]);
 
/* Initialise common parts */
browser_window_initialise_common(window, NULL);
 
/* window characteristics */
window->browser_window_type = BROWSER_WINDOW_IFRAME;
window->scrolling = cur->scrolling;
window->border = cur->border;
window->border_colour = cur->border_colour;
window->no_resize = true;
window->margin_width = cur->margin_width;
window->margin_height = cur->margin_height;
window->cur_sel = bw->cur_sel;
window->scale = bw->scale;
if (cur->name) {
window->name = strdup(cur->name);
if (!window->name)
warn_user("NoMemory", 0);
}
 
/* linking */
window->box = cur->box;
window->parent = bw;
window->box->iframe = window;
 
/* iframe dimensions */
box_bounds(window->box, &rect);
 
browser_window_set_position(window, rect.x0, rect.y0);
browser_window_set_dimensions(window, rect.x1 - rect.x0,
rect.y1 - rect.y0);
}
 
/* calculate dimensions */
browser_window_update_extent(bw);
browser_window_recalculate_iframes(bw);
 
index = 0;
for (cur = iframe; cur; cur = cur->next) {
window = &(bw->iframes[index++]);
if (cur->url) {
/* fetch iframe's content */
browser_window_go_unverifiable(window,
nsurl_access(cur->url),
nsurl_access(hlcache_handle_get_url(
bw->current_content)),
false, bw->current_content);
}
}
}
 
 
/**
* Recalculate iframe positions following a resize.
*
* \param bw The browser window to reposition iframes for
*/
 
void browser_window_recalculate_iframes(struct browser_window *bw)
{
struct browser_window *window;
int index;
 
for (index = 0; index < bw->iframe_count; index++) {
window = &(bw->iframes[index]);
 
if (window != NULL) {
browser_window_handle_scrollbars(window);
}
}
}
 
 
/**
* Create and open a frameset for a browser window.
*
* \param bw The browser window to create the frameset for
* \param iframe The frameset to create
*/
 
void browser_window_create_frameset(struct browser_window *bw,
struct content_html_frames *frameset)
{
int row, col, index;
struct content_html_frames *frame;
struct browser_window *window;
hlcache_handle *parent;
 
assert(bw && frameset);
 
/* 1. Create children */
assert(bw->children == NULL);
assert(frameset->cols + frameset->rows != 0);
 
bw->children = calloc((frameset->cols * frameset->rows), sizeof(*bw));
if (!bw->children)
return;
bw->cols = frameset->cols;
bw->rows = frameset->rows;
for (row = 0; row < bw->rows; row++) {
for (col = 0; col < bw->cols; col++) {
index = (row * bw->cols) + col;
frame = &frameset->children[index];
window = &bw->children[index];
 
/* Initialise common parts */
browser_window_initialise_common(window, NULL);
 
/* window characteristics */
if (frame->children)
window->browser_window_type =
BROWSER_WINDOW_FRAMESET;
else
window->browser_window_type =
BROWSER_WINDOW_FRAME;
window->scrolling = frame->scrolling;
window->border = frame->border;
window->border_colour = frame->border_colour;
window->no_resize = frame->no_resize;
window->frame_width = frame->width;
window->frame_height = frame->height;
window->margin_width = frame->margin_width;
window->margin_height = frame->margin_height;
if (frame->name) {
window->name = strdup(frame->name);
if (!window->name)
warn_user("NoMemory", 0);
}
 
window->cur_sel = bw->cur_sel;
window->scale = bw->scale;
 
/* linking */
window->parent = bw;
 
if (window->name)
LOG(("Created frame '%s'", window->name));
else
LOG(("Created frame (unnamed)"));
}
}
 
/* 2. Calculate dimensions */
browser_window_update_extent(bw);
browser_window_recalculate_frameset(bw);
 
/* 3. Recurse for grandchildren */
for (row = 0; row < bw->rows; row++) {
for (col = 0; col < bw->cols; col++) {
index = (row * bw->cols) + col;
frame = &frameset->children[index];
window = &bw->children[index];
 
if (frame->children)
browser_window_create_frameset(window, frame);
}
}
 
/* Use the URL of the first ancestor window containing html content
* as the referer */
for (window = bw; window->parent; window = window->parent) {
if (window->current_content &&
content_get_type(window->current_content) ==
CONTENT_HTML)
break;
}
 
parent = window->current_content;
 
/* 4. Launch content */
for (row = 0; row < bw->rows; row++) {
for (col = 0; col < bw->cols; col++) {
index = (row * bw->cols) + col;
frame = &frameset->children[index];
window = &bw->children[index];
 
if (frame->url) {
browser_window_go_unverifiable(window,
nsurl_access(frame->url),
nsurl_access(hlcache_handle_get_url(
parent)),
true,
parent);
}
}
}
}
 
 
/**
* Recalculate frameset positions following a resize.
*
* \param bw The browser window to reposition framesets for
*/
 
void browser_window_recalculate_frameset(struct browser_window *bw)
{
int widths[bw->cols][bw->rows];
int heights[bw->cols][bw->rows];
int bw_width, bw_height;
int avail_width, avail_height;
int row, row2, col, index;
struct browser_window *window;
float relative;
int size, extent, applied;
int x, y;
int new_width, new_height;
 
assert(bw);
 
/* window dimensions */
if (!bw->parent) {
browser_window_get_dimensions(bw, &bw_width, &bw_height, true);
bw->x = 0;
bw->y = 0;
bw->width = bw_width;
bw->height = bw_height;
} else {
bw_width = bw->width;
bw_height = bw->height;
}
bw_width++;
bw_height++;
 
/* widths */
for (row = 0; row < bw->rows; row++) {
avail_width = bw_width;
relative = 0;
for (col = 0; col < bw->cols; col++) {
index = (row * bw->cols) + col;
window = &bw->children[index];
 
switch (window->frame_width.unit) {
case FRAME_DIMENSION_PIXELS:
widths[col][row] = window->frame_width.value *
window->scale;
if (window->border) {
if (col != 0)
widths[col][row] += 1;
if (col != bw->cols - 1)
widths[col][row] += 1;
}
break;
case FRAME_DIMENSION_PERCENT:
widths[col][row] = bw_width *
window->frame_width.value / 100;
break;
case FRAME_DIMENSION_RELATIVE:
widths[col][row] = 0;
relative += window->frame_width.value;
break;
default:
/* unknown frame dimension unit */
assert(window->frame_width.unit ==
FRAME_DIMENSION_PIXELS ||
window->frame_width.unit ==
FRAME_DIMENSION_PERCENT ||
window->frame_width.unit ==
FRAME_DIMENSION_RELATIVE);
break;
}
avail_width -= widths[col][row];
}
 
/* Redistribute to fit window */
if ((relative > 0) && (avail_width > 0)) {
/* Expand the relative sections to fill remainder */
for (col = 0; col < bw->cols; col++) {
index = (row * bw->cols) + col;
window = &bw->children[index];
 
if (window->frame_width.unit ==
FRAME_DIMENSION_RELATIVE) {
size = avail_width * window->
frame_width.value /
relative;
avail_width -= size;
relative -= window->frame_width.value;
widths[col][row] += size;
}
}
} else if (bw_width != avail_width) {
/* proportionally distribute error */
extent = avail_width;
applied = 0;
for (col = 0; col < bw->cols; col++) {
if (col == bw->cols - 1) {
/* Last cell, use up remainder */
widths[col][row] += extent - applied;
widths[col][row] =
widths[col][row] < 0 ?
0 : widths[col][row];
} else {
/* Find size of cell adjustment */
size = (widths[col][row] * extent) /
(bw_width - extent);
/* Modify cell */
widths[col][row] += size;
applied += size;
}
}
}
}
 
/* heights */
for (col = 0; col < bw->cols; col++) {
avail_height = bw_height;
relative = 0;
for (row = 0; row < bw->rows; row++) {
index = (row * bw->cols) + col;
window = &bw->children[index];
 
switch (window->frame_height.unit) {
case FRAME_DIMENSION_PIXELS:
heights[col][row] = window->frame_height.value *
window->scale;
if (window->border) {
if (row != 0)
heights[col][row] += 1;
if (row != bw->rows - 1)
heights[col][row] += 1;
}
break;
case FRAME_DIMENSION_PERCENT:
heights[col][row] = bw_height *
window->frame_height.value / 100;
break;
case FRAME_DIMENSION_RELATIVE:
heights[col][row] = 0;
relative += window->frame_height.value;
break;
default:
/* unknown frame dimension unit */
assert(window->frame_height.unit ==
FRAME_DIMENSION_PIXELS ||
window->frame_height.unit ==
FRAME_DIMENSION_PERCENT ||
window->frame_height.unit ==
FRAME_DIMENSION_RELATIVE);
break;
}
avail_height -= heights[col][row];
}
 
if (avail_height == 0)
continue;
 
/* Redistribute to fit window */
if ((relative > 0) && (avail_height > 0)) {
/* Expand the relative sections to fill remainder */
for (row = 0; row < bw->rows; row++) {
index = (row * bw->cols) + col;
window = &bw->children[index];
 
if (window->frame_height.unit ==
FRAME_DIMENSION_RELATIVE) {
size = avail_height * window->
frame_height.value /
relative;
avail_height -= size;
relative -= window->frame_height.value;
heights[col][row] += size;
}
}
} else if (bw_height != avail_height) {
/* proportionally distribute error */
extent = avail_height;
applied = 0;
for (row = 0; row < bw->rows; row++) {
if (row == bw->rows - 1) {
/* Last cell, use up remainder */
heights[col][row] += extent - applied;
heights[col][row] =
heights[col][row] < 0 ?
0 : heights[col][row];
} else {
/* Find size of cell adjustment */
size = (heights[col][row] * extent) /
(bw_height - extent);
/* Modify cell */
heights[col][row] += size;
applied += size;
}
}
}
}
 
/* position frames and calculate children */
for (row = 0; row < bw->rows; row++) {
x = 0;
for (col = 0; col < bw->cols; col++) {
index = (row * bw->cols) + col;
window = &bw->children[index];
 
y = 0;
for (row2 = 0; row2 < row; row2++)
y+= heights[col][row2];
 
window->x = x;
window->y = y;
 
new_width = widths[col][row] - 1;
new_height = heights[col][row] - 1;
 
if (window->width != new_width ||
window->height != new_height) {
/* Change in frame size */
browser_window_reformat(window, false,
new_width * bw->scale,
new_height * bw->scale);
window->width = new_width;
window->height = new_height;
 
browser_window_handle_scrollbars(window);
}
 
x += widths[col][row];
 
if (window->children)
browser_window_recalculate_frameset(window);
}
}
}
 
 
/**
* Resize a browser window that is a frame.
*
* \param bw The browser window to resize
*/
 
void browser_window_resize_frame(struct browser_window *bw, int x, int y)
{
struct browser_window *parent;
struct browser_window *sibling;
int col = -1, row = -1, i;
bool change = false;
 
parent = bw->parent;
assert(parent);
 
/* get frame location */
for (i = 0; i < (parent->cols * parent->rows); i++) {
if (&parent->children[i] == bw) {
col = i % parent->cols;
row = i / parent->cols;
}
}
assert((col >= 0) && (row >= 0));
 
sibling = NULL;
if (bw->drag_resize_left)
sibling = &parent->children[row * parent->cols + (col - 1)];
else if (bw->drag_resize_right)
sibling = &parent->children[row * parent->cols + (col + 1)];
if (sibling)
change |= browser_window_resolve_frame_dimension(bw, sibling,
x, y, true, false);
 
sibling = NULL;
if (bw->drag_resize_up)
sibling = &parent->children[(row - 1) * parent->cols + col];
else if (bw->drag_resize_down)
sibling = &parent->children[(row + 1) * parent->cols + col];
if (sibling)
change |= browser_window_resolve_frame_dimension(bw, sibling,
x, y, false, true);
 
if (change)
browser_window_recalculate_frameset(parent);
}
 
 
bool browser_window_resolve_frame_dimension(struct browser_window *bw,
struct browser_window *sibling,
int x, int y, bool width, bool height)
{
int bw_dimension, sibling_dimension;
int bw_pixels, sibling_pixels;
struct frame_dimension *bw_d, *sibling_d;
float total_new;
int frame_size;
 
assert(!(width && height));
 
/* extend/shrink the box to the pointer */
if (width) {
if (bw->drag_resize_left)
bw_dimension = bw->x + bw->width - x;
else
bw_dimension = x - bw->x;
bw_pixels = bw->width;
sibling_pixels = sibling->width;
bw_d = &bw->frame_width;
sibling_d = &sibling->frame_width;
frame_size = bw->parent->width;
} else {
if (bw->drag_resize_up)
bw_dimension = bw->y + bw->height - y;
else
bw_dimension = y - bw->y;
bw_pixels = bw->height;
sibling_pixels = sibling->height;
bw_d = &bw->frame_height;
sibling_d = &sibling->frame_height;
frame_size = bw->parent->height;
}
sibling_dimension = bw_pixels + sibling_pixels - bw_dimension;
 
/* check for no change or no frame size*/
if ((bw_dimension == bw_pixels) || (frame_size == 0))
return false;
/* check for both being 0 */
total_new = bw_dimension + sibling_dimension;
if ((bw_dimension + sibling_dimension) == 0)
return false;
 
/* our frame dimensions are now known to be:
*
* <-- frame_size --> [VISIBLE PIXELS]
* |<-- bw_pixels -->|<-- sibling_pixels -->| [VISIBLE PIXELS, BEFORE RESIZE]
* |<-- bw_d->value-->|<-- sibling_d->value-->| [SPECIFIED UNITS, BEFORE RESIZE]
* |<--bw_dimension-->|<--sibling_dimension-->| [VISIBLE PIXELS, AFTER RESIZE]
* |<-- total_new -->| [VISIBLE PIXELS, AFTER RESIZE]
*
* when we resize, we must retain the original unit specification such that any
* subsequent resizing of the parent window will recalculate the page as the
* author specified.
*
* if the units of both frames are the same then we can resize the values simply
* by updating the values to be a percentage of the original widths.
*/
if (bw_d->unit == sibling_d->unit) {
float total_specified = bw_d->value + sibling_d->value;
bw_d->value = (total_specified * bw_dimension) / total_new;
sibling_d->value = total_specified - bw_d->value;
return true;
}
 
/* if one of the sizes is relative then we don't alter the relative width and
* just let it reflow across. the non-relative (pixel/percentage) value can
* simply be resolved to the specified width that will result in the required
* dimension.
*/
if (bw_d->unit == FRAME_DIMENSION_RELATIVE) {
if ((sibling_pixels == 0) && (bw_dimension == 0))
return false;
if (fabs(sibling_d->value) < 0.0001)
bw_d->value = 1;
if (sibling_pixels == 0)
sibling_d->value = (sibling_d->value * bw_pixels) / bw_dimension;
else
sibling_d->value =
(sibling_d->value * sibling_dimension) / sibling_pixels;
 
/* todo: the availble resize may have changed, update the drag box */
return true;
} else if (sibling_d->unit == FRAME_DIMENSION_RELATIVE) {
if ((bw_pixels == 0) && (sibling_dimension == 0))
return false;
if (fabs(bw_d->value) < 0.0001)
bw_d->value = 1;
if (bw_pixels == 0)
bw_d->value = (bw_d->value * sibling_pixels) / sibling_dimension;
else
bw_d->value = (bw_d->value * bw_dimension) / bw_pixels;
 
/* todo: the availble resize may have changed, update the drag box */
return true;
}
 
/* finally we have a pixel/percentage mix. unlike relative values, percentages
* can easily be backwards-calculated as they can simply be scaled like pixel
* values
*/
if (bw_d->unit == FRAME_DIMENSION_PIXELS) {
float total_specified = bw_d->value + frame_size * sibling_d->value / 100;
bw_d->value = (total_specified * bw_dimension) / total_new;
sibling_d->value = (total_specified - bw_d->value) * 100 / frame_size;
return true;
} else if (sibling_d->unit == FRAME_DIMENSION_PIXELS) {
float total_specified = bw_d->value * frame_size / 100 + sibling_d->value;
sibling_d->value = (total_specified * sibling_dimension) / total_new;
bw_d->value = (total_specified - sibling_d->value) * 100 / frame_size;
return true;
}
assert(!"Invalid frame dimension unit");
return false;
}
 
 
static bool browser_window_resize_frames(struct browser_window *bw,
browser_mouse_state mouse, int x, int y,
browser_pointer_shape *pointer)
{
struct browser_window *parent;
bool left, right, up, down;
int i, resize_margin;
 
if ((x < bw->x) || (x > bw->x + bw->width) ||
(y < bw->y) || (y > bw->y + bw->height))
return false;
 
parent = bw->parent;
if ((!bw->no_resize) && parent) {
resize_margin = FRAME_RESIZE;
if (resize_margin * 2 > bw->width)
resize_margin = bw->width / 2;
left = (x < bw->x + resize_margin);
right = (x > bw->x + bw->width - resize_margin);
resize_margin = FRAME_RESIZE;
if (resize_margin * 2 > bw->height)
resize_margin = bw->height / 2;
up = (y < bw->y + resize_margin);
down = (y > bw->y + bw-> height - resize_margin);
 
/* check if the edges can actually be moved */
if (left || right || up || down) {
int row = -1, col = -1;
switch (bw->browser_window_type) {
case BROWSER_WINDOW_NORMAL:
case BROWSER_WINDOW_IFRAME:
assert(0);
break;
case BROWSER_WINDOW_FRAME:
case BROWSER_WINDOW_FRAMESET:
break;
}
for (i = 0; i < (parent->cols * parent->rows); i++) {
if (&parent->children[i] == bw) {
col = i % parent->cols;
row = i / parent->cols;
break;
}
}
assert((row >= 0) && (col >= 0));
 
/* check the sibling frame is within bounds */
left &= (col > 0);
right &= (col < parent->cols - 1);
up &= (row > 0);
down &= (row < parent->rows - 1);
 
/* check the sibling frames can be resized */
if (left)
left &= !parent->children[row *
parent->cols + (col - 1)].
no_resize;
if (right)
right &= !parent->children[row *
parent->cols + (col + 1)].
no_resize;
if (up)
up &= !parent->children[(row - 1) *
parent->cols + col].
no_resize;
if (down)
down &= !parent->children[(row + 1) *
parent->cols + col].
no_resize;
 
/* can't have opposite directions simultaneously */
if (up)
down = false;
if (left)
right = false;
}
 
if (left || right || up || down) {
if (left) {
if (down)
*pointer = BROWSER_POINTER_LD;
else if (up)
*pointer = BROWSER_POINTER_LU;
else
*pointer = BROWSER_POINTER_LEFT;
} else if (right) {
if (down)
*pointer = BROWSER_POINTER_RD;
else if (up)
*pointer = BROWSER_POINTER_RU;
else
*pointer = BROWSER_POINTER_RIGHT;
} else if (up) {
*pointer = BROWSER_POINTER_UP;
} else {
*pointer = BROWSER_POINTER_DOWN;
}
if (mouse & (BROWSER_MOUSE_DRAG_1 |
BROWSER_MOUSE_DRAG_2)) {
 
/* TODO: Pass appropriate rectangle to allow
* front end to clamp pointer range */
browser_window_set_drag_type(bw,
DRAGGING_FRAME, NULL);
bw->drag_start_x = x;
bw->drag_start_y = y;
bw->drag_resize_left = left;
bw->drag_resize_right = right;
bw->drag_resize_up = up;
bw->drag_resize_down = down;
}
return true;
}
}
 
if (bw->children) {
for (i = 0; i < (bw->cols * bw->rows); i++)
if (browser_window_resize_frames(&bw->children[i],
mouse, x, y, pointer))
return true;
}
if (bw->iframes) {
for (i = 0; i < bw->iframe_count; i++)
if (browser_window_resize_frames(&bw->iframes[i],
mouse, x, y, pointer))
return true;
}
return false;
}
 
 
bool browser_window_frame_resize_start(struct browser_window *bw,
browser_mouse_state mouse, int x, int y,
browser_pointer_shape *pointer)
{
struct browser_window *root = browser_window_get_root(bw);
int offx, offy;
 
browser_window_get_position(bw, true, &offx, &offy);
 
return browser_window_resize_frames(root, mouse,
x + offx, y + offy, pointer);
}
/programs/network/netsurf/netsurf/desktop/frames.h
0,0 → 1,52
/*
* Copyright 2006 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Frame and frameset creation and manipulation (interface).
*/
 
#ifndef _NETSURF_DESKTOP_FRAMES_H_
#define _NETSURF_DESKTOP_FRAMES_H_
 
#include "desktop/browser.h"
 
struct scrollbar_msg_data;
 
void browser_window_create_iframes(struct browser_window *bw,
struct content_html_iframe *iframe);
void browser_window_recalculate_iframes(struct browser_window *bw);
void browser_window_create_frameset(struct browser_window *bw,
struct content_html_frames *frameset);
void browser_window_recalculate_frameset(struct browser_window *bw);
bool browser_window_frame_resize_start(struct browser_window *bw,
browser_mouse_state mouse, int x, int y,
browser_pointer_shape *pointer);
void browser_window_resize_frame(struct browser_window *bw, int x, int y);
 
void browser_window_scroll_callback(void *client_data,
struct scrollbar_msg_data *scrollbar_data);
 
 
/**
* Create, remove, and update browser window scrollbars
*
* \param bw The browser window
*/
void browser_window_handle_scrollbars(struct browser_window *bw);
 
#endif
/programs/network/netsurf/netsurf/desktop/gui.h
0,0 → 1,183
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Interface to platform-specific gui functions.
*/
 
#ifndef _NETSURF_DESKTOP_GUI_H_
#define _NETSURF_DESKTOP_GUI_H_
 
typedef enum {
GUI_SAVE_SOURCE,
GUI_SAVE_DRAW,
GUI_SAVE_PDF,
GUI_SAVE_TEXT,
GUI_SAVE_COMPLETE,
GUI_SAVE_OBJECT_ORIG,
GUI_SAVE_OBJECT_NATIVE,
GUI_SAVE_LINK_URI,
GUI_SAVE_LINK_URL,
GUI_SAVE_LINK_TEXT,
GUI_SAVE_HOTLIST_EXPORT_HTML,
GUI_SAVE_HISTORY_EXPORT_HTML,
GUI_SAVE_TEXT_SELECTION,
GUI_SAVE_CLIPBOARD_CONTENTS
} gui_save_type;
 
typedef enum {
GDRAGGING_NONE,
GDRAGGING_SCROLLBAR,
GDRAGGING_OTHER
} gui_drag_type;
 
struct gui_window;
struct gui_download_window;
struct browser_window;
struct selection;
struct form_control;
 
#include <stdbool.h>
 
#include <libwapcaplet/libwapcaplet.h>
#include <libcss/libcss.h>
 
#include "utils/config.h"
#include "content/hlcache.h"
#include "desktop/download.h"
#include "desktop/mouse.h"
#include "desktop/search.h"
#include "utils/errors.h"
 
/** \todo remove these when each frontend calls nslog_init */
#include <stdio.h>
bool nslog_ensure(FILE *fptr);
 
void gui_poll(bool active);
void gui_quit(void);
 
struct gui_window *gui_create_browser_window(struct browser_window *bw,
struct browser_window *clone, bool new_tab);
void gui_window_destroy(struct gui_window *g);
void gui_window_set_title(struct gui_window *g, const char *title);
void gui_window_redraw_window(struct gui_window *g);
void gui_window_update_box(struct gui_window *g,
const struct rect *rect);
bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy);
void gui_window_set_scroll(struct gui_window *g, int sx, int sy);
void gui_window_scroll_visible(struct gui_window *g, int x0, int y0,
int x1, int y1);
void gui_window_get_dimensions(struct gui_window *g, int *width, int *height,
bool scaled);
void gui_window_update_extent(struct gui_window *g);
void gui_window_set_status(struct gui_window *g, const char *text);
void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape);
void gui_window_hide_pointer(struct gui_window *g);
void gui_window_set_url(struct gui_window *g, const char *url);
void gui_window_start_throbber(struct gui_window *g);
void gui_window_stop_throbber(struct gui_window *g);
void gui_window_set_icon(struct gui_window *g, hlcache_handle *icon);
void gui_window_set_search_ico(hlcache_handle *ico);
void gui_window_place_caret(struct gui_window *g, int x, int y, int height);
void gui_window_remove_caret(struct gui_window *g);
void gui_window_new_content(struct gui_window *g);
bool gui_window_scroll_start(struct gui_window *g);
 
bool gui_window_drag_start(struct gui_window *g, gui_drag_type type,
const struct rect *rect);
 
void gui_window_save_link(struct gui_window *g, const char *url,
const char *title);
 
struct gui_download_window *gui_download_window_create(download_context *ctx,
struct gui_window *parent);
nserror gui_download_window_data(struct gui_download_window *dw,
const char *data, unsigned int size);
void gui_download_window_error(struct gui_download_window *dw,
const char *error_msg);
void gui_download_window_done(struct gui_download_window *dw);
 
void gui_drag_save_object(gui_save_type type, hlcache_handle *c,
struct gui_window *g);
void gui_drag_save_selection(struct selection *s, struct gui_window *g);
void gui_start_selection(struct gui_window *g);
void gui_clear_selection(struct gui_window *g);
 
 
 
/**
* Core asks front end for clipboard contents.
*
* \param buffer UTF-8 text, allocated by front end, ownership yeilded to core
* \param length Byte length of UTF-8 text in buffer
*/
void gui_get_clipboard(char **buffer, size_t *length);
 
typedef struct nsnsclipboard_styles {
size_t start; /**< Start of run */
 
plot_font_style_t style; /**< Style to give text run */
} nsclipboard_styles;
/**
* Core tells front end to put given text in clipboard
*
* \param buffer UTF-8 text, owned by core
* \param length Byte length of UTF-8 text in buffer
* \param styles Array of styles given to text runs, owned by core, or NULL
* \param n_styles Number of text run styles in array
*/
void gui_set_clipboard(const char *buffer, size_t length,
nsclipboard_styles styles[], int n_styles);
 
 
 
void gui_create_form_select_menu(struct browser_window *bw,
struct form_control *control);
 
void gui_launch_url(const char *url);
 
struct ssl_cert_info;
 
void gui_cert_verify(nsurl *url, const struct ssl_cert_info *certs,
unsigned long num, nserror (*cb)(bool proceed, void *pw),
void *cbpw);
 
/**
* Callback to translate resource to full url.
*
* Transforms a resource: path into a full URL. The returned URL
* is used as the target for a redirect. The caller takes ownership of
* the returned nsurl including unrefing it when finished with it.
*
* \param path The path of the resource to locate.
* \return A string containing the full URL of the target object or
* NULL if no suitable resource can be found.
*/
nsurl* gui_get_resource_url(const char *path);
 
/** css callback to obtain named system colours from a frontend. */
css_error gui_system_colour(void *pw, lwc_string *name, css_color *color);
 
/** Obtain a named system colour from a frontend. */
colour gui_system_colour_char(const char *name);
 
bool gui_system_colour_init(void);
void gui_system_colour_finalize(void);
 
#endif
/programs/network/netsurf/netsurf/desktop/history_core.c
0,0 → 1,846
/*
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
* Copyright 2005 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Browser history tree (implementation).
*/
 
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "content/content.h"
#include "content/hlcache.h"
#include "content/urldb.h"
#include "css/css.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
#include "desktop/history_core.h"
#include "desktop/plotters.h"
#include "desktop/thumbnail.h"
#include "image/bitmap.h"
#include "render/font.h"
#include "utils/log.h"
#include "utils/url.h"
#include "utils/utils.h"
 
 
#define WIDTH 100
#define HEIGHT 86
#define RIGHT_MARGIN 50
#define BOTTOM_MARGIN 30
 
struct history_page {
char *url; /**< Page URL, never 0. */
char *frag_id; /** Fragment identifier, or 0. */
char *title; /**< Page title, never 0. */
};
 
/** A node in the history tree. */
struct history_entry {
struct history_page page;
struct history_entry *back; /**< Parent. */
struct history_entry *next; /**< Next sibling. */
struct history_entry *forward; /**< First child. */
struct history_entry *forward_pref; /**< Child in direction of
current entry. */
struct history_entry *forward_last; /**< Last child. */
unsigned int children; /**< Number of children. */
int x; /**< Position of node. */
int y; /**< Position of node. */
struct bitmap *bitmap; /**< Thumbnail bitmap, or 0. */
};
 
/** History tree for a window. */
struct history {
/** First page in tree (page that window opened with). */
struct history_entry *start;
/** Current position in tree. */
struct history_entry *current;
/** Width of layout. */
int width;
/** Height of layout. */
int height;
};
 
static struct history_entry *history_clone_entry(struct history *history,
struct history_entry *entry);
static void history_free_entry(struct history_entry *entry);
static void history_layout(struct history *history);
static int history_layout_subtree(struct history *history,
struct history_entry *entry, int x, int y, bool shuffle);
static bool history_redraw_entry(struct history *history,
struct history_entry *entry,
int x0, int y0, int x1, int y1,
int x, int y, bool clip, const struct redraw_context *ctx);
static struct history_entry *history_find_position(struct history_entry *entry,
int x, int y);
static bool history_enumerate_entry(const struct history *history,
const struct history_entry *entry, history_enumerate_cb cb, void *ud);
 
 
/**
* Create a new history tree for a window.
*
* \return pointer to an opaque history structure, 0 on failure.
*/
 
struct history *history_create(void)
{
struct history *history;
 
history = calloc(1, sizeof *history);
if (!history) {
warn_user("NoMemory", 0);
return 0;
}
history->width = RIGHT_MARGIN / 2;
history->height = BOTTOM_MARGIN / 2;
return history;
}
 
 
/**
* Clone a history tree
*
* \param history opaque history structure, as returned by history_create()
*
* \return pointer to an opaque history structure, 0 on failure.
*/
 
struct history *history_clone(struct history *history)
{
struct history *new_history;
 
if (!history->start)
return history_create();
 
new_history = malloc(sizeof *history);
if (!new_history)
return 0;
memcpy(new_history, history, sizeof *history);
 
new_history->start = history_clone_entry(new_history,
new_history->start);
if (!history->start) {
LOG(("Insufficient memory to clone history"));
warn_user("NoMemory", 0);
history_destroy(new_history);
return 0;
}
 
return new_history;
}
 
 
/**
* Clone a history entry
*
* \param history opaque history structure, as returned by history_create()
* \param start entry to clone
*
* \return a cloned history entry, or 0 on error
*/
 
struct history_entry *history_clone_entry(struct history *history,
struct history_entry *entry)
{
struct history_entry *child;
struct history_entry *new_child;
struct history_entry *prev = NULL;
struct history_entry *new_entry;
 
assert(entry->page.url);
assert(entry->page.title);
 
/* clone the entry */
new_entry = malloc(sizeof *entry);
if (!new_entry)
return 0;
memcpy(new_entry, entry, sizeof *entry);
new_entry->page.url = strdup(entry->page.url);
if (entry->page.frag_id)
new_entry->page.frag_id = strdup(entry->page.frag_id);
new_entry->page.title = strdup(entry->page.title);
if (!new_entry->page.url || !new_entry->page.title ||
((entry->page.frag_id) && (!new_entry->page.frag_id))) {
free(new_entry->page.url);
free(new_entry->page.title);
free(new_entry->page.frag_id);
free(new_entry);
return 0;
}
 
/* update references */
if (history->current == entry)
history->current = new_entry;
 
/* recurse for all children */
for (child = new_entry->forward; child; child = child->next) {
new_child = history_clone_entry(history, child);
if (new_child)
new_child->back = new_entry;
if (prev)
prev->next = new_child;
if (new_entry->forward == child)
new_entry->forward = new_child;
if (new_entry->forward_pref == child)
new_entry->forward_pref = new_child;
if (new_entry->forward_last == child)
new_entry->forward_last = new_child;
if (!new_child)
return 0;
prev = new_child;
}
return new_entry;
}
 
 
/**
* Insert a url into the history tree.
*
* \param history opaque history structure, as returned by history_create()
* \param content content to add to history
* \param frag_id fragment identifier
*
* The page is added after the current entry and becomes current.
*/
 
void history_add(struct history *history, hlcache_handle *content,
const char *frag_id)
{
struct history_entry *entry;
nsurl *nsurl = hlcache_handle_get_url(content);
char *url;
char *title;
struct bitmap *bitmap;
nserror error;
size_t url_len;
 
assert(history);
assert(content);
 
/* allocate space */
entry = malloc(sizeof *entry);
if (entry == NULL)
return;
 
/* TODO: use a nsurl? */
error = nsurl_get(nsurl, NSURL_WITH_FRAGMENT, &url, &url_len);
if (error != NSERROR_OK) {
warn_user("NoMemory", 0);
free(entry);
return;
}
 
title = strdup(content_get_title(content));
if (title == NULL) {
warn_user("NoMemory", 0);
free(url);
free(entry);
return;
}
 
entry->page.url = url;
entry->page.frag_id = frag_id ? strdup(frag_id) : 0;
entry->page.title = title;
entry->back = history->current;
entry->next = 0;
entry->forward = entry->forward_pref = entry->forward_last = 0;
entry->children = 0;
entry->bitmap = 0;
if (history->current) {
if (history->current->forward_last)
history->current->forward_last->next = entry;
else
history->current->forward = entry;
history->current->forward_pref = entry;
history->current->forward_last = entry;
history->current->children++;
} else {
history->start = entry;
}
history->current = entry;
 
/* if we have a thumbnail, don't update until the page has finished
* loading */
bitmap = urldb_get_thumbnail(nsurl);
if (!bitmap) {
bitmap = bitmap_create(WIDTH, HEIGHT,
BITMAP_NEW | BITMAP_CLEAR_MEMORY |
BITMAP_OPAQUE);
if (!bitmap) {
warn_user("NoMemory", 0);
return;
}
if (thumbnail_create(content, bitmap, nsurl) == false) {
/* Thumbnailing failed. Ignore it silently */
bitmap_destroy(bitmap);
bitmap = NULL;
}
}
entry->bitmap = bitmap;
 
history_layout(history);
}
 
 
/**
* Update the thumbnail for the current entry.
*
* \param history opaque history structure, as returned by history_create()
* \param content content for current entry
*/
 
void history_update(struct history *history, hlcache_handle *content)
{
char *title;
 
if (!history || !history->current || !history->current->bitmap)
return;
 
assert(history->current->page.url);
assert(history->current->page.title);
 
title = strdup(content_get_title(content));
if (!title) {
warn_user("NoMemory", 0);
return;
}
 
assert(title);
free(history->current->page.title);
history->current->page.title = title;
 
thumbnail_create(content, history->current->bitmap, NULL);
}
 
 
/**
* Free a history structure.
*
* \param history opaque history structure, as returned by history_create()
*/
 
void history_destroy(struct history *history)
{
if (!history)
return;
history_free_entry(history->start);
free(history);
}
 
 
/**
* Free an entry in the tree recursively.
*/
 
void history_free_entry(struct history_entry *entry)
{
if (!entry)
return;
history_free_entry(entry->forward);
history_free_entry(entry->next);
free(entry->page.url);
if (entry->page.frag_id)
free(entry->page.frag_id);
free(entry->page.title);
free(entry);
}
 
 
/**
* Go back in the history.
*
* \param bw browser window
* \param history history of the window
*/
 
void history_back(struct browser_window *bw, struct history *history)
{
if (!history || !history->current || !history->current->back)
return;
history_go(bw, history, history->current->back, false);
}
 
 
/**
* Go forward in the history.
*
* \param bw browser window
* \param history history of the window
*/
 
void history_forward(struct browser_window *bw, struct history *history)
{
if (!history || !history->current || !history->current->forward_pref)
return;
history_go(bw, history, history->current->forward_pref, false);
}
 
 
/**
* Check whether it is pssible to go back in the history.
*
* \param history history of the window
* \return true if the history can go back, false otherwise
*/
 
bool history_back_available(struct history *history)
{
return (history && history->current && history->current->back);
}
 
 
/**
* Check whether it is pssible to go forwards in the history.
*
* \param history history of the window
* \return true if the history can go forwards, false otherwise
*/
 
bool history_forward_available(struct history *history)
{
return (history && history->current && history->current->forward_pref);
}
 
 
/* Documented in history_core.h */
void history_go(struct browser_window *bw, struct history *history,
struct history_entry *entry, bool new_window)
{
char *url;
struct history_entry *current;
 
// LOG(("%p %p %p", bw, history, entry));
// LOG(("%s %s %s",
// entry->page.url, entry->page.title, entry->page.frag_id));
 
if (entry->page.frag_id) {
url = malloc(strlen(entry->page.url) +
strlen(entry->page.frag_id) + 5);
if (!url) {
warn_user("NoMemory", 0);
return;
}
sprintf(url, "%s#%s", entry->page.url, entry->page.frag_id);
}
else
url = entry->page.url;
 
if (new_window) {
current = history->current;
history->current = entry;
browser_window_create(url, bw, 0, false, false);
history->current = current;
} else {
history->current = entry;
browser_window_go(bw, url, 0, false);
}
 
if (entry->page.frag_id)
free(url);
}
 
 
/**
* Compute node positions.
*
* \param history history to layout
*
* Each node's x and y are filled in.
*/
 
void history_layout(struct history *history)
{
time_t t = time(0);
struct tm *tp = localtime(&t);
bool shuffle = tp->tm_mon == 3 && tp->tm_mday == 1;
 
if (!history)
return;
 
history->width = 0;
if (history->start)
history->height = history_layout_subtree(history,
history->start, RIGHT_MARGIN / 2, BOTTOM_MARGIN / 2,
shuffle);
else
history->height = 0;
if (shuffle) {
history->width = 600 + WIDTH;
history->height = 400 + HEIGHT;
}
history->width += RIGHT_MARGIN / 2;
history->height += BOTTOM_MARGIN / 2;
}
 
 
/**
* Recursively position a subtree.
*
* \param history history being laid out
* \param entry subtree to position
* \param x x position for entry
* \param y smallest available y
* \param shuffle shuffle layout
* \return greatest y used by subtree
*/
 
int history_layout_subtree(struct history *history,
struct history_entry *entry, int x, int y, bool shuffle)
{
struct history_entry *child;
int y1 = y;
 
if (history->width < x + WIDTH)
history->width = x + WIDTH;
 
if (!entry->forward) {
entry->x = x;
entry->y = y;
if (shuffle) {
entry->x = rand() % 600;
entry->y = rand() % 400;
}
return y + HEIGHT;
}
 
/* layout child subtrees below each other */
for (child = entry->forward; child; child = child->next) {
y1 = history_layout_subtree(history, child,
x + WIDTH + RIGHT_MARGIN, y1, shuffle);
if (child->next)
y1 += BOTTOM_MARGIN;
}
 
/* place ourselves in the middle */
entry->x = x;
entry->y = (y + y1) / 2 - HEIGHT / 2;
if (shuffle) {
entry->x = rand() % 600;
entry->y = rand() % 400;
}
 
return y1;
}
 
 
/**
* Get the dimensions of a history.
*
* \param history history to measure
* \param width updated to width
* \param height updated to height
*/
 
void history_size(struct history *history, int *width, int *height)
{
*width = history->width;
*height = history->height;
}
 
 
/**
* Redraw a history.
*
* \param history history to render
* \param ctx current redraw context
*/
 
bool history_redraw(struct history *history, const struct redraw_context *ctx)
{
if (!history->start)
return true;
return history_redraw_entry(history, history->start, 0, 0, 0, 0, 0, 0,
false, ctx);
}
 
/**
* Redraw part of a history.
*
* \param history history to render
* \param x0 left X co-ordinate of redraw area
* \param y0 top Y co-ordinate of redraw area
* \param x1 right X co-ordinate of redraw area
* \param y1 lower Y co-ordinate of redraw area
* \param x start X co-ordinate on plot canvas
* \param y start Y co-ordinate on plot canvas
* \param ctx current redraw context
*/
 
bool history_redraw_rectangle(struct history *history,
int x0, int y0, int x1, int y1,
int x, int y, const struct redraw_context *ctx)
{
if (!history->start)
return true;
return history_redraw_entry(history, history->start,
x0, y0, x1, y1, x, y, true, ctx);
}
 
/**
* Recursively redraw a history_entry.
*
* \param history history containing the entry
* \param history_entry entry to render
* \param ctx current redraw context
*/
 
bool history_redraw_entry(struct history *history,
struct history_entry *entry,
int x0, int y0, int x1, int y1,
int x, int y, bool clip, const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
size_t char_offset;
int actual_x;
struct history_entry *child;
colour c = entry == history->current ? HISTORY_COLOUR_SELECTED : HISTORY_COLOUR_FOREGROUND;
int tailsize = 5;
int xoffset = x - x0;
int yoffset = y - y0;
plot_style_t pstyle_history_rect = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = c,
.stroke_width = entry == history->current ? 3 : 1,
};
plot_font_style_t fstyle = *plot_style_font;
 
if (clip) {
struct rect rect;
rect.x0 = x0 + xoffset;
rect.y0 = y0 + yoffset;
rect.x1 = x1 + xoffset;
rect.y1 = y1 + yoffset;
if(!plot->clip(&rect))
return false;
}
 
if (!plot->bitmap(entry->x + xoffset, entry->y + yoffset, WIDTH, HEIGHT,
entry->bitmap, 0xffffff, 0))
return false;
if (!plot->rectangle(entry->x - 1 + xoffset,
entry->y - 1 + yoffset,
entry->x + xoffset + WIDTH,
entry->y + yoffset + HEIGHT,
&pstyle_history_rect))
return false;
 
if (!nsfont.font_position_in_string(plot_style_font, entry->page.title,
strlen(entry->page.title), WIDTH,
&char_offset, &actual_x))
return false;
 
fstyle.background = HISTORY_COLOUR_BACKGROUND;
fstyle.foreground = c;
fstyle.weight = entry == history->current ? 900 : 400;
 
if (!plot->text(entry->x + xoffset, entry->y + HEIGHT + 12 + yoffset,
entry->page.title, char_offset, &fstyle))
return false;
 
for (child = entry->forward; child; child = child->next) {
if (!plot->line(entry->x + WIDTH + xoffset,
entry->y + HEIGHT / 2 + yoffset,
entry->x + WIDTH + tailsize + xoffset,
entry->y + HEIGHT / 2 + yoffset,
plot_style_stroke_history))
return false;
if (!plot->line(entry->x + WIDTH + tailsize + xoffset,
entry->y + HEIGHT / 2 + yoffset,
child->x - tailsize +xoffset,
child->y + HEIGHT / 2 + yoffset,
plot_style_stroke_history))
return false;
if (!plot->line(child->x - tailsize + xoffset,
child->y + HEIGHT / 2 + yoffset,
child->x + xoffset, child->y + HEIGHT / 2 + yoffset,
plot_style_stroke_history))
return false;
if (!history_redraw_entry(history, child, x0, y0, x1, y1, x, y,
clip, ctx))
return false;
}
 
return true;
}
 
 
/**
* Handle a mouse click in a history.
*
* \param bw browser window containing history
* \param history history that was clicked in
* \param x click coordinate
* \param y click coordinate
* \param new_window open a new window instead of using bw
* \return true if action was taken, false if click was not on an entry
*/
 
bool history_click(struct browser_window *bw, struct history *history,
int x, int y, bool new_window)
{
struct history_entry *entry;
 
entry = history_find_position(history->start, x, y);
if (!entry)
return false;
if (entry == history->current)
return false;
 
history_go(bw, history, entry, new_window);
 
return true;
}
 
 
/**
* Determine the URL of the entry at a position.
*
* \param history history to search
* \param x coordinate
* \param y coordinate
* \return URL, or 0 if no entry at (x, y)
*/
 
const char *history_position_url(struct history *history, int x, int y)
{
struct history_entry *entry;
 
entry = history_find_position(history->start, x, y);
if (!entry)
return 0;
 
return entry->page.url;
}
 
 
/**
* Find the history entry at a position.
*
* \param entry entry to search from
* \param x coordinate
* \param y coordinate
* \return an entry if found, 0 if none
*/
 
struct history_entry *history_find_position(struct history_entry *entry,
int x, int y)
{
struct history_entry *child;
struct history_entry *found;
 
if (!entry)
return 0;
 
if (entry->x <= x && x <= entry->x + WIDTH &&
entry->y <= y && y <= entry->y + HEIGHT)
return entry;
 
for (child = entry->forward; child; child = child->next) {
found = history_find_position(child, x, y);
if (found)
return found;
}
 
return 0;
}
 
/* Documented in history_core.h */
void history_enumerate_forward(struct history *history,
history_enumerate_cb cb, void *user_data)
{
struct history_entry *entry;
if (history == NULL || history->current == NULL) return;
for (entry = history->current->forward_pref; entry != NULL; entry = entry->forward_pref) {
if (!cb(history, entry->x, entry->y, entry->x + WIDTH,
entry->y + HEIGHT, entry, user_data))
break;
}
}
 
/* Documented in history_core.h */
void history_enumerate_back(struct history *history,
history_enumerate_cb cb, void *user_data)
{
struct history_entry *entry;
if (history == NULL || history->current == NULL) return;
for (entry = history->current->back; entry != NULL; entry = entry->back) {
if (!cb(history, entry->x, entry->y, entry->x + WIDTH,
entry->y + HEIGHT, entry, user_data))
break;
}
}
 
/* Documented in history_core.h */
void history_enumerate(const struct history *history, history_enumerate_cb cb,
void *user_data)
{
history_enumerate_entry(history, history->start, cb, user_data);
}
 
/**
* Enumerate subentries in history
* See also history_enumerate()
*
* \param history history to enumerate
* \param entry entry to start enumeration at
* \param cb callback function
* \param ud context pointer passed to cb
* \return true to continue enumeration, false to cancel
*/
static bool history_enumerate_entry(const struct history *history,
const struct history_entry *entry, history_enumerate_cb cb, void *ud)
{
const struct history_entry *child;
if (!cb(history, entry->x, entry->y, entry->x + WIDTH, entry->y + HEIGHT,
entry, ud)) return false;
for (child = entry->forward; child; child = child->next) {
if (!history_enumerate_entry(history, child, cb, ud))
return false;
}
return true;
}
 
/* Documented in history_core.h */
const char *history_entry_get_url(const struct history_entry *entry)
{
return entry->page.url;
}
 
/* Documented in history_core.h */
const char *history_entry_get_fragment_id(const struct history_entry *entry)
{
return entry->page.frag_id;
}
 
/* Documented in history_core.h */
const char *history_entry_get_title(const struct history_entry *entry)
{
return entry->page.title;
}
/programs/network/netsurf/netsurf/desktop/history_core.h
0,0 → 1,130
/*
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Browser history tree (interface).
*/
 
#ifndef _NETSURF_DESKTOP_HISTORY_H_
#define _NETSURF_DESKTOP_HISTORY_H_
 
#include <stdbool.h>
 
struct hlcache_handle;
struct history;
struct browser_window;
struct history_entry;
struct redraw_context;
 
struct history *history_create(void);
struct history *history_clone(struct history *history);
void history_add(struct history *history, struct hlcache_handle *content,
const char *frag_id);
void history_update(struct history *history, struct hlcache_handle *content);
void history_destroy(struct history *history);
void history_back(struct browser_window *bw, struct history *history);
void history_forward(struct browser_window *bw, struct history *history);
bool history_back_available(struct history *history);
bool history_forward_available(struct history *history);
void history_size(struct history *history, int *width, int *height);
bool history_redraw(struct history *history, const struct redraw_context *ctx);
bool history_redraw_rectangle(struct history *history,
int x0, int y0, int x1, int y1, int x, int y,
const struct redraw_context *ctx);
bool history_click(struct browser_window *bw, struct history *history,
int x, int y, bool new_window);
const char *history_position_url(struct history *history, int x, int y);
 
/**
* Callback function type for history enumeration
*
* \param history history being enumerated
* \param x0, y0, x1, y1 Coordinates of entry in history tree view
* \param entry Current history entry
* \return true to continue enumeration, false to cancel enumeration
*/
typedef bool (*history_enumerate_cb)(const struct history *history, int x0, int y0,
int x1, int y1,
const struct history_entry *entry, void *user_data);
 
/**
* Enumerate all entries in the history.
* Do not change the history while it is being enumerated.
*
* \param history history to enumerate
* \param cb callback function
* \param user_data context pointer passed to cb
*/
void history_enumerate(const struct history *history, history_enumerate_cb cb, void *user_data);
 
/**
* Enumerate all entries that will be reached by the 'forward' button
*
* \param history The history object to enumerate in
* \param cb The callback function
* \param user_data Data passed to the callback
*/
void history_enumerate_forward( struct history *history,
history_enumerate_cb cb, void *user_data );
 
/**
* Enumerate all entries that will be reached by the 'back' button
*
* \param history The history object to enumerate in
* \param cb The callback function
* \param user_data Data passed to the callback
*/
void history_enumerate_back( struct history *history,
history_enumerate_cb cb, void *user_data );
 
/**
* Returns the URL to a history entry
*
* \param entry the history entry to retrieve the URL from
* \return the URL
*/
const char *history_entry_get_url(const struct history_entry *entry);
 
/**
* Returns the URL to a history entry
*
* \param entry the history entry to retrieve the fragment id from
* \return the fragment id
*/
const char *history_entry_get_fragment_id(const struct history_entry *entry);
 
/**
* Returns the title of a history entry
*
* \param entry the history entry to retrieve the title from
* \return the title
*/
const char *history_entry_get_title(const struct history_entry *entry);
 
/**
* Open a history entry in the specified browser window
*
* \param bw browser window
* \param history history containing entry
* \param entry entry to open
* \param new_window open entry in new window
*/
void history_go(struct browser_window *bw, struct history *history,
struct history_entry *entry, bool new_window);
 
#endif
/programs/network/netsurf/netsurf/desktop/history_global_core.c
0,0 → 1,459
/*
* Copyright 2005 Richard Wilson <info@tinct.net>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
 
#include <stdlib.h>
 
#include "content/content.h"
#include "content/hlcache.h"
#include "content/urldb.h"
#include "desktop/browser.h"
#include "desktop/history_global_core.h"
#include "desktop/plotters.h"
#include "desktop/tree.h"
#include "desktop/tree_url_node.h"
#include "utils/messages.h"
#include "utils/utils.h"
#include "utils/log.h"
 
#define MAXIMUM_BASE_NODES 16
#define GLOBAL_HISTORY_RECENT_URLS 16
#define URL_CHUNK_LENGTH 512
 
static struct node *global_history_base_node[MAXIMUM_BASE_NODES];
static int global_history_base_node_time[MAXIMUM_BASE_NODES];
static int global_history_base_node_count = 0;
 
static bool global_history_initialised;
 
static struct tree *global_history_tree;
static struct node *global_history_tree_root;
 
static hlcache_handle *folder_icon;
 
static const char *const weekday_msg_name [] =
{
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
};
 
/**
* Find an entry in the global history
*
* \param url The URL to find
* \return Pointer to node, or NULL if not found
*/
static struct node *history_global_find(const char *url)
{
int i;
struct node *node;
const char *text;
 
for (i = 0; i < global_history_base_node_count; i++) {
if (!tree_node_is_deleted(global_history_base_node[i])) {
node = tree_node_get_child(global_history_base_node[i]);
for (; node != NULL; node = tree_node_get_next(node)) {
text = tree_url_node_get_url(node);
if ((text != NULL) && !strcmp(url, text))
return node;
}
}
}
return NULL;
}
 
/**
* Internal routine to actually perform global history addition
*
* \param url The URL to add
* \param data URL data associated with URL
* \return true (for urldb_iterate_entries)
*/
static bool global_history_add_internal(nsurl *url, const struct url_data *data)
{
int i, j;
struct node *parent = NULL;
struct node *link;
struct node *node;
bool before = false;
int visit_date;
 
assert((url != NULL) && (data != NULL));
 
visit_date = data->last_visit;
 
/* find parent node */
for (i = 0; i < global_history_base_node_count; i++) {
if (global_history_base_node_time[i] <= visit_date) {
parent = global_history_base_node[i];
break;
}
}
 
/* the entry is too old to care about */
if (parent == NULL)
return true;
 
if (tree_node_is_deleted(parent)) {
/* parent was deleted, so find place to insert it */
link = global_history_tree_root;
 
for (j = global_history_base_node_count - 1; j >= 0; j--) {
if (!tree_node_is_deleted(global_history_base_node[j]) &&
global_history_base_node_time[j] >
global_history_base_node_time[i]) {
link = global_history_base_node[j];
before = true;
break;
}
}
 
tree_set_node_selected(global_history_tree,
parent, true, false);
tree_set_node_expanded(global_history_tree,
parent, false, true, true);
tree_link_node(global_history_tree, link, parent, before);
}
 
/* find any previous occurance */
if (global_history_initialised == false) {
node = history_global_find(nsurl_access(url));
if (node != NULL) {
tree_update_URL_node(global_history_tree,
node, url, data);
tree_delink_node(global_history_tree, node);
tree_link_node(global_history_tree, parent, node,
false);
return true;
}
}
 
/* Add the node at the bottom */
node = tree_create_URL_node_readonly(global_history_tree,
parent, url, data,
tree_url_node_callback, NULL);
 
return true;
}
 
static node_callback_resp
history_global_node_callback(void *user_data,
struct node_msg_data *msg_data)
{
if (msg_data->msg == NODE_DELETE_ELEMENT_IMG)
return NODE_CALLBACK_HANDLED;
return NODE_CALLBACK_NOT_HANDLED;
}
 
/**
* Initialises a single grouping node for the global history tree.
*
* \return false on memory exhaustion, true otherwise
*/
static bool history_global_initialise_node(const char *title,
time_t base, int days_back)
{
struct tm *full_time;
char *buffer;
struct node *node;
 
base += days_back * 60 * 60 * 24;
if (title == NULL) {
full_time = localtime(&base);
buffer = strdup(messages_get(weekday_msg_name[full_time->tm_wday]));
} else {
buffer = strdup(title);
}
 
if (buffer == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
return false;
}
 
node = tree_create_folder_node(NULL, NULL, buffer,
false, true, true);
if (node == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
free(buffer);
return false;
}
if (folder_icon != NULL)
tree_set_node_icon(global_history_tree, node, folder_icon);
tree_set_node_user_callback(node, history_global_node_callback, NULL);
 
global_history_base_node[global_history_base_node_count] = node;
global_history_base_node_time[global_history_base_node_count] = base;
global_history_base_node_count++;
 
return true;
}
 
/**
* Initialises the grouping nodes(Today, Yesterday etc.) for the global history
* tree.
*
* \return false on memory exhaustion, true otherwise
*/
static bool history_global_initialise_nodes(void)
{
struct tm *full_time;
time_t t;
int weekday;
int i;
 
/* get the current time */
t = time(NULL);
if (t == -1) {
LOG(("time info unaviable"));
return false;
}
 
/* get the time at the start of today */
full_time = localtime(&t);
weekday = full_time->tm_wday;
full_time->tm_sec = 0;
full_time->tm_min = 0;
full_time->tm_hour = 0;
t = mktime(full_time);
if (t == -1) {
LOG(("mktime failed"));
return false;
}
 
history_global_initialise_node(messages_get("DateToday"), t, 0);
if (weekday > 0)
if (!history_global_initialise_node(
messages_get("DateYesterday"), t, -1))
return false;
for (i = 2; i <= weekday; i++)
if (!history_global_initialise_node(NULL, t, -i))
return false;
 
if (!history_global_initialise_node(messages_get("Date1Week"),
t, -weekday - 7))
return false;
if (!history_global_initialise_node(messages_get("Date2Week"),
t, -weekday - 14))
return false;
if (!history_global_initialise_node(messages_get("Date3Week"),
t, -weekday - 21))
return false;
 
return true;
}
 
/**
* Initialises the global history tree.
*
* \param data user data for the callbacks
* \param start_redraw callback function called before every redraw
* \param end_redraw callback function called after every redraw
* \return true on success, false on memory exhaustion
*/
bool history_global_initialise(struct tree *tree, const char* folder_icon_name)
{
folder_icon = tree_load_icon(folder_icon_name);
tree_url_node_init(folder_icon_name);
 
if (tree == NULL)
return false;
 
global_history_tree = tree;
global_history_tree_root = tree_get_root(global_history_tree);
 
if (!history_global_initialise_nodes())
return false;
 
LOG(("Building history tree"));
 
global_history_initialised = true;
urldb_iterate_entries(global_history_add_internal);
global_history_initialised = false;
tree_set_node_expanded(global_history_tree, global_history_tree_root,
false, true, true);
LOG(("History tree built"));
return true;
}
 
 
/**
* Get flags with which the global history tree should be created;
*
* \return the flags
*/
unsigned int history_global_get_tree_flags(void)
{
return TREE_NO_FLAGS;
}
 
 
/**
* Deletes the global history tree.
*/
void history_global_cleanup(void)
{
hlcache_handle_release(folder_icon);
tree_url_node_cleanup();
}
 
 
/**
* Adds a url to the global history.
*
* \param url the url to be added
*/
void global_history_add(nsurl *url)
{
const struct url_data *data;
 
data = urldb_get_url_data(url);
if (data == NULL)
return;
 
global_history_add_internal(url, data);
}
 
 
/* Actions to be connected to front end specific toolbars */
 
/**
* Save the global history in a human-readable form under the given location.
*
* \param path the path where the history will be saved
*/
bool history_global_export(const char *path)
{
return tree_urlfile_save(global_history_tree, path, "NetSurf history");
}
 
/**
* Delete nodes which are currently selected.
*/
void history_global_delete_selected(void)
{
tree_delete_selected_nodes(global_history_tree,
global_history_tree_root);
}
 
/**
* Delete all nodes.
*/
void history_global_delete_all(void)
{
bool redraw_needed = tree_get_redraw(global_history_tree);
if (redraw_needed)
tree_set_redraw(global_history_tree, false);
 
tree_set_node_selected(global_history_tree, global_history_tree_root,
true, true);
tree_delete_selected_nodes(global_history_tree,
global_history_tree_root);
 
if (redraw_needed)
tree_set_redraw(global_history_tree, true);
}
 
/**
* Select all nodes in the tree.
*/
void history_global_select_all(void)
{
tree_set_node_selected(global_history_tree, global_history_tree_root,
true, true);
}
 
/**
* Unselect all nodes.
*/
void history_global_clear_selection(void)
{
tree_set_node_selected(global_history_tree, global_history_tree_root,
true, false);
}
 
/**
* Expand grouping folders and history entries.
*/
void history_global_expand_all(void)
{
tree_set_node_expanded(global_history_tree, global_history_tree_root,
true, true, true);
}
 
/**
* Expand grouping folders only.
*/
void history_global_expand_directories(void)
{
tree_set_node_expanded(global_history_tree, global_history_tree_root,
true, true, false);
}
 
/**
* Expand history entries only.
*/
void history_global_expand_addresses(void)
{
tree_set_node_expanded(global_history_tree, global_history_tree_root,
true, false, true);
}
 
/**
* Collapse grouping folders and history entries.
*/
void history_global_collapse_all(void)
{
tree_set_node_expanded(global_history_tree, global_history_tree_root,
false, true, true);
}
 
/**
* Collapse grouping folders only.
*/
void history_global_collapse_directories(void)
{
tree_set_node_expanded(global_history_tree, global_history_tree_root,
false, true, false);
}
 
/**
* Collapse history entries only.
*/
void history_global_collapse_addresses(void)
{
tree_set_node_expanded(global_history_tree, global_history_tree_root,
false, false, true);
}
 
/**
* Open the selected entries in seperate browser windows.
*
* \param tabs open multiple entries in tabs in the new window
*/
void history_global_launch_selected(bool tabs)
{
tree_launch_selected(global_history_tree, tabs);
}
/programs/network/netsurf/netsurf/desktop/history_global_core.h
0,0 → 1,44
/*
* Copyright 2005 Richard Wilson <info@tinct.net>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NETSURF_DESKTOP_HISTORY_GLOBAL_H_
#define _NETSURF_DESKTOP_HISTORY_GLOBAL_H_
 
#include <stdbool.h>
 
#include "desktop/tree.h"
 
bool history_global_initialise(struct tree *tree, const char* folder_icon_name);
unsigned int history_global_get_tree_flags(void);
void history_global_cleanup(void);
 
bool history_global_export(const char *path);
void history_global_delete_selected(void);
void history_global_delete_all(void);
void history_global_select_all(void);
void history_global_clear_selection(void);
void history_global_expand_all(void);
void history_global_expand_directories(void);
void history_global_expand_addresses(void);
void history_global_collapse_all(void);
void history_global_collapse_directories(void);
void history_global_collapse_addresses(void);
void history_global_launch_selected(bool tabs);
 
#endif
/programs/network/netsurf/netsurf/desktop/hotlist.c
0,0 → 1,528
/*
* Copyright 2004, 2005 Richard Wilson <info@tinct.net>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <ctype.h>
#include <stdlib.h>
 
#include "content/content.h"
#include "content/hlcache.h"
#include "content/urldb.h"
#include "desktop/browser.h"
#include "desktop/hotlist.h"
#include "desktop/plotters.h"
#include "desktop/tree.h"
#include "desktop/tree_url_node.h"
 
#include "utils/messages.h"
#include "utils/utils.h"
#include "utils/log.h"
 
#define URL_CHUNK_LENGTH 512
 
static struct tree *hotlist_tree;
static struct node *hotlist_tree_root;
 
static bool creating_node;
static hlcache_handle *folder_icon;
 
static const struct {
const char *url;
const char *msg_key;
} hotlist_default_entries[] = {
{ "http://www.netsurf-browser.org/", "HotlistHomepage" },
{ "http://www.netsurf-browser.org/downloads/riscos/testbuilds",
"HotlistTestBuild" },
{ "http://www.netsurf-browser.org/documentation",
"HotlistDocumentation" },
{ "http://sourceforge.net/tracker/?atid=464312&group_id=51719",
"HotlistBugTracker" },
{ "http://sourceforge.net/tracker/?atid=464315&group_id=51719",
"HotlistFeatureRequest" }
};
#define HOTLIST_ENTRIES_COUNT (sizeof(hotlist_default_entries) / sizeof(hotlist_default_entries[0]))
 
static node_callback_resp hotlist_node_callback(void *user_data,
struct node_msg_data *msg_data)
{
struct node *node = msg_data->node;
const char *text;
char *norm_text;
bool is_folder = tree_node_is_folder(node);
bool cancelled = false;
 
switch (msg_data->msg) {
case NODE_ELEMENT_EDIT_CANCELLED:
cancelled = true;
/* fall through */
case NODE_ELEMENT_EDIT_FINISHED:
if (creating_node && !cancelled &&
(is_folder == false) &&
(msg_data->flag == TREE_ELEMENT_TITLE)) {
tree_url_node_edit_url(hotlist_tree, node);
} else {
creating_node = false;
}
return NODE_CALLBACK_HANDLED;
 
case NODE_ELEMENT_EDIT_FINISHING:
if (creating_node && (is_folder == false))
return tree_url_node_callback(hotlist_tree, msg_data);
 
if (is_folder == true) {
text = msg_data->data.text;
while (isspace(*text))
text++;
norm_text = strdup(text);
if (norm_text == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
return NODE_CALLBACK_REJECT;
}
/* don't allow zero length entry text, return false */
if (norm_text[0] == '\0') {
warn_user("NoNameError", 0);
msg_data->data.text = NULL;
return NODE_CALLBACK_CONTINUE;
}
msg_data->data.text = norm_text;
}
break;
 
case NODE_DELETE_ELEMENT_IMG:
return NODE_CALLBACK_HANDLED;
 
default:
if (is_folder == false)
return tree_url_node_callback(hotlist_tree, msg_data);
}
 
return NODE_CALLBACK_NOT_HANDLED;
}
 
/* exported interface documented in hotlist.h */
bool hotlist_initialise(struct tree *tree, const char *hotlist_path,
const char* folder_icon_name)
{
struct node *node;
const struct url_data *url_data;
char *name;
int hlst_loop;
 
/* Either load or create a hotlist */
 
creating_node = false;
 
folder_icon = tree_load_icon(folder_icon_name);
 
tree_url_node_init(folder_icon_name);
 
if (tree == NULL)
return false;
 
hotlist_tree = tree;
hotlist_tree_root = tree_get_root(hotlist_tree);
 
if (tree_urlfile_load(hotlist_path, hotlist_tree,
hotlist_node_callback, NULL)) {
return true;
}
 
 
/* failed to load hotlist file, use default list */
name = strdup("NetSurf");
if (name == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
return false;
}
node = tree_create_folder_node(hotlist_tree, hotlist_tree_root,
name, true, false, false);
if (node == NULL) {
free(name);
return false;
}
 
tree_set_node_user_callback(node, hotlist_node_callback, NULL);
tree_set_node_icon(hotlist_tree, node, folder_icon);
 
for (hlst_loop = 0; hlst_loop != HOTLIST_ENTRIES_COUNT; hlst_loop++) {
nsurl *url;
if (nsurl_create(hotlist_default_entries[hlst_loop].url,
&url) != NSERROR_OK) {
return false;
}
url_data = urldb_get_url_data(url);
if (url_data == NULL) {
urldb_add_url(url);
urldb_set_url_persistence(url, true);
url_data = urldb_get_url_data(url);
}
if (url_data != NULL) {
tree_create_URL_node(hotlist_tree, node, url,
messages_get(hotlist_default_entries[hlst_loop].msg_key),
hotlist_node_callback, NULL);
tree_update_URL_node(hotlist_tree, node, url, url_data);
}
nsurl_unref(url);
}
 
return true;
}
 
 
/**
* Get flags with which the hotlist tree should be created;
*
* \return the flags
*/
unsigned int hotlist_get_tree_flags(void)
{
return TREE_MOVABLE;
}
 
 
/**
* Deletes the global history tree and saves the hotlist.
* \param hotlist_path the path where the hotlist should be saved
*/
void hotlist_cleanup(const char *hotlist_path)
{
hotlist_export(hotlist_path);
hlcache_handle_release(folder_icon);
tree_url_node_cleanup();
}
 
 
/**
* Informs the hotlist that some content has been visited. Internal procedure.
*
* \param content the content visited
* \param node the node to update siblings and children of
*/
static void hotlist_visited_internal(hlcache_handle *content, struct node *node)
{
struct node *child;
const char *text;
const char *url;
nsurl *nsurl;
 
if (content == NULL ||
hlcache_handle_get_url(content) == NULL ||
hotlist_tree == NULL)
return;
 
nsurl = hlcache_handle_get_url(content);
url = nsurl_access(nsurl);
 
for (; node; node = tree_node_get_next(node)) {
if (!tree_node_is_folder(node)) {
text = tree_url_node_get_url(node);
if (strcmp(text, url) == 0) {
tree_update_URL_node(hotlist_tree, node,
nsurl, NULL);
}
}
child = tree_node_get_child(node);
if (child != NULL) {
hotlist_visited_internal(content, child);
}
}
}
 
/**
* Informs the hotlist that some content has been visited
*
* \param content the content visited
*/
void hotlist_visited(hlcache_handle *content)
{
if (hotlist_tree != NULL) {
hotlist_visited_internal(content, tree_get_root(hotlist_tree));
}
}
 
/**
* Save the hotlist in a human-readable form under the given location.
*
* \param path the path where the hotlist will be saved
*/
bool hotlist_export(const char *path)
{
return tree_urlfile_save(hotlist_tree, path, "NetSurf hotlist");
}
 
/**
* Edit the node which is currently selected. Works only if one node is
* selected.
*/
void hotlist_edit_selected(void)
{
struct node *node;
struct node_element *element;
 
node = tree_get_selected_node(hotlist_tree_root);
 
if (node != NULL) {
creating_node = true;
element = tree_node_find_element(node, TREE_ELEMENT_TITLE, NULL);
tree_start_edit(hotlist_tree, element);
}
}
 
/**
* Delete nodes which are currently selected.
*/
void hotlist_delete_selected(void)
{
tree_delete_selected_nodes(hotlist_tree, hotlist_tree_root);
}
 
/**
* Select all nodes in the tree.
*/
void hotlist_select_all(void)
{
tree_set_node_selected(hotlist_tree, hotlist_tree_root,
true, true);
}
 
/**
* Unselect all nodes.
*/
void hotlist_clear_selection(void)
{
tree_set_node_selected(hotlist_tree, hotlist_tree_root,
true, false);
}
 
/**
* Expand grouping folders and history entries.
*/
void hotlist_expand_all(void)
{
tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
true, true, true);
}
 
/**
* Expand grouping folders only.
*/
void hotlist_expand_directories(void)
{
tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
true, true, false);
}
 
/**
* Expand history entries only.
*/
void hotlist_expand_addresses(void)
{
tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
true, false, true);
}
 
/**
* Collapse grouping folders and history entries.
*/
void hotlist_collapse_all(void)
{
tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
false, true, true);
}
 
/**
* Collapse grouping folders only.
*/
void hotlist_collapse_directories(void)
{
tree_set_node_expanded(hotlist_tree, hotlist_tree_root,
false, true, false);
}
 
/**
* Collapse history entries only.
*/
void hotlist_collapse_addresses(void)
{
tree_set_node_expanded(hotlist_tree,
hotlist_tree_root, false, false, true);
}
 
/**
* Add a folder node.
*
* \param selected create the folder in the currently-selected node
*/
void hotlist_add_folder(bool selected)
{
struct node *node, *parent = NULL;
struct node_element *element;
char *title = strdup("Untitled");
 
if (title == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
return;
}
creating_node = true;
 
if (selected == true) {
parent = tree_get_selected_node(tree_get_root(hotlist_tree));
if (parent && (tree_node_is_folder(parent) == false)) {
parent = tree_node_get_parent(parent);
}
}
 
if (parent == NULL) {
parent = tree_get_default_folder_node(hotlist_tree);
}
 
node = tree_create_folder_node(hotlist_tree, parent, title,
true, false, false);
if (node == NULL) {
free(title);
return;
}
tree_set_node_user_callback(node, hotlist_node_callback, NULL);
tree_set_node_icon(hotlist_tree, node, folder_icon);
element = tree_node_find_element(node, TREE_ELEMENT_TITLE, NULL);
tree_start_edit(hotlist_tree, element);
}
 
/**
* Add an entry node.
*
* \param selected add the entry in the currently-selected node
*/
void hotlist_add_entry(bool selected)
{
struct node *node;
struct node *parent = NULL;
nsurl *url;
creating_node = true;
 
if (selected == true) {
parent = tree_get_selected_node(tree_get_root(hotlist_tree));
if (parent && (tree_node_is_folder(parent) == false)) {
parent = tree_node_get_parent(parent);
}
}
 
if (parent == NULL) {
parent = tree_get_default_folder_node(hotlist_tree);
}
 
if (nsurl_create("http://netsurf-browser.org/", &url) != NSERROR_OK)
return;
node = tree_create_URL_node(hotlist_tree, parent, url, "Untitled",
hotlist_node_callback, NULL);
 
nsurl_unref(url);
 
if (node == NULL)
return;
tree_set_node_user_callback(node, hotlist_node_callback, NULL);
tree_url_node_edit_title(hotlist_tree, node);
}
 
/**
* Adds the currently viewed page to the hotlist
*/
void hotlist_add_page(const char *url)
{
const struct url_data *data;
struct node *node, *parent;
nsurl *nsurl;
 
if (url == NULL)
return;
 
if (nsurl_create(url, &nsurl) != NSERROR_OK)
return;
 
data = urldb_get_url_data(nsurl);
if (data == NULL)
return;
 
parent = tree_get_default_folder_node(hotlist_tree);
node = tree_create_URL_node(hotlist_tree, parent, nsurl, NULL,
hotlist_node_callback, NULL);
tree_update_URL_node(hotlist_tree, node, nsurl, data);
nsurl_unref(nsurl);
}
 
/**
* Adds the currently viewed page to the hotlist at the given co-ordinates
* \param url url of the page
* \param x X cooridinate with respect to tree origin
* \param y Y cooridinate with respect to tree origin
*/
void hotlist_add_page_xy(const char *url, int x, int y)
{
const struct url_data *data;
struct node *link, *node;
bool before;
nsurl *nsurl;
 
if (url == NULL)
return;
 
if (nsurl_create(url, &nsurl) != NSERROR_OK)
return;
 
data = urldb_get_url_data(nsurl);
if (data == NULL) {
urldb_add_url(nsurl);
urldb_set_url_persistence(nsurl, true);
data = urldb_get_url_data(nsurl);
}
if (data != NULL) {
link = tree_get_link_details(hotlist_tree, x, y, &before);
node = tree_create_URL_node(NULL, NULL, nsurl,
NULL, hotlist_node_callback, NULL);
tree_link_node(hotlist_tree, link, node, before);
}
nsurl_unref(nsurl);
}
 
/**
* Open the selected entries in separate browser windows.
*
* \param tabs open multiple entries in tabs in the new window
*/
void hotlist_launch_selected(bool tabs)
{
tree_launch_selected(hotlist_tree, tabs);
}
 
/**
* Set the hotlist's default folder to the selected node.
*
* \param clear reset the default to tree root
*/
bool hotlist_set_default_folder(bool clear)
{
if (clear == true) {
tree_clear_default_folder_node(hotlist_tree);
return true;
} else {
return tree_set_default_folder_node(hotlist_tree, NULL);
}
}
/programs/network/netsurf/netsurf/desktop/hotlist.h
0,0 → 1,62
/*
* Copyright 2004, 2005 Richard Wilson <info@tinct.net>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Hotlist (interface).
*/
 
#ifndef _NETSURF_DESKTOP_HOTLIST_H_
#define _NETSURF_DESKTOP_HOTLIST_H_
 
#include <stdbool.h>
 
#include "desktop/tree.h"
 
/**
* Initialise the hotlist from a frontend.
*
* \param tree The tree object which holds the hotlist.
* \param hotlist_path The file path to initialise the hotlist entries from.
* \param folder_icon_name The name to use for folder icons.
*/
bool hotlist_initialise(struct tree *tree, const char *hotlist_path, const char* folder_icon_name);
 
unsigned int hotlist_get_tree_flags(void);
void hotlist_cleanup(const char *hotlist_path);
 
bool hotlist_export(const char *path);
void hotlist_edit_selected(void);
void hotlist_delete_selected(void);
void hotlist_select_all(void);
void hotlist_clear_selection(void);
void hotlist_expand_all(void);
void hotlist_expand_directories(void);
void hotlist_expand_addresses(void);
void hotlist_collapse_all(void);
void hotlist_collapse_directories(void);
void hotlist_collapse_addresses(void);
void hotlist_add_folder(bool selected);
void hotlist_add_entry(bool selected);
void hotlist_add_page(const char *url);
void hotlist_add_page_xy(const char *url, int x, int y);
void hotlist_launch_selected(bool tabs);
bool hotlist_set_default_folder(bool clear);
#endif
/programs/network/netsurf/netsurf/desktop/knockout.c
0,0 → 1,820
/*
* Copyright 2006 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Knockout rendering (implementation).
*
* Knockout rendering is an optimisation which is particularly for
* unaccelerated screen redraw. It tries to avoid plotting the same area more
* than once.
*
* If the object is to plot two overlapping rectangles (one large, one small),
* such as:
*
* +-----------------+
* |#################|
* |####+-------+####|
* |####|:::::::|####|
* |####|:::::::|####|
* |####|:::::::|####|
* |####+-------+####|
* |#################|
* +-----------------+
*
* Without knockout rendering we plot the bottom rectangle and then the top one:
*
* +-----------------+ +-----------------+
* |#################| |#################|
* |#################| |####+-------+####|
* |#################| |####|:::::::|####|
* |#################| and then, |####|:::::::|####|
* |#################| |####|:::::::|####|
* |#################| |####+-------+####|
* |#################| |#################|
* +-----------------+ +-----------------+
*
* With knockout rendering, the bottom rectangle is split up into smaller
* ones and each pixel is just plotted once:
*
* +-----------------+
* |#################|
* +----+-------+----+
* |####|:::::::|####|
* |####|:::::::|####|
* |####|:::::::|####|
* +----+-------+----+
* |#################|
* +-----------------+
*/
 
#include <assert.h>
#include <string.h>
#include "desktop/knockout.h"
#include "desktop/plotters.h"
#include "image/bitmap.h"
#include "utils/log.h"
 
/* Define to enable knockout debug */
#undef KNOCKOUT_DEBUG
 
#define KNOCKOUT_ENTRIES 3072 /* 40 bytes each */
#define KNOCKOUT_BOXES 768 /* 28 bytes each */
#define KNOCKOUT_POLYGONS 3072 /* 4 bytes each */
 
struct knockout_box;
struct knockout_entry;
 
 
static void knockout_calculate(int x0, int y0, int x1, int y1, struct knockout_box *box);
static bool knockout_plot_fill_recursive(struct knockout_box *box, plot_style_t *plot_style);
static bool knockout_plot_bitmap_recursive(struct knockout_box *box,
struct knockout_entry *entry);
 
static bool knockout_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle);
static bool knockout_plot_polygon(const int *p, unsigned int n, const plot_style_t *pstyle);
static bool knockout_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *plot_style);
static bool knockout_plot_clip(const struct rect *clip);
static bool knockout_plot_text(int x, int y, const char *text, size_t length,
const plot_font_style_t *fstyle);
static bool knockout_plot_disc(int x, int y, int radius, const plot_style_t *pstyle);
static bool knockout_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *pstyle);
static bool knockout_plot_bitmap(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bitmap_flags_t flags);
static bool knockout_plot_flush(void);
static bool knockout_plot_group_start(const char *name);
static bool knockout_plot_group_end(void);
static bool knockout_plot_path(const float *p, unsigned int n, colour fill,
float width, colour c, const float transform[6]);
 
 
const struct plotter_table knockout_plotters = {
.rectangle = knockout_plot_rectangle,
.line = knockout_plot_line,
.polygon = knockout_plot_polygon,
.clip = knockout_plot_clip,
.text = knockout_plot_text,
.disc = knockout_plot_disc,
.arc = knockout_plot_arc,
.bitmap = knockout_plot_bitmap,
.group_start = knockout_plot_group_start,
.group_end = knockout_plot_group_end,
.flush = knockout_plot_flush,
.path = knockout_plot_path,
.option_knockout = true,
};
 
 
typedef enum {
KNOCKOUT_PLOT_RECTANGLE,
KNOCKOUT_PLOT_LINE,
KNOCKOUT_PLOT_POLYGON,
KNOCKOUT_PLOT_FILL, /* knockout, knocked out */
KNOCKOUT_PLOT_CLIP,
KNOCKOUT_PLOT_TEXT,
KNOCKOUT_PLOT_DISC,
KNOCKOUT_PLOT_ARC,
KNOCKOUT_PLOT_BITMAP, /* knockout, knocked out */
KNOCKOUT_PLOT_GROUP_START,
KNOCKOUT_PLOT_GROUP_END,
} knockout_type;
 
 
struct knockout_box {
struct rect bbox;
bool deleted; /* box has been deleted, ignore */
struct knockout_box *child;
struct knockout_box *next;
};
 
 
struct knockout_entry {
knockout_type type;
struct knockout_box *box; /* relating series of knockout clips */
union {
struct {
int x0;
int y0;
int x1;
int y1;
plot_style_t plot_style;
} rectangle;
struct {
int x0;
int y0;
int x1;
int y1;
plot_style_t plot_style;
} line;
struct {
int *p;
unsigned int n;
plot_style_t plot_style;
} polygon;
struct {
int x0;
int y0;
int x1;
int y1;
plot_style_t plot_style;
} fill;
struct rect clip;
struct {
int x;
int y;
const char *text;
size_t length;
plot_font_style_t font_style;
} text;
struct {
int x;
int y;
int radius;
plot_style_t plot_style;
} disc;
struct {
int x;
int y;
int radius;
int angle1;
int angle2;
plot_style_t plot_style;
} arc;
struct {
int x;
int y;
int width;
int height;
struct bitmap *bitmap;
colour bg;
bitmap_flags_t flags;
} bitmap;
struct {
const char *name;
} group_start;
} data;
};
 
 
static struct knockout_entry knockout_entries[KNOCKOUT_ENTRIES];
static struct knockout_box knockout_boxes[KNOCKOUT_BOXES];
static int knockout_polygons[KNOCKOUT_POLYGONS];
static int knockout_entry_cur = 0;
static int knockout_box_cur = 0;
static int knockout_polygon_cur = 0;
static struct knockout_box *knockout_list = NULL;
 
static struct plotter_table real_plot;
 
static struct rect clip_cur;
static int nested_depth = 0;
 
/**
* Start a knockout plotting session
*
* \param ctx the redraw context with real plotter table
* \param knk_ctx updated to copy of ctx, with plotter table replaced
* \return true on success, false otherwise
*/
bool knockout_plot_start(const struct redraw_context *ctx,
struct redraw_context *knk_ctx)
{
/* check if we're recursing */
if (nested_depth++ > 0) {
/* we should already have the knockout renderer as default */
assert(ctx->plot->rectangle == knockout_plotters.rectangle);
*knk_ctx = *ctx;
return true;
}
 
/* end any previous sessions */
if (knockout_entry_cur > 0)
knockout_plot_end();
 
/* get copy of real plotter table */
real_plot = *(ctx->plot);
 
/* set up knockout rendering context */
*knk_ctx = *ctx;
knk_ctx->plot = &knockout_plotters;
return true;
}
 
 
/**
* End a knockout plotting session
*
* \return true on success, false otherwise
*/
bool knockout_plot_end(void)
{
/* only output when we've finished any nesting */
if (--nested_depth == 0)
return knockout_plot_flush();
 
assert(nested_depth > 0);
return true;
}
 
 
/**
* Flush the current knockout session to empty the buffers
*
* \return true on success, false otherwise
*/
bool knockout_plot_flush(void)
{
int i;
bool success = true;
struct knockout_box *box;
 
/* debugging information */
#ifdef KNOCKOUT_DEBUG
LOG(("Entries are %i/%i, %i/%i, %i/%i",
knockout_entry_cur, KNOCKOUT_ENTRIES,
knockout_box_cur, KNOCKOUT_BOXES,
knockout_polygon_cur, KNOCKOUT_POLYGONS));
#endif
 
for (i = 0; i < knockout_entry_cur; i++) {
switch (knockout_entries[i].type) {
case KNOCKOUT_PLOT_RECTANGLE:
success &= real_plot.rectangle(
knockout_entries[i].data.rectangle.x0,
knockout_entries[i].data.rectangle.y0,
knockout_entries[i].data.rectangle.x1,
knockout_entries[i].data.rectangle.y1,
&knockout_entries[i].data.rectangle.plot_style);
break;
case KNOCKOUT_PLOT_LINE:
success &= real_plot.line(
knockout_entries[i].data.line.x0,
knockout_entries[i].data.line.y0,
knockout_entries[i].data.line.x1,
knockout_entries[i].data.line.y1,
&knockout_entries[i].data.line.plot_style);
break;
case KNOCKOUT_PLOT_POLYGON:
success &= real_plot.polygon(
knockout_entries[i].data.polygon.p,
knockout_entries[i].data.polygon.n,
&knockout_entries[i].data.polygon.plot_style);
break;
case KNOCKOUT_PLOT_FILL:
box = knockout_entries[i].box->child;
if (box)
success &= knockout_plot_fill_recursive(box,
&knockout_entries[i].data.fill.plot_style);
else if (!knockout_entries[i].box->deleted)
success &= real_plot.rectangle(
knockout_entries[i].data.fill.x0,
knockout_entries[i].data.fill.y0,
knockout_entries[i].data.fill.x1,
knockout_entries[i].data.fill.y1,
&knockout_entries[i].data.fill.plot_style);
break;
case KNOCKOUT_PLOT_CLIP:
success &= real_plot.clip(
&knockout_entries[i].data.clip);
break;
case KNOCKOUT_PLOT_TEXT:
success &= real_plot.text(
knockout_entries[i].data.text.x,
knockout_entries[i].data.text.y,
knockout_entries[i].data.text.text,
knockout_entries[i].data.text.length,
&knockout_entries[i].data.text.font_style);
break;
case KNOCKOUT_PLOT_DISC:
success &= real_plot.disc(
knockout_entries[i].data.disc.x,
knockout_entries[i].data.disc.y,
knockout_entries[i].data.disc.radius,
&knockout_entries[i].data.disc.plot_style);
break;
case KNOCKOUT_PLOT_ARC:
success &= real_plot.arc(
knockout_entries[i].data.arc.x,
knockout_entries[i].data.arc.y,
knockout_entries[i].data.arc.radius,
knockout_entries[i].data.arc.angle1,
knockout_entries[i].data.arc.angle2,
&knockout_entries[i].data.arc.plot_style);
break;
case KNOCKOUT_PLOT_BITMAP:
box = knockout_entries[i].box->child;
if (box) {
success &= knockout_plot_bitmap_recursive(box,
&knockout_entries[i]);
} else if (!knockout_entries[i].box->deleted) {
success &= real_plot.bitmap(
knockout_entries[i].data.
bitmap.x,
knockout_entries[i].data.
bitmap.y,
knockout_entries[i].data.
bitmap.width,
knockout_entries[i].data.
bitmap.height,
knockout_entries[i].data.
bitmap.bitmap,
knockout_entries[i].data.
bitmap.bg,
knockout_entries[i].data.
bitmap.flags);
}
break;
case KNOCKOUT_PLOT_GROUP_START:
success &= real_plot.group_start(
knockout_entries[i].data.group_start.name);
break;
case KNOCKOUT_PLOT_GROUP_END:
success &= real_plot.group_end();
break;
}
}
 
knockout_entry_cur = 0;
knockout_box_cur = 0;
knockout_polygon_cur = 0;
knockout_list = NULL;
 
return success;
}
 
 
/**
* Knockout a section of previous rendering
*
* \param x0 the left edge of the removal box
* \param y0 the bottom edge of the removal box
* \param x1 the right edge of the removal box
* \param y1 the top edge of the removal box
* \param box the parent box set to consider, or NULL for top level
*/
void knockout_calculate(int x0, int y0, int x1, int y1, struct knockout_box *owner)
{
struct knockout_box *box;
struct knockout_box *parent;
struct knockout_box *prev = NULL;
int nx0, ny0, nx1, ny1;
 
if (owner == NULL)
box = knockout_list;
else
box = owner->child;
 
for (parent = box; parent; parent = parent->next) {
/* permanently delink deleted nodes */
if (parent->deleted) {
if (prev) {
/* not the first valid element: just skip future */
prev->next = parent->next;
} else {
if (owner) {
/* first valid element: update child reference */
owner->child = parent->next;
/* have we deleted all child nodes? */
if (!owner->child)
owner->deleted = true;
} else {
/* we are the head of the list */
knockout_list = parent->next;
}
}
continue;
} else {
prev = parent;
}
 
/* get the parent dimensions */
nx0 = parent->bbox.x0;
ny0 = parent->bbox.y0;
nx1 = parent->bbox.x1;
ny1 = parent->bbox.y1;
 
/* reject non-overlapping boxes */
if ((nx0 >= x1) || (nx1 <= x0) || (ny0 >= y1) || (ny1 <= y0))
continue;
 
/* check for a total knockout */
if ((x0 <= nx0) && (x1 >= nx1) && (y0 <= ny0) && (y1 >= ny1)) {
parent->deleted = true;
continue;
}
 
/* has the box been replaced by children? */
if (parent->child) {
knockout_calculate(x0, y0, x1, y1, parent);
} else {
/* we need a maximum of 4 child boxes */
if (knockout_box_cur + 4 >= KNOCKOUT_BOXES) {
knockout_plot_flush();
return;
}
 
/* clip top */
if (y1 < ny1) {
knockout_boxes[knockout_box_cur].bbox.x0 = nx0;
knockout_boxes[knockout_box_cur].bbox.y0 = y1;
knockout_boxes[knockout_box_cur].bbox.x1 = nx1;
knockout_boxes[knockout_box_cur].bbox.y1 = ny1;
knockout_boxes[knockout_box_cur].deleted = false;
knockout_boxes[knockout_box_cur].child = NULL;
knockout_boxes[knockout_box_cur].next = parent->child;
parent->child = &knockout_boxes[knockout_box_cur++];
ny1 = y1;
}
/* clip bottom */
if (y0 > ny0) {
knockout_boxes[knockout_box_cur].bbox.x0 = nx0;
knockout_boxes[knockout_box_cur].bbox.y0 = ny0;
knockout_boxes[knockout_box_cur].bbox.x1 = nx1;
knockout_boxes[knockout_box_cur].bbox.y1 = y0;
knockout_boxes[knockout_box_cur].deleted = false;
knockout_boxes[knockout_box_cur].child = NULL;
knockout_boxes[knockout_box_cur].next = parent->child;
parent->child = &knockout_boxes[knockout_box_cur++];
ny0 = y0;
}
/* clip right */
if (x1 < nx1) {
knockout_boxes[knockout_box_cur].bbox.x0 = x1;
knockout_boxes[knockout_box_cur].bbox.y0 = ny0;
knockout_boxes[knockout_box_cur].bbox.x1 = nx1;
knockout_boxes[knockout_box_cur].bbox.y1 = ny1;
knockout_boxes[knockout_box_cur].deleted = false;
knockout_boxes[knockout_box_cur].child = NULL;
knockout_boxes[knockout_box_cur].next = parent->child;
parent->child = &knockout_boxes[knockout_box_cur++];
/* nx1 isn't used again, but if it was it would
* need to be updated to x1 here. */
}
/* clip left */
if (x0 > nx0) {
knockout_boxes[knockout_box_cur].bbox.x0 = nx0;
knockout_boxes[knockout_box_cur].bbox.y0 = ny0;
knockout_boxes[knockout_box_cur].bbox.x1 = x0;
knockout_boxes[knockout_box_cur].bbox.y1 = ny1;
knockout_boxes[knockout_box_cur].deleted = false;
knockout_boxes[knockout_box_cur].child = NULL;
knockout_boxes[knockout_box_cur].next = parent->child;
parent->child = &knockout_boxes[knockout_box_cur++];
/* nx0 isn't used again, but if it was it would
* need to be updated to x0 here. */
}
}
}
}
 
 
bool knockout_plot_fill_recursive(struct knockout_box *box, plot_style_t *plot_style)
{
bool success = true;
struct knockout_box *parent;
 
for (parent = box; parent; parent = parent->next) {
if (parent->deleted)
continue;
if (parent->child)
knockout_plot_fill_recursive(parent->child, plot_style);
else
success &= real_plot.rectangle(parent->bbox.x0,
parent->bbox.y0,
parent->bbox.x1,
parent->bbox.y1,
plot_style);
}
return success;
}
 
 
bool knockout_plot_bitmap_recursive(struct knockout_box *box,
struct knockout_entry *entry)
{
bool success = true;
struct knockout_box *parent;
 
for (parent = box; parent; parent = parent->next) {
if (parent->deleted)
continue;
if (parent->child)
knockout_plot_bitmap_recursive(parent->child, entry);
else {
success &= real_plot.clip(&parent->bbox);
success &= real_plot.bitmap(entry->data.bitmap.x,
entry->data.bitmap.y,
entry->data.bitmap.width,
entry->data.bitmap.height,
entry->data.bitmap.bitmap,
entry->data.bitmap.bg,
entry->data.bitmap.flags);
}
}
return success;
}
 
bool knockout_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *pstyle)
{
int kx0, ky0, kx1, ky1;
 
if (pstyle->fill_type != PLOT_OP_TYPE_NONE) {
/* filled draw */
 
/* get our bounds */
kx0 = (x0 > clip_cur.x0) ? x0 : clip_cur.x0;
ky0 = (y0 > clip_cur.y0) ? y0 : clip_cur.y0;
kx1 = (x1 < clip_cur.x1) ? x1 : clip_cur.x1;
ky1 = (y1 < clip_cur.y1) ? y1 : clip_cur.y1;
if ((kx0 > clip_cur.x1) || (kx1 < clip_cur.x0) ||
(ky0 > clip_cur.y1) || (ky1 < clip_cur.y0))
return true;
 
/* fills both knock out and get knocked out */
knockout_calculate(kx0, ky0, kx1, ky1, NULL);
knockout_boxes[knockout_box_cur].bbox.x0 = x0;
knockout_boxes[knockout_box_cur].bbox.y0 = y0;
knockout_boxes[knockout_box_cur].bbox.x1 = x1;
knockout_boxes[knockout_box_cur].bbox.y1 = y1;
knockout_boxes[knockout_box_cur].deleted = false;
knockout_boxes[knockout_box_cur].child = NULL;
knockout_boxes[knockout_box_cur].next = knockout_list;
knockout_list = &knockout_boxes[knockout_box_cur];
knockout_entries[knockout_entry_cur].box = &knockout_boxes[knockout_box_cur];
knockout_entries[knockout_entry_cur].data.fill.x0 = x0;
knockout_entries[knockout_entry_cur].data.fill.y0 = y0;
knockout_entries[knockout_entry_cur].data.fill.x1 = x1;
knockout_entries[knockout_entry_cur].data.fill.y1 = y1;
knockout_entries[knockout_entry_cur].data.fill.plot_style = *pstyle;
knockout_entries[knockout_entry_cur].data.fill.plot_style.stroke_type = PLOT_OP_TYPE_NONE; /* ensure we only plot the fill */
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_FILL;
if ((++knockout_entry_cur >= KNOCKOUT_ENTRIES) ||
(++knockout_box_cur >= KNOCKOUT_BOXES))
knockout_plot_flush();
}
 
if (pstyle->stroke_type != PLOT_OP_TYPE_NONE) {
/* draw outline */
 
knockout_entries[knockout_entry_cur].data.rectangle.x0 = x0;
knockout_entries[knockout_entry_cur].data.rectangle.y0 = y0;
knockout_entries[knockout_entry_cur].data.rectangle.x1 = x1;
knockout_entries[knockout_entry_cur].data.rectangle.y1 = y1;
knockout_entries[knockout_entry_cur].data.fill.plot_style = *pstyle;
knockout_entries[knockout_entry_cur].data.fill.plot_style.fill_type = PLOT_OP_TYPE_NONE; /* ensure we only plot the outline */
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_RECTANGLE;
if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
knockout_plot_flush();
}
return true;
}
 
bool knockout_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle)
{
knockout_entries[knockout_entry_cur].data.line.x0 = x0;
knockout_entries[knockout_entry_cur].data.line.y0 = y0;
knockout_entries[knockout_entry_cur].data.line.x1 = x1;
knockout_entries[knockout_entry_cur].data.line.y1 = y1;
knockout_entries[knockout_entry_cur].data.line.plot_style = *pstyle;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_LINE;
if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
knockout_plot_flush();
return true;
}
 
 
bool knockout_plot_polygon(const int *p, unsigned int n, const plot_style_t *pstyle)
{
bool success = true;
int *dest;
 
/* ensure we have sufficient room even when flushed */
if (n * 2 >= KNOCKOUT_POLYGONS) {
knockout_plot_flush();
success = real_plot.polygon(p, n, pstyle);
return success;
}
 
/* ensure we have enough room right now */
if (knockout_polygon_cur + n * 2 >= KNOCKOUT_POLYGONS)
knockout_plot_flush();
 
/* copy our data */
dest = &(knockout_polygons[knockout_polygon_cur]);
memcpy(dest, p, n * 2 * sizeof(int));
knockout_polygon_cur += n * 2;
knockout_entries[knockout_entry_cur].data.polygon.p = dest;
knockout_entries[knockout_entry_cur].data.polygon.n = n;
knockout_entries[knockout_entry_cur].data.polygon.plot_style = *pstyle;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_POLYGON;
if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
knockout_plot_flush();
return true;
}
 
 
bool knockout_plot_path(const float *p, unsigned int n, colour fill,
float width, colour c, const float transform[6])
{
knockout_plot_flush();
return real_plot.path(p, n, fill, width, c, transform);
}
 
 
bool knockout_plot_clip(const struct rect *clip)
{
if (clip->x1 < clip->x0 || clip->y0 > clip->y1) {
#ifdef KNOCKOUT_DEBUG
LOG(("bad clip rectangle %i %i %i %i",
clip->x0, clip->y0, clip->x1, clip->y1));
#endif
return false;
}
 
/* memorise clip for bitmap tiling */
clip_cur = *clip;
 
knockout_entries[knockout_entry_cur].data.clip = *clip;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_CLIP;
if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
knockout_plot_flush();
return true;
}
 
 
bool knockout_plot_text(int x, int y, const char *text, size_t length,
const plot_font_style_t *fstyle)
{
knockout_entries[knockout_entry_cur].data.text.x = x;
knockout_entries[knockout_entry_cur].data.text.y = y;
knockout_entries[knockout_entry_cur].data.text.text = text;
knockout_entries[knockout_entry_cur].data.text.length = length;
knockout_entries[knockout_entry_cur].data.text.font_style = *fstyle;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_TEXT;
if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
knockout_plot_flush();
return true;
}
 
 
bool knockout_plot_disc(int x, int y, int radius, const plot_style_t *pstyle)
{
knockout_entries[knockout_entry_cur].data.disc.x = x;
knockout_entries[knockout_entry_cur].data.disc.y = y;
knockout_entries[knockout_entry_cur].data.disc.radius = radius;
knockout_entries[knockout_entry_cur].data.disc.plot_style = *pstyle;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_DISC;
if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
knockout_plot_flush();
return true;
}
 
bool knockout_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *pstyle)
{
knockout_entries[knockout_entry_cur].data.arc.x = x;
knockout_entries[knockout_entry_cur].data.arc.y = y;
knockout_entries[knockout_entry_cur].data.arc.radius = radius;
knockout_entries[knockout_entry_cur].data.arc.angle1 = angle1;
knockout_entries[knockout_entry_cur].data.arc.angle2 = angle2;
knockout_entries[knockout_entry_cur].data.arc.plot_style = *pstyle;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_ARC;
if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
knockout_plot_flush();
return true;
}
 
 
 
bool knockout_plot_bitmap(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bitmap_flags_t flags)
{
int kx0, ky0, kx1, ky1;
 
/* get our bounds */
kx0 = clip_cur.x0;
ky0 = clip_cur.y0;
kx1 = clip_cur.x1;
ky1 = clip_cur.y1;
if (!(flags & BITMAPF_REPEAT_X)) {
if (x > kx0)
kx0 = x;
if (x + width < kx1)
kx1 = x + width;
if ((kx0 > clip_cur.x1) || (kx1 < clip_cur.x0))
return true;
}
if (!(flags & BITMAPF_REPEAT_Y)) {
if (y > ky0)
ky0 = y;
if (y + height < ky1)
ky1 = y + height;
if ((ky0 > clip_cur.y1) || (ky1 < clip_cur.y0))
return true;
}
 
/* tiled bitmaps both knock out and get knocked out */
if (bitmap_get_opaque(bitmap))
knockout_calculate(kx0, ky0, kx1, ky1, NULL);
knockout_boxes[knockout_box_cur].bbox.x0 = kx0;
knockout_boxes[knockout_box_cur].bbox.y0 = ky0;
knockout_boxes[knockout_box_cur].bbox.x1 = kx1;
knockout_boxes[knockout_box_cur].bbox.y1 = ky1;
knockout_boxes[knockout_box_cur].deleted = false;
knockout_boxes[knockout_box_cur].child = NULL;
knockout_boxes[knockout_box_cur].next = knockout_list;
knockout_list = &knockout_boxes[knockout_box_cur];
knockout_entries[knockout_entry_cur].box = &knockout_boxes[knockout_box_cur];
knockout_entries[knockout_entry_cur].data.bitmap.x = x;
knockout_entries[knockout_entry_cur].data.bitmap.y = y;
knockout_entries[knockout_entry_cur].data.bitmap.width = width;
knockout_entries[knockout_entry_cur].data.bitmap.height = height;
knockout_entries[knockout_entry_cur].data.bitmap.bitmap = bitmap;
knockout_entries[knockout_entry_cur].data.bitmap.bg = bg;
knockout_entries[knockout_entry_cur].data.bitmap.flags = flags;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_BITMAP;
if ((++knockout_entry_cur >= KNOCKOUT_ENTRIES) ||
(++knockout_box_cur >= KNOCKOUT_BOXES))
knockout_plot_flush();
return knockout_plot_clip(&clip_cur);
}
 
bool knockout_plot_group_start(const char *name)
{
if (real_plot.group_start == NULL) {
return true;
}
 
knockout_entries[knockout_entry_cur].data.group_start.name = name;
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_GROUP_START;
if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
knockout_plot_flush();
return true;
}
 
bool knockout_plot_group_end(void)
{
if (real_plot.group_end == NULL) {
return true;
}
 
knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_GROUP_END;
if (++knockout_entry_cur >= KNOCKOUT_ENTRIES)
knockout_plot_flush();
return true;
}
/programs/network/netsurf/netsurf/desktop/knockout.h
0,0 → 1,35
/*
* Copyright 2006 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Knockout rendering (interface).
*/
 
#ifndef _NETSURF_DESKTOP_KNOCKOUT_H_
#define _NETSURF_DESKTOP_KNOCKOUT_H_
 
#include "desktop/plotters.h"
 
 
bool knockout_plot_start(const struct redraw_context *ctx,
struct redraw_context *knk_ctx);
bool knockout_plot_end(void);
 
extern const struct plotter_table knockout_plotters;
 
#endif
/programs/network/netsurf/netsurf/desktop/make.browser
0,0 → 1,22
CFLAGS += -O2
NETSURF_FB_FRONTEND := sdl
NETSURF_FB_FONTLIB := internal
 
NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
 
# Default resource install path
NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
 
# Default framebuffer search path
NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
 
# freetype compiled in font serch path
NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
OBJS := browser.o download.o frames.o history_core.o netsurf.o \
save_complete.o save_text.o selection.o textinput.o
 
 
OUTFILE = TEST.o
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include
include $(MENUETDEV)/makefiles/Makefile_for_o_lib
/programs/network/netsurf/netsurf/desktop/make.desktop
0,0 → 1,24
CFLAGS += -O2
NETSURF_FB_FRONTEND := sdl
NETSURF_FB_FONTLIB := internal
 
NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
 
# Default resource install path
NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
 
# Default framebuffer search path
NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
 
# freetype compiled in font serch path
NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
OBJS := cookies.o history_global_core.o hotlist.o knockout.o \
mouse.o options.o plot_style.o print.o search.o searchweb.o \
scrollbar.o sslcert.o textarea.o thumbnail.o tree.o \
tree_url_node.o version.o
 
 
OUTFILE = TEST.o
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include
include $(MENUETDEV)/makefiles/Makefile_for_o_lib
/programs/network/netsurf/netsurf/desktop/mouse.c
0,0 → 1,47
/*
* Copyright 2010 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Browser window creation and manipulation (implementation).
*/
 
#include "desktop/browser.h"
#include "utils/log.h"
 
/**
* Debug function logs a browser mouse state.
*
* \param mouse browser_mouse_state to dump
*/
void browser_mouse_state_dump(browser_mouse_state mouse)
{
LOG(("mouse state: %s %s %s %s %s %s %s %s %s %s %s %s %s",
mouse & BROWSER_MOUSE_PRESS_1 ? "P1" : " ",
mouse & BROWSER_MOUSE_PRESS_2 ? "P2" : " ",
mouse & BROWSER_MOUSE_CLICK_1 ? "C1" : " ",
mouse & BROWSER_MOUSE_CLICK_2 ? "C2" : " ",
mouse & BROWSER_MOUSE_DOUBLE_CLICK ? "DC" : " ",
mouse & BROWSER_MOUSE_DRAG_1 ? "D1" : " ",
mouse & BROWSER_MOUSE_DRAG_2 ? "D2" : " ",
mouse & BROWSER_MOUSE_DRAG_ON ? "DO" : " ",
mouse & BROWSER_MOUSE_HOLDING_1 ? "H1" : " ",
mouse & BROWSER_MOUSE_HOLDING_2 ? "H2" : " ",
mouse & BROWSER_MOUSE_MOD_1 ? "M1" : " ",
mouse & BROWSER_MOUSE_MOD_2 ? "M2" : " ",
mouse & BROWSER_MOUSE_MOD_3 ? "M3" : " "));
}
/programs/network/netsurf/netsurf/desktop/mouse.h
0,0 → 1,108
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
* Copyright 2010 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Core mouse state.
*/
 
#ifndef _NETSURF_DESKTOP_MOUSE_H_
#define _NETSURF_DESKTOP_MOUSE_H_
 
/* Mouse state. 1 is primary mouse button (e.g. Select on RISC OS).
* 2 is secondary mouse button (e.g. Adjust on RISC OS). */
typedef enum {
BROWSER_MOUSE_HOVER = 0, /* No mouse buttons pressed,
* May be used to indicate
* hover or end of drag. */
 
BROWSER_MOUSE_PRESS_1 = (1 << 0), /* button 1 pressed */
BROWSER_MOUSE_PRESS_2 = (1 << 1), /* button 2 pressed */
 
/* note: click meaning is different for
* different front ends. On RISC OS, it
* is standard to act on press, so a
* click is fired at the same time as a
* mouse button is pressed. With GTK, it
* is standard to act on release, so a
* click is fired when the mouse button
* is released, if the operation wasn't
* a drag. */
 
BROWSER_MOUSE_CLICK_1 = (1 << 2), /* button 1 clicked. */
BROWSER_MOUSE_CLICK_2 = (1 << 3), /* button 2 clicked. */
 
BROWSER_MOUSE_DOUBLE_CLICK = (1 << 4), /* button 1 double clicked */
 
BROWSER_MOUSE_DRAG_1 = (1 << 5), /* start of button 1 drag */
BROWSER_MOUSE_DRAG_2 = (1 << 6), /* start of button 2 drag */
 
BROWSER_MOUSE_DRAG_ON = (1 << 7), /* a drag operation was started
* and a mouse button is still
* pressed */
 
BROWSER_MOUSE_HOLDING_1 = (1 << 8), /* during button 1 drag */
BROWSER_MOUSE_HOLDING_2 = (1 << 9), /* during button 2 drag */
 
 
BROWSER_MOUSE_MOD_1 = (1 << 10), /* 1st modifier key pressed
* (eg. Shift) */
BROWSER_MOUSE_MOD_2 = (1 << 11), /* 2nd modifier key pressed
* (eg. Ctrl) */
BROWSER_MOUSE_MOD_3 = (1 << 12) /* 3rd modifier key pressed
* (eg. Alt) */
} browser_mouse_state;
 
 
typedef enum { GUI_POINTER_DEFAULT, GUI_POINTER_POINT, GUI_POINTER_CARET,
GUI_POINTER_MENU, GUI_POINTER_UP, GUI_POINTER_DOWN,
GUI_POINTER_LEFT, GUI_POINTER_RIGHT, GUI_POINTER_RU,
GUI_POINTER_LD, GUI_POINTER_LU, GUI_POINTER_RD,
GUI_POINTER_CROSS, GUI_POINTER_MOVE, GUI_POINTER_WAIT,
GUI_POINTER_HELP, GUI_POINTER_NO_DROP, GUI_POINTER_NOT_ALLOWED,
GUI_POINTER_PROGRESS } gui_pointer_shape;
 
/** Mouse pointer type */
typedef enum {
BROWSER_POINTER_DEFAULT = GUI_POINTER_DEFAULT,
BROWSER_POINTER_POINT = GUI_POINTER_POINT,
BROWSER_POINTER_CARET = GUI_POINTER_CARET,
BROWSER_POINTER_MENU = GUI_POINTER_MENU,
BROWSER_POINTER_UP = GUI_POINTER_UP,
BROWSER_POINTER_DOWN = GUI_POINTER_DOWN,
BROWSER_POINTER_LEFT = GUI_POINTER_LEFT,
BROWSER_POINTER_RIGHT = GUI_POINTER_RIGHT,
BROWSER_POINTER_RU = GUI_POINTER_RU,
BROWSER_POINTER_LD = GUI_POINTER_LD,
BROWSER_POINTER_LU = GUI_POINTER_LU,
BROWSER_POINTER_RD = GUI_POINTER_RD,
BROWSER_POINTER_CROSS = GUI_POINTER_CROSS,
BROWSER_POINTER_MOVE = GUI_POINTER_MOVE,
BROWSER_POINTER_WAIT = GUI_POINTER_WAIT,
BROWSER_POINTER_HELP = GUI_POINTER_HELP,
BROWSER_POINTER_NO_DROP = GUI_POINTER_NO_DROP,
BROWSER_POINTER_NOT_ALLOWED = GUI_POINTER_NOT_ALLOWED,
BROWSER_POINTER_PROGRESS = GUI_POINTER_PROGRESS,
BROWSER_POINTER_AUTO
} browser_pointer_shape;
 
 
void browser_mouse_state_dump(browser_mouse_state mouse);
 
#endif
/programs/network/netsurf/netsurf/desktop/netsurf.c
0,0 → 1,305
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2007 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <locale.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/config.h"
#include "utils/utsname.h"
#include "content/content_factory.h"
#include "content/fetch.h"
#include "content/hlcache.h"
#include "content/mimesniff.h"
#include "content/urldb.h"
#include "css/css.h"
#include "image/image.h"
#include "image/image_cache.h"
#include "desktop/netsurf.h"
#include "desktop/401login.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
#include "desktop/options.h"
#include "desktop/searchweb.h"
 
#include "javascript/js.h"
 
#include "render/html.h"
#include "render/textplain.h"
#include "utils/corestrings.h"
#include "utils/log.h"
#include "utils/url.h"
#include "utils/utf8.h"
#include "utils/utils.h"
#include "utils/messages.h"
 
/** speculative pre-conversion small image size
*
* Experimenting by visiting every page from default page in order and
* then netsurf homepage
*
* 0 : Cache hit/miss/speculative miss/fail 604/147/ 0/0 (80%/19%/ 0%/ 0%)
* 2048 : Cache hit/miss/speculative miss/fail 622/119/ 17/0 (82%/15%/ 2%/ 0%)
* 4096 : Cache hit/miss/speculative miss/fail 656/109/ 25/0 (83%/13%/ 3%/ 0%)
* 8192 : Cache hit/miss/speculative miss/fail 648/104/ 40/0 (81%/13%/ 5%/ 0%)
* ALL : Cache hit/miss/speculative miss/fail 775/ 0/161/0 (82%/ 0%/17%/ 0%)
*/
#define SPECULATE_SMALL 4096
 
/* the time between cache clean runs in ms */
#define IMAGE_CACHE_CLEAN_TIME (10 * 1000)
 
#define HL_CACHE_CLEAN_TIME (2 * IMAGE_CACHE_CLEAN_TIME)
 
bool netsurf_quit = false;
bool verbose_log = false;
 
static void netsurf_lwc_iterator(lwc_string *str, void *pw)
{
LOG(("[%3u] %.*s", str->refcnt, (int) lwc_string_length(str), lwc_string_data(str)));
}
 
/**
* Dispatch a low-level cache query to the frontend
*
* \param query Query descriptor
* \param pw Private data
* \param cb Continuation callback
* \param cbpw Private data for continuation
* \return NSERROR_OK
*/
static nserror netsurf_llcache_query_handler(const llcache_query *query,
void *pw, llcache_query_response cb, void *cbpw)
{
switch (query->type) {
case LLCACHE_QUERY_AUTH:
gui_401login_open(query->url, query->data.auth.realm, cb, cbpw);
break;
case LLCACHE_QUERY_REDIRECT:
/** \todo Need redirect query dialog */
/* For now, do nothing, as this query type isn't emitted yet */
break;
case LLCACHE_QUERY_SSL:
gui_cert_verify(query->url, query->data.ssl.certs,
query->data.ssl.num, cb, cbpw);
break;
}
 
return NSERROR_OK;
}
 
#define MINIMUM_MEMORY_CACHE_SIZE (2 * 1024 * 1024)
 
/**
* Initialise components used by gui NetSurf.
*/
 
nserror netsurf_init(int *pargc,
char ***pargv,
const char *options,
const char *messages)
{
nserror error;
struct utsname utsname;
nserror ret = NSERROR_OK;
struct hlcache_parameters hlcache_parameters = {
.bg_clean_time = HL_CACHE_CLEAN_TIME,
.cb = netsurf_llcache_query_handler,
};
struct image_cache_parameters image_cache_parameters = {
.bg_clean_time = IMAGE_CACHE_CLEAN_TIME,
.speculative_small = SPECULATE_SMALL
};
#ifdef HAVE_SIGPIPE
/* Ignore SIGPIPE - this is necessary as OpenSSL can generate these
* and the default action is to terminate the app. There's no easy
* way of determining the cause of the SIGPIPE (other than using
* sigaction() and some mechanism for getting the file descriptor
* out of libcurl). However, we expect nothing else to generate a
* SIGPIPE, anyway, so may as well just ignore them all. */
signal(SIGPIPE, SIG_IGN);
#endif
 
#ifndef HAVE_STDOUT
ret = nslog_init(nslog_ensure, pargc, *pargv);
#else
ret = nslog_init(NULL, pargc, *pargv);
#endif
 
if (ret != NSERROR_OK)
return ret;
 
#ifdef _MEMDEBUG_H_
memdebug_memdebug("memdump");
#endif
LOG(("version '%s'", netsurf_version));
if (uname(&utsname) < 0)
LOG(("Failed to extract machine information"));
else
LOG(("NetSurf on <%s>, node <%s>, release <%s>, version <%s>, "
"machine <%s>", utsname.sysname,
utsname.nodename, utsname.release,
utsname.version, utsname.machine));
 
LOG(("Using '%s' for Options file", options));
nsoption_read(options);
gui_options_init_defaults();
 
messages_load(messages);
 
/* corestrings init */
error = corestrings_init();
if (error != NSERROR_OK)
return error;
 
/* set up cache limits based on the memory cache size option */
hlcache_parameters.limit = nsoption_int(memory_cache_size);
 
if (hlcache_parameters.limit < MINIMUM_MEMORY_CACHE_SIZE) {
hlcache_parameters.limit = MINIMUM_MEMORY_CACHE_SIZE;
LOG(("Setting minimum memory cache size to %d",
hlcache_parameters.limit));
}
 
/* image cache is 25% of total memory cache size */
image_cache_parameters.limit = (hlcache_parameters.limit * 25) / 100;
 
/* image cache hysteresis is 20% of teh image cache size */
image_cache_parameters.hysteresis = (image_cache_parameters.limit * 20) / 100;
 
/* account for image cache use from total */
hlcache_parameters.limit -= image_cache_parameters.limit;
 
/* image handler bitmap cache */
error = image_cache_init(&image_cache_parameters);
if (error != NSERROR_OK)
return error;
 
/* content handler initialisation */
error = nscss_init();
if (error != NSERROR_OK)
return error;
 
error = html_init();
if (error != NSERROR_OK)
return error;
 
error = image_init();
if (error != NSERROR_OK)
return error;
 
error = textplain_init();
if (error != NSERROR_OK)
return error;
 
 
error = mimesniff_init();
if (error != NSERROR_OK)
return error;
 
url_init();
 
setlocale(LC_ALL, "C");
 
fetch_init();
/* Initialise the hlcache and allow it to init the llcache for us */
hlcache_initialise(&hlcache_parameters);
 
/* Initialize system colours */
gui_system_colour_init();
 
nsoption_commandline(pargc, *pargv);
 
js_initialise();
 
return ret;
}
 
 
/**
* Gui NetSurf main loop.
*/
int netsurf_main_loop(void)
{
while (!netsurf_quit) {
LOG(("GUI POLL"));
gui_poll(fetch_active);
LOG(("CACHE POLL"));
hlcache_poll();
}
 
return 0;
}
 
/**
* Clean up components used by gui NetSurf.
*/
 
void netsurf_exit(void)
{
hlcache_stop();
LOG(("Closing GUI"));
gui_quit();
LOG(("Finalising JavaScript"));
js_finalise();
 
LOG(("Closing search and related resources"));
search_web_cleanup();
 
LOG(("Finalising high-level cache"));
hlcache_finalise();
 
LOG(("Closing fetches"));
fetch_quit();
 
mimesniff_fini();
 
/* dump any remaining cache entries */
image_cache_fini();
 
/* Clean up after content handlers */
content_factory_fini();
 
LOG(("Closing utf8"));
utf8_finalise();
 
LOG(("Destroying URLdb"));
urldb_destroy();
 
LOG(("Destroying System colours"));
gui_system_colour_finalize();
 
corestrings_fini();
LOG(("Remaining lwc strings:"));
lwc_iterate_strings(netsurf_lwc_iterator, NULL);
 
LOG(("Exited successfully"));
}
 
 
/programs/network/netsurf/netsurf/desktop/netsurf.h
0,0 → 1,35
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef _NETSURF_DESKTOP_NETSURF_H_
#define _NETSURF_DESKTOP_NETSURF_H_
 
#include <stdbool.h>
#include "utils/errors.h"
 
extern bool netsurf_quit;
extern bool verbose_log;
extern const char * const netsurf_version;
extern const int netsurf_version_major;
extern const int netsurf_version_minor;
 
nserror netsurf_init(int *argc, char ***argv, const char *options, const char *messages);
extern void netsurf_exit(void);
extern int netsurf_main_loop(void);
 
#endif
/programs/network/netsurf/netsurf/desktop/options.c
0,0 → 1,475
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2005 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Option reading and saving (implementation).
*
* Options are stored in the format key:value, one per line. For bool options,
* value is "0" or "1".
*/
 
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
 
#include "css/css.h"
#include "desktop/plot_style.h"
#include "utils/log.h"
#include "utils/utils.h"
#include "desktop/options.h"
 
struct ns_options nsoptions = {
NSOPTION_MAIN_DEFAULTS,
NSOPTION_SYS_COLOUR_DEFAULTS,
NSOPTION_EXTRA_DEFAULTS
};
 
enum option_type_e {
OPTION_BOOL,
OPTION_INTEGER,
OPTION_STRING,
OPTION_COLOUR
} ;
 
struct option_entry_s {
const char *key;
enum option_type_e type;
void *p;
};
 
struct option_entry_s option_table[] = {
NSOPTION_MAIN_TABLE,
NSOPTION_EXTRA_TABLE
};
 
#define option_table_entries (sizeof option_table / sizeof option_table[0])
 
/**
* Set an option value based on a string
*/
static bool
strtooption(const char *value, struct option_entry_s *option_entry)
{
bool ret = false;
colour rgbcolour; /* RRGGBB */
 
switch (option_entry->type) {
case OPTION_BOOL:
*((bool *)option_entry->p) = value[0] == '1';
ret = true;
break;
 
case OPTION_INTEGER:
*((int *)option_entry->p) = atoi(value);
ret = true;
break;
 
case OPTION_COLOUR:
sscanf(value, "%x", &rgbcolour);
*((colour *)option_entry->p) =
((0x000000FF & rgbcolour) << 16) |
((0x0000FF00 & rgbcolour) << 0) |
((0x00FF0000 & rgbcolour) >> 16);
ret = true;
break;
 
case OPTION_STRING:
free(*((char **)option_entry->p));
if (*value == 0) {
/* do not allow empty strings in text options */
*((char **)option_entry->p) = NULL;
} else {
*((char **)option_entry->p) = strdup(value);
}
ret = true;
break;
}
 
return ret;
}
 
static void nsoptions_validate(struct ns_options *opts)
{
if (opts->font_size < 50)
opts->font_size = 50;
 
if (1000 < opts->font_size)
opts->font_size = 1000;
 
if (opts->font_min_size < 10)
opts->font_min_size = 10;
 
if (500 < opts->font_min_size)
opts->font_min_size = 500;
 
if (opts->memory_cache_size < 0)
opts->memory_cache_size = 0;
 
}
 
/* exported interface documented in options.h */
void nsoption_read(const char *path)
{
char s[100];
FILE *fp;
 
if (path == NULL) {
LOG(("No options loaded"));
return;
}
 
fp = fopen(path, "r");
if (!fp) {
LOG(("failed to open file '%s'", path));
return;
}
 
while (fgets(s, 100, fp)) {
char *colon, *value;
unsigned int i;
 
if (s[0] == 0 || s[0] == '#')
continue;
colon = strchr(s, ':');
if (colon == 0)
continue;
s[strlen(s) - 1] = 0; /* remove \n at end */
*colon = 0; /* terminate key */
value = colon + 1;
 
for (i = 0; i != option_table_entries; i++) {
if (strcasecmp(s, option_table[i].key) != 0)
continue;
 
strtooption(value, option_table + i);
break;
}
}
 
fclose(fp);
 
nsoptions_validate(&nsoptions);
}
 
 
/* exported interface documented in options.h */
void nsoption_write(const char *path)
{
unsigned int entry;
FILE *fp;
colour rgbcolour; /* RRGGBB */
 
fp = fopen(path, "w");
if (!fp) {
LOG(("failed to open file '%s' for writing", path));
return;
}
 
for (entry = 0; entry != option_table_entries; entry++) {
switch (option_table[entry].type) {
case OPTION_BOOL:
fprintf(fp, "%s:%c\n", option_table[entry].key,
*((bool *) option_table[entry].p) ? '1' : '0');
break;
 
case OPTION_INTEGER:
fprintf(fp, "%s:%i\n", option_table[entry].key,
*((int *) option_table[entry].p));
break;
 
case OPTION_COLOUR:
rgbcolour = ((0x000000FF & *((colour *)
option_table[entry].p)) << 16) |
((0x0000FF00 & *((colour *)
option_table[entry].p)) << 0) |
((0x00FF0000 & *((colour *)
option_table[entry].p)) >> 16);
fprintf(fp, "%s:%06x\n", option_table[entry].key,
rgbcolour);
break;
 
case OPTION_STRING:
if (((*((char **) option_table[entry].p)) != NULL) &&
(*(*((char **) option_table[entry].p)) != 0)) {
fprintf(fp, "%s:%s\n", option_table[entry].key,
*((char **) option_table[entry].p));
}
break;
}
}
 
fclose(fp);
}
 
 
/**
* Output an option value into a string, in HTML format.
*
* \param option The option to output the value of.
* \param size The size of the string buffer.
* \param pos The current position in string
* \param string The string in which to output the value.
* \return The number of bytes written to string or -1 on error
*/
static size_t
nsoption_output_value_html(struct option_entry_s *option,
size_t size, size_t pos, char *string)
{
size_t slen = 0; /* length added to string */
colour rgbcolour; /* RRGGBB */
 
switch (option->type) {
case OPTION_BOOL:
slen = snprintf(string + pos, size - pos, "%s",
*((bool *)option->p) ? "true" : "false");
break;
 
case OPTION_INTEGER:
slen = snprintf(string + pos, size - pos, "%i",
*((int *)option->p));
break;
 
case OPTION_COLOUR:
rgbcolour = ((0x000000FF & *((colour *) option->p)) << 16) |
((0x0000FF00 & *((colour *) option->p)) << 0) |
((0x00FF0000 & *((colour *) option->p)) >> 16);
slen = snprintf(string + pos, size - pos,
"<span style=\"background-color: #%06x; "
"color: #%06x;\">#%06x</span>", rgbcolour,
(~rgbcolour) & 0xffffff, rgbcolour);
break;
 
case OPTION_STRING:
if (*((char **)option->p) != NULL) {
slen = snprintf(string + pos, size - pos, "%s",
*((char **)option->p));
} else {
slen = snprintf(string + pos, size - pos,
"<span class=\"null-content\">NULL"
"</span>");
}
break;
}
 
return slen;
}
 
 
/**
* Output an option value into a string, in plain text format.
*
* \param option The option to output the value of.
* \param size The size of the string buffer.
* \param pos The current position in string
* \param string The string in which to output the value.
* \return The number of bytes written to string or -1 on error
*/
static size_t
nsoption_output_value_text(struct option_entry_s *option,
size_t size, size_t pos, char *string)
{
size_t slen = 0; /* length added to string */
colour rgbcolour; /* RRGGBB */
 
switch (option->type) {
case OPTION_BOOL:
slen = snprintf(string + pos, size - pos, "%c",
*((bool *)option->p) ? '1' : '0');
break;
 
case OPTION_INTEGER:
slen = snprintf(string + pos, size - pos, "%i",
*((int *)option->p));
break;
 
case OPTION_COLOUR:
rgbcolour = ((0x000000FF & *((colour *) option->p)) << 16) |
((0x0000FF00 & *((colour *) option->p)) << 0) |
((0x00FF0000 & *((colour *) option->p)) >> 16);
slen = snprintf(string + pos, size - pos, "%06x", rgbcolour);
break;
 
case OPTION_STRING:
if (*((char **)option->p) != NULL) {
slen = snprintf(string + pos, size - pos, "%s",
*((char **)option->p));
}
break;
}
 
return slen;
}
 
/* exported interface documented in options.h */
void
nsoption_commandline(int *pargc, char **argv)
{
char *arg;
char *val;
int arglen;
int idx = 1;
int mv_loop;
 
unsigned int entry_loop;
 
while (idx < *pargc) {
arg = argv[idx];
arglen = strlen(arg);
 
/* check we have an option */
/* option must start -- and be as long as the shortest option*/
if ((arglen < (2+5) ) || (arg[0] != '-') || (arg[1] != '-'))
break;
 
arg += 2; /* skip -- */
 
val = strchr(arg, '=');
if (val == NULL) {
/* no equals sign - next parameter is val */
idx++;
if (idx >= *pargc)
break;
val = argv[idx];
} else {
/* equals sign */
arglen = val - arg ;
val++;
}
 
/* arg+arglen is the option to set, val is the value */
 
LOG(("%.*s = %s",arglen,arg,val));
 
for (entry_loop = 0;
entry_loop < option_table_entries;
entry_loop++) {
if (strncmp(arg, option_table[entry_loop].key,
arglen) == 0) {
strtooption(val, option_table + entry_loop);
break;
}
}
 
idx++;
}
 
/* remove processed options from argv */
for (mv_loop=0;mv_loop < (*pargc - idx); mv_loop++) {
argv[mv_loop + 1] = argv[mv_loop + idx];
}
*pargc -= (idx - 1);
}
 
/* exported interface documented in options.h */
int
nsoption_snoptionf(char *string, size_t size, unsigned int option, const char *fmt)
{
size_t slen = 0; /* current output string length */
int fmtc = 0; /* current index into format string */
struct option_entry_s *option_entry;
 
if (option >= option_table_entries)
return -1;
 
option_entry = option_table + option;
 
while((slen < size) && (fmt[fmtc] != 0)) {
if (fmt[fmtc] == '%') {
fmtc++;
switch (fmt[fmtc]) {
case 'k':
slen += snprintf(string + slen, size - slen,
"%s", option_entry->key);
break;
 
case 't':
switch (option_entry->type) {
case OPTION_BOOL:
slen += snprintf(string + slen,
size - slen,
"boolean");
break;
 
case OPTION_INTEGER:
slen += snprintf(string + slen,
size - slen,
"integer");
break;
 
case OPTION_COLOUR:
slen += snprintf(string + slen,
size - slen,
"colour");
break;
 
case OPTION_STRING:
slen += snprintf(string + slen,
size - slen,
"string");
break;
 
}
break;
 
 
case 'V':
slen += nsoption_output_value_html(option_entry,
size, slen, string);
break;
case 'v':
slen += nsoption_output_value_text(option_entry,
size, slen, string);
break;
}
fmtc++;
} else {
string[slen] = fmt[fmtc];
slen++;
fmtc++;
}
}
 
/* Ensure that we NUL-terminate the output */
string[min(slen, size - 1)] = '\0';
 
return slen;
}
 
/* exported interface documented in options.h */
void
nsoption_dump(FILE *outf)
{
char buffer[256];
int opt_loop = 0;
int res;
 
do {
res = nsoption_snoptionf(buffer, sizeof buffer, opt_loop,
"%k:%v\n");
if (res > 0) {
fprintf(outf, "%s", buffer);
}
opt_loop++;
} while (res > 0);
}
 
/programs/network/netsurf/netsurf/desktop/options.h
0,0 → 1,188
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Option reading and saving (interface).
*
* Non-platform specific options can be added by editing this file and
* netsurf/desktop/options.c
*
* Platform specific options should be added in the platform options.h.
*
* The following types of options are supported:
* - bool (OPTION_BOOL)
* - int (OPTION_INTEGER)
* - char* (OPTION_STRING) (must be allocated on heap, may be 0, free before
* assigning a new value)
*/
 
#ifndef _NETSURF_DESKTOP_OPTIONS_H_
#define _NETSURF_DESKTOP_OPTIONS_H_
 
#define _NETSURF_DESKTOP_OPTIONS_INCLUDING_
 
#include <stdbool.h>
#include <stdio.h>
 
#include "desktop/plot_style.h"
#include "desktop/options_main.h"
 
#if defined(riscos)
#include "riscos/options.h"
#elif defined(nsgtk)
#include "gtk/options.h"
#elif defined(nsbeos)
#include "beos/options.h"
#elif defined(nsamiga)
#include "amiga/options.h"
#elif defined(nsframebuffer)
#include "framebuffer/options.h"
#elif defined(nsatari)
#include "atari/options.h"
#elif defined(nsmonkey)
#include "monkey/options.h"
#else
#define NSOPTION_EXTRA_DEFINE
#define NSOPTION_EXTRA_DEFAULTS
#define NSOPTION_EXTRA_TABLE
#endif
 
/* allow the colour defaults to be overidden by the frontends */
#ifndef NSOPTION_SYS_COLOUR_DEFAULTS
#define NSOPTION_SYS_COLOUR_DEFAULTS NSOPTION_MAIN_SYS_COLOUR_DEFAULTS
#endif
 
#undef _NETSURF_DESKTOP_OPTIONS_INCLUDING_
 
 
enum { OPTION_HTTP_PROXY_AUTH_NONE = 0,
OPTION_HTTP_PROXY_AUTH_BASIC = 1,
OPTION_HTTP_PROXY_AUTH_NTLM = 2 };
 
#define DEFAULT_MARGIN_TOP_MM 10
#define DEFAULT_MARGIN_BOTTOM_MM 10
#define DEFAULT_MARGIN_LEFT_MM 10
#define DEFAULT_MARGIN_RIGHT_MM 10
#define DEFAULT_EXPORT_SCALE 0.7
#ifdef riscos
#define DEFAULT_REFLOW_PERIOD 100 /* time in cs */
#else
#define DEFAULT_REFLOW_PERIOD 25 /* time in cs */
#endif
 
struct ns_options {
NSOPTION_MAIN_DEFINE;
NSOPTION_EXTRA_DEFINE;
};
 
/* global option struct */
extern struct ns_options nsoptions;
 
/* acessors */
#define nsoption_bool(OPTION) (nsoptions.OPTION)
#define nsoption_int(OPTION) (nsoptions.OPTION)
#define nsoption_charp(OPTION) (nsoptions.OPTION)
#define nsoption_colour(OPTION) (nsoptions.OPTION)
 
#define nsoption_set_bool(OPTION, VALUE) nsoptions.OPTION = VALUE
#define nsoption_set_int(OPTION, VALUE) nsoptions.OPTION = VALUE
#define nsoption_set_colour(OPTION, VALUE) nsoptions.OPTION = VALUE
#define nsoption_set_charp(OPTION, VALUE) do { \
if (nsoptions.OPTION != NULL) { \
free(nsoptions.OPTION); \
} \
nsoptions.OPTION = VALUE; \
if ((nsoptions.OPTION != NULL) && \
(*nsoptions.OPTION == 0)) { \
free(nsoptions.OPTION); \
nsoptions.OPTION = NULL; \
} \
} while (0)
 
#define nsoption_setnull_charp(OPTION, VALUE) \
do { \
if (nsoptions.OPTION == NULL) { \
nsoptions.OPTION = VALUE; \
if (*nsoptions.OPTION == 0) { \
free(nsoptions.OPTION); \
nsoptions.OPTION = NULL; \
} \
} else { \
free(VALUE); \
} \
} while (0)
 
 
/**
* Read options from a file.
*
* \param path name of file to read options from
*
* Option variables corresponding to lines in the file are updated. Missing
* options are unchanged. If the file fails to open, options are unchanged.
*/
void nsoption_read(const char *path);
 
/**
* Save options to a file.
*
* \param path name of file to write options to
*
* Errors are ignored.
*/
void nsoption_write(const char *path);
 
/**
* Dump user options to stream
*
* \param outf output stream to dump options to.
*/
void nsoption_dump(FILE *outf);
 
/**
* Fill a buffer with an option using a format.
*
* The format string is copied into the output buffer with the
* following replaced:
* %k - The options key
* %t - The options type
* %V - value - HTML type formatting
* %v - value - plain formatting
*
* \param string The buffer in which to place the results.
* \param size The size of the string buffer.
* \param option The opaque option number.
* \param fmt The format string.
* \return The number of bytes written to \a string or -1 on error
*/
int nsoption_snoptionf(char *string, size_t size, unsigned int option,
const char *fmt);
 
/**
* Process commandline and set options approriately.
*/
void nsoption_commandline(int *pargc, char **argv);
 
/**
* Set default values for unset front-end specific options
*/
void gui_options_init_defaults(void);
 
#endif
 
/programs/network/netsurf/netsurf/desktop/options_main.h
0,0 → 1,401
/*
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Option available on all platforms
*
* Non-platform specific options can be added by editing this file
*
* Platform specific options should be added in the platform options.h.
*
* The following types of options are supported:
* - bool (OPTION_BOOL) boolean
* - int (OPTION_INTEGER) integer
* - colour (OPTION_COLOUR) colour
* - char* (OPTION_STRING) must be allocated on heap, may be NULL
*/
 
#ifndef _NETSURF_DESKTOP_OPTIONS_MAIN_H_
#define _NETSURF_DESKTOP_OPTIONS_MAIN_H_
 
#define NSOPTION_MAIN_DEFINE \
/** An HTTP proxy should be used. */ \
bool http_proxy; \
/** Hostname of proxy. */ \
char *http_proxy_host; \
/** Proxy port. */ \
int http_proxy_port; \
/** Proxy authentication method. */ \
int http_proxy_auth; \
/** Proxy authentication user name */ \
char *http_proxy_auth_user; \
/** Proxy authentication password */ \
char *http_proxy_auth_pass; \
/** Default font size / 0.1pt. */ \
int font_size; \
/** Minimum font size. */ \
int font_min_size; \
/** Default sans serif font */ \
char *font_sans; \
/** Default serif font */ \
char *font_serif; \
/** Default monospace font */ \
char *font_mono; \
/** Default cursive font */ \
char *font_cursive; \
/** Default fantasy font */ \
char *font_fantasy; \
/** Accept-Language header. */ \
char *accept_language; \
/** Accept-Charset header. */ \
char *accept_charset; \
/** Preferred maximum size of memory cache / bytes. */ \
int memory_cache_size; \
/** Preferred expiry size of disc cache / bytes. */ \
int disc_cache_size; \
/** Preferred expiry age of disc cache / days. */ \
int disc_cache_age; \
/** Whether to block advertisements */ \
bool block_ads; \
/** Disable website tracking, see \
* http://www.w3.org/Submission/2011/SUBM-web-tracking-protection-20110224/#dnt-uas */ \
bool do_not_track; \
/** Minimum GIF animation delay */ \
int minimum_gif_delay; \
/** Whether to send the referer HTTP header */ \
bool send_referer; \
/** Whether to fetch foreground images */ \
bool foreground_images; \
/** Whether to fetch background images */ \
bool background_images; \
/** Whether to animate images */ \
bool animate_images; \
/** Whether to execute javascript */ \
bool enable_javascript; \
/** How many days to retain URL data for */ \
int expire_url; \
/** Default font family */ \
int font_default; \
/** ca-bundle location */ \
char *ca_bundle; \
/** ca-path location */ \
char *ca_path; \
/** Cookie file location */ \
char *cookie_file; \
/** Cookie jar location */ \
char *cookie_jar; \
/** Home page location */ \
char *homepage_url; \
/** search web from url bar */ \
bool search_url_bar; \
/** URL completion in url bar */ \
bool url_suggestion; \
/** default web search provider */ \
int search_provider; \
/** default x position of new windows */ \
int window_x; \
/** default y position of new windows */ \
int window_y; \
/** default width of new windows */ \
int window_width; \
/** default height of new windows */ \
int window_height; \
/** width of screen when above options were saved */ \
int window_screen_width; \
/** height of screen when above options were saved */ \
int window_screen_height; \
/** default size of status bar vs. h scroll bar */ \
int toolbar_status_width; \
/** default window scale */ \
int scale; \
/* Whether to reflow web pages while objects are fetching */ \
bool incremental_reflow; \
/* Minimum time between HTML reflows while objects are fetching */ \
unsigned int min_reflow_period; /* time in cs */ \
bool core_select_menu; \
/** top margin of exported page */ \
int margin_top; \
/** bottom margin of exported page */ \
int margin_bottom; \
/** left margin of exported page */ \
int margin_left; \
/** right margin of exported page*/ \
int margin_right; \
/** scale of exported content*/ \
int export_scale; \
/** suppressing images in printed content*/ \
bool suppress_images; \
/** turning off all backgrounds for printed content*/ \
bool remove_backgrounds; \
/** turning on content loosening for printed content*/ \
bool enable_loosening; \
/** compression of PDF documents*/ \
bool enable_PDF_compression; \
/** setting a password and encoding PDF documents*/ \
bool enable_PDF_password; \
\
/* Fetcher configuration */ \
/** Maximum simultaneous active fetchers */ \
int max_fetchers; \
/** Maximum simultaneous active fetchers per host. \
* (<=option_max_fetchers else it makes no sense) Note that \
* rfc2616 section 8.1.4 says that there should be no more \
* than two keepalive connections per host. None of the main \
* browsers follow this as it slows page fetches down \
* considerably. See \
* https://bugzilla.mozilla.org/show_bug.cgi?id=423377#c4 \
*/ \
int max_fetchers_per_host; \
/** Maximum number of inactive fetchers cached. The total \
* number of handles netsurf will therefore have open is this \
* plus option_max_fetchers. \
*/ \
int max_cached_fetch_handles; \
/** Suppress debug output from cURL. */ \
bool suppress_curl_debug; \
\
/** Whether to allow target="_blank" */ \
bool target_blank; \
\
/** Whether second mouse button opens in new tab */ \
bool button_2_tab; \
\
/* system colours */ \
colour sys_colour_ActiveBorder; \
colour sys_colour_ActiveCaption; \
colour sys_colour_AppWorkspace; \
colour sys_colour_Background; \
colour sys_colour_ButtonFace; \
colour sys_colour_ButtonHighlight; \
colour sys_colour_ButtonShadow; \
colour sys_colour_ButtonText; \
colour sys_colour_CaptionText; \
colour sys_colour_GrayText; \
colour sys_colour_Highlight; \
colour sys_colour_HighlightText; \
colour sys_colour_InactiveBorder; \
colour sys_colour_InactiveCaption; \
colour sys_colour_InactiveCaptionText; \
colour sys_colour_InfoBackground; \
colour sys_colour_InfoText; \
colour sys_colour_Menu; \
colour sys_colour_MenuText; \
colour sys_colour_Scrollbar; \
colour sys_colour_ThreeDDarkShadow; \
colour sys_colour_ThreeDFace; \
colour sys_colour_ThreeDHighlight; \
colour sys_colour_ThreeDLightShadow; \
colour sys_colour_ThreeDShadow; \
colour sys_colour_Window; \
colour sys_colour_WindowFrame; \
colour sys_colour_WindowText
 
#define NSOPTION_MAIN_DEFAULTS \
.http_proxy = false, \
.http_proxy_host = NULL, \
.http_proxy_port = 8080, \
.http_proxy_auth = OPTION_HTTP_PROXY_AUTH_NONE, \
.http_proxy_auth_user = NULL, \
.http_proxy_auth_pass = NULL, \
.font_size = 128, \
.font_min_size = 85, \
.font_sans = NULL, \
.font_serif = NULL, \
.font_mono = NULL, \
.font_cursive = NULL, \
.font_fantasy = NULL, \
.accept_language = NULL, \
.accept_charset = NULL, \
.memory_cache_size = 12 * 1024 * 1024, \
.disc_cache_size = 1024 * 1024 * 1024, \
.disc_cache_age = 28, \
.block_ads = false, \
.do_not_track = false, \
.minimum_gif_delay = 10, \
.send_referer = true, \
.foreground_images = true, \
.background_images = true, \
.animate_images = true, \
.expire_url = 28, \
.font_default = PLOT_FONT_FAMILY_SANS_SERIF, \
.ca_bundle = NULL, \
.ca_path = NULL, \
.cookie_file = NULL, \
.cookie_jar = NULL, \
.homepage_url = NULL, \
.search_url_bar = false, \
.url_suggestion = true, \
.search_provider = 0, \
.window_x = 0, \
.window_y = 0, \
.window_width = 0, \
.window_height = 0, \
.window_screen_width = 0, \
.window_screen_height = 0, \
.toolbar_status_width = 6667, \
.scale = 100, \
.incremental_reflow = true, \
.min_reflow_period = DEFAULT_REFLOW_PERIOD, \
.core_select_menu = false, \
.margin_top = DEFAULT_MARGIN_TOP_MM, \
.margin_bottom = DEFAULT_MARGIN_BOTTOM_MM, \
.margin_left = DEFAULT_MARGIN_LEFT_MM, \
.margin_right = DEFAULT_MARGIN_RIGHT_MM, \
.export_scale = DEFAULT_EXPORT_SCALE * 100, \
.suppress_images = false, \
.remove_backgrounds = false, \
.enable_loosening = true, \
.enable_PDF_compression = true, \
.enable_PDF_password = false, \
.max_fetchers = 24, \
.max_fetchers_per_host = 5, \
.max_cached_fetch_handles = 6, \
.suppress_curl_debug = true, \
.target_blank = true, \
.button_2_tab = true, \
.enable_javascript = true
 
#define NSOPTION_MAIN_SYS_COLOUR_DEFAULTS \
.sys_colour_ActiveBorder = 0x00000000, \
.sys_colour_ActiveCaption = 0x00000000, \
.sys_colour_AppWorkspace = 0x00000000, \
.sys_colour_Background = 0x00000000, \
.sys_colour_ButtonFace = 0x00000000, \
.sys_colour_ButtonHighlight = 0x00000000, \
.sys_colour_ButtonShadow = 0x00000000, \
.sys_colour_ButtonText = 0x00000000, \
.sys_colour_CaptionText = 0x0000000, \
.sys_colour_GrayText = 0x00000000, \
.sys_colour_Highlight = 0x00000000, \
.sys_colour_HighlightText = 0x00000000, \
.sys_colour_InactiveBorder = 0x00000000, \
.sys_colour_InactiveCaption = 0x00000000, \
.sys_colour_InactiveCaptionText = 0x00000000, \
.sys_colour_InfoBackground = 0x00000000, \
.sys_colour_InfoText = 0x00000000, \
.sys_colour_Menu = 0x00000000, \
.sys_colour_MenuText = 0x0000000, \
.sys_colour_Scrollbar = 0x0000000, \
.sys_colour_ThreeDDarkShadow = 0x000000, \
.sys_colour_ThreeDFace = 0x000000, \
.sys_colour_ThreeDHighlight = 0x000000, \
.sys_colour_ThreeDLightShadow = 0x000000, \
.sys_colour_ThreeDShadow = 0x000000, \
.sys_colour_Window = 0x000000, \
.sys_colour_WindowFrame = 0x000000, \
.sys_colour_WindowText = 0x000000
 
 
#define NSOPTION_MAIN_TABLE \
{ "http_proxy", OPTION_BOOL, &nsoptions.http_proxy }, \
{ "http_proxy_host", OPTION_STRING, &nsoptions.http_proxy_host }, \
{ "http_proxy_port", OPTION_INTEGER, &nsoptions.http_proxy_port }, \
{ "http_proxy_auth", OPTION_INTEGER, &nsoptions.http_proxy_auth }, \
{ "http_proxy_auth_user", OPTION_STRING, &nsoptions.http_proxy_auth_user }, \
{ "http_proxy_auth_pass", OPTION_STRING, &nsoptions.http_proxy_auth_pass }, \
{ "font_size", OPTION_INTEGER, &nsoptions.font_size }, \
{ "font_min_size", OPTION_INTEGER, &nsoptions.font_min_size }, \
{ "font_sans", OPTION_STRING, &nsoptions.font_sans }, \
{ "font_serif", OPTION_STRING, &nsoptions.font_serif }, \
{ "font_mono", OPTION_STRING, &nsoptions.font_mono }, \
{ "font_cursive", OPTION_STRING, &nsoptions.font_cursive }, \
{ "font_fantasy", OPTION_STRING, &nsoptions.font_fantasy }, \
{ "accept_language", OPTION_STRING, &nsoptions.accept_language }, \
{ "accept_charset", OPTION_STRING, &nsoptions.accept_charset }, \
{ "memory_cache_size", OPTION_INTEGER, &nsoptions.memory_cache_size }, \
{ "disc_cache_size", OPTION_INTEGER, &nsoptions.disc_cache_size }, \
{ "disc_cache_age", OPTION_INTEGER, &nsoptions.disc_cache_age }, \
{ "block_advertisements", OPTION_BOOL, &nsoptions.block_ads }, \
{ "do_not_track", OPTION_BOOL, &nsoptions.do_not_track }, \
{ "minimum_gif_delay", OPTION_INTEGER, &nsoptions.minimum_gif_delay }, \
{ "send_referer", OPTION_BOOL, &nsoptions.send_referer }, \
{ "foreground_images", OPTION_BOOL, &nsoptions.foreground_images }, \
{ "background_images", OPTION_BOOL, &nsoptions.background_images }, \
{ "animate_images", OPTION_BOOL, &nsoptions.animate_images }, \
{ "enable_javascript", OPTION_BOOL, &nsoptions.enable_javascript}, \
{ "expire_url", OPTION_INTEGER, &nsoptions.expire_url }, \
{ "font_default", OPTION_INTEGER, &nsoptions.font_default }, \
{ "ca_bundle", OPTION_STRING, &nsoptions.ca_bundle }, \
{ "ca_path", OPTION_STRING, &nsoptions.ca_path }, \
{ "cookie_file", OPTION_STRING, &nsoptions.cookie_file }, \
{ "cookie_jar", OPTION_STRING, &nsoptions.cookie_jar }, \
{ "homepage_url", OPTION_STRING, &nsoptions.homepage_url }, \
{ "search_url_bar", OPTION_BOOL, &nsoptions.search_url_bar}, \
{ "search_provider", OPTION_INTEGER, &nsoptions.search_provider}, \
{ "url_suggestion", OPTION_BOOL, &nsoptions.url_suggestion }, \
{ "window_x", OPTION_INTEGER, &nsoptions.window_x }, \
{ "window_y", OPTION_INTEGER, &nsoptions.window_y }, \
{ "window_width", OPTION_INTEGER, &nsoptions.window_width }, \
{ "window_height", OPTION_INTEGER, &nsoptions.window_height }, \
{ "window_screen_width", OPTION_INTEGER, &nsoptions.window_screen_width }, \
{ "window_screen_height", OPTION_INTEGER, &nsoptions.window_screen_height }, \
{ "toolbar_status_size", OPTION_INTEGER, &nsoptions.toolbar_status_width }, \
{ "scale", OPTION_INTEGER, &nsoptions.scale }, \
{ "incremental_reflow", OPTION_BOOL, &nsoptions.incremental_reflow }, \
{ "min_reflow_period", OPTION_INTEGER, &nsoptions.min_reflow_period }, \
{ "core_select_menu", OPTION_BOOL, &nsoptions.core_select_menu }, \
/* Fetcher options */ \
{ "max_fetchers", OPTION_INTEGER, &nsoptions.max_fetchers }, \
{ "max_fetchers_per_host", OPTION_INTEGER, &nsoptions.max_fetchers_per_host }, \
{ "max_cached_fetch_handles", OPTION_INTEGER, &nsoptions.max_cached_fetch_handles }, \
{ "suppress_curl_debug",OPTION_BOOL, &nsoptions.suppress_curl_debug }, \
{ "target_blank", OPTION_BOOL, &nsoptions.target_blank }, \
{ "button_2_tab", OPTION_BOOL, &nsoptions.button_2_tab }, \
/* PDF / Print options*/ \
{ "margin_top", OPTION_INTEGER, &nsoptions.margin_top}, \
{ "margin_bottom", OPTION_INTEGER, &nsoptions.margin_bottom}, \
{ "margin_left", OPTION_INTEGER, &nsoptions.margin_left}, \
{ "margin_right", OPTION_INTEGER, &nsoptions.margin_right}, \
{ "export_scale", OPTION_INTEGER, &nsoptions.export_scale}, \
{ "suppress_images", OPTION_BOOL, &nsoptions.suppress_images}, \
{ "remove_backgrounds", OPTION_BOOL, &nsoptions.remove_backgrounds}, \
{ "enable_loosening", OPTION_BOOL, &nsoptions.enable_loosening}, \
{ "enable_PDF_compression", OPTION_BOOL, &nsoptions.enable_PDF_compression}, \
{ "enable_PDF_password", OPTION_BOOL, &nsoptions.enable_PDF_password}, \
\
/* System colours */ \
{ "sys_colour_ActiveBorder",OPTION_COLOUR,&nsoptions.sys_colour_ActiveBorder }, \
{ "sys_colour_ActiveCaption",OPTION_COLOUR,&nsoptions.sys_colour_ActiveCaption }, \
{ "sys_colour_AppWorkspace",OPTION_COLOUR,&nsoptions.sys_colour_AppWorkspace }, \
{ "sys_colour_Background",OPTION_COLOUR,&nsoptions.sys_colour_Background }, \
{ "sys_colour_ButtonFace",OPTION_COLOUR,&nsoptions.sys_colour_ButtonFace }, \
{ "sys_colour_ButtonHighlight",OPTION_COLOUR,&nsoptions.sys_colour_ButtonHighlight }, \
{ "sys_colour_ButtonShadow",OPTION_COLOUR,&nsoptions.sys_colour_ButtonShadow }, \
{ "sys_colour_ButtonText",OPTION_COLOUR,&nsoptions.sys_colour_ButtonText }, \
{ "sys_colour_CaptionText",OPTION_COLOUR,&nsoptions.sys_colour_CaptionText }, \
{ "sys_colour_GrayText",OPTION_COLOUR,&nsoptions.sys_colour_GrayText }, \
{ "sys_colour_Highlight",OPTION_COLOUR,&nsoptions.sys_colour_Highlight }, \
{ "sys_colour_HighlightText",OPTION_COLOUR,&nsoptions.sys_colour_HighlightText }, \
{ "sys_colour_InactiveBorder",OPTION_COLOUR,&nsoptions.sys_colour_InactiveBorder }, \
{ "sys_colour_InactiveCaption",OPTION_COLOUR,&nsoptions.sys_colour_InactiveCaption }, \
{ "sys_colour_InactiveCaptionText",OPTION_COLOUR,&nsoptions.sys_colour_InactiveCaptionText }, \
{ "sys_colour_InfoBackground",OPTION_COLOUR,&nsoptions.sys_colour_InfoBackground }, \
{ "sys_colour_InfoText",OPTION_COLOUR,&nsoptions.sys_colour_InfoText }, \
{ "sys_colour_Menu",OPTION_COLOUR,&nsoptions.sys_colour_Menu }, \
{ "sys_colour_MenuText",OPTION_COLOUR,&nsoptions.sys_colour_MenuText }, \
{ "sys_colour_Scrollbar",OPTION_COLOUR,&nsoptions.sys_colour_Scrollbar }, \
{ "sys_colour_ThreeDDarkShadow",OPTION_COLOUR,&nsoptions.sys_colour_ThreeDDarkShadow }, \
{ "sys_colour_ThreeDFace",OPTION_COLOUR,&nsoptions.sys_colour_ThreeDFace }, \
{ "sys_colour_ThreeDHighlight",OPTION_COLOUR,&nsoptions.sys_colour_ThreeDHighlight }, \
{ "sys_colour_ThreeDLightShadow", OPTION_COLOUR,&nsoptions.sys_colour_ThreeDLightShadow }, \
{ "sys_colour_ThreeDShadow", OPTION_COLOUR,&nsoptions.sys_colour_ThreeDShadow }, \
{ "sys_colour_Window", OPTION_COLOUR,&nsoptions.sys_colour_Window }, \
{ "sys_colour_WindowFrame", OPTION_COLOUR,&nsoptions.sys_colour_WindowFrame }, \
{ "sys_colour_WindowText", OPTION_COLOUR,&nsoptions.sys_colour_WindowText }
 
#endif
/programs/network/netsurf/netsurf/desktop/plot_style.c
0,0 → 1,175
/*
* Copyright 2009 Vincent Sanders <vince@kyllikki.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/**
* \file desktop/plot_style.c
* \brief Plotter global styles.
*
* These plot styles are globaly available and used in many places.
*/
 
#include "desktop/plotters.h"
 
static plot_style_t plot_style_fill_white_static = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = 0xffffff,
};
plot_style_t *plot_style_fill_white = &plot_style_fill_white_static;
 
static plot_style_t plot_style_fill_black_static = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = 0x0,
};
plot_style_t *plot_style_fill_black = &plot_style_fill_black_static;
 
static plot_style_t plot_style_fill_red_static = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = 0x000000ff,
};
plot_style_t *plot_style_fill_red = &plot_style_fill_red_static;
 
/* Box model debug outline styles for content, padding and margin edges */
static const plot_style_t plot_style_content_edge_static = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = 0x00ff0000,
.stroke_width = 1,
};
plot_style_t const * const plot_style_content_edge =
&plot_style_content_edge_static;
 
static const plot_style_t plot_style_padding_edge_static = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = 0x000000ff,
.stroke_width = 1,
};
plot_style_t const * const plot_style_padding_edge =
&plot_style_padding_edge_static;
 
static const plot_style_t plot_style_margin_edge_static = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = 0x0000ffff,
.stroke_width = 1,
};
plot_style_t const * const plot_style_margin_edge =
&plot_style_margin_edge_static;
 
/* Broken object replacement styles */
static const plot_style_t plot_style_broken_object_static = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = 0x008888ff,
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = 0x000000ff,
.stroke_width = 1,
};
plot_style_t const * const plot_style_broken_object =
&plot_style_broken_object_static;
 
static const plot_font_style_t plot_fstyle_broken_object_static = {
.family = PLOT_FONT_FAMILY_SANS_SERIF,
.size = 16 * FONT_SIZE_SCALE,
.weight = 400,
.flags = FONTF_NONE,
.background = 0x8888ff,
.foreground = 0x000044,
};
plot_font_style_t const * const plot_fstyle_broken_object =
&plot_fstyle_broken_object_static;
 
/* caret style used in html_redraw_caret */
static plot_style_t plot_style_caret_static = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = 0x0000ff, /* todo - choose a proper colour */
};
plot_style_t *plot_style_caret = &plot_style_caret_static;
 
 
 
/* html redraw widget styles */
 
/** plot style for filled widget base colour. */
static plot_style_t plot_style_fill_wbasec_static = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = WIDGET_BASEC,
};
plot_style_t *plot_style_fill_wbasec = &plot_style_fill_wbasec_static;
 
/** plot style for dark filled widget base colour . */
static plot_style_t plot_style_fill_darkwbasec_static = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = double_darken_colour(WIDGET_BASEC),
};
plot_style_t *plot_style_fill_darkwbasec = &plot_style_fill_darkwbasec_static;
 
/** plot style for light filled widget base colour. */
static plot_style_t plot_style_fill_lightwbasec_static = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = double_lighten_colour(WIDGET_BASEC),
};
plot_style_t *plot_style_fill_lightwbasec = &plot_style_fill_lightwbasec_static;
 
 
/** plot style for widget background. */
static plot_style_t plot_style_fill_wblobc_static = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = WIDGET_BLOBC,
};
plot_style_t *plot_style_fill_wblobc = &plot_style_fill_wblobc_static;
 
/** plot style for checkbox cross. */
static plot_style_t plot_style_stroke_wblobc_static = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = WIDGET_BLOBC,
.stroke_width = 2,
};
plot_style_t *plot_style_stroke_wblobc = &plot_style_stroke_wblobc_static;
 
/** stroke style for widget double dark colour. */
static plot_style_t plot_style_stroke_darkwbasec_static = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = double_darken_colour(WIDGET_BASEC),
};
plot_style_t *plot_style_stroke_darkwbasec = &plot_style_stroke_darkwbasec_static;
 
/** stroke style for widget double light colour. */
static plot_style_t plot_style_stroke_lightwbasec_static = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = double_lighten_colour(WIDGET_BASEC),
};
plot_style_t *plot_style_stroke_lightwbasec = &plot_style_stroke_lightwbasec_static;
 
/* history styles */
 
/** stroke style for history core. */
static plot_style_t plot_style_stroke_history_static = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = HISTORY_COLOUR_LINES,
.stroke_width = 2,
};
plot_style_t *plot_style_stroke_history = &plot_style_stroke_history_static;
 
/* Generic font style */
static const plot_font_style_t plot_style_font_static = {
.family = PLOT_FONT_FAMILY_SANS_SERIF,
.size = 8 * FONT_SIZE_SCALE,
.weight = 400,
.flags = FONTF_NONE,
.background = 0xffffff,
.foreground = 0x000000,
};
plot_font_style_t const * const plot_style_font = &plot_style_font_static;
 
/programs/network/netsurf/netsurf/desktop/plot_style.h
0,0 → 1,185
/*
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Plotter styles.
*/
 
#ifndef _NETSURF_DESKTOP_PLOT_STYLE_H_
#define _NETSURF_DESKTOP_PLOT_STYLE_H_
 
#include <stdint.h>
 
/* html widget colours */
#define WIDGET_BASEC 0xd9d9d9
#define WIDGET_BLOBC 0x000000
 
/* Darken a colour by taking three quarters of each channel's intensity */
#define darken_colour(c1) \
((((3 * ((c1 >> 16) & 0xff)) >> 2) << 16) | \
(((3 * ((c1 >> 8) & 0xff)) >> 2) << 8) | \
(((3 * ( c1 & 0xff)) >> 2) << 0))
 
/* Darken a colour by taking nine sixteenths of each channel's intensity */
#define double_darken_colour(c1) \
((((9 * ((c1 >> 16) & 0xff)) >> 4) << 16) | \
(((9 * ((c1 >> 8) & 0xff)) >> 4) << 8) | \
(((9 * ( c1 & 0xff)) >> 4) << 0))
 
/* Lighten a colour by taking three quarters of each channel's intensity
* and adding a full quarter
*/
#define lighten_colour(c1) \
(((((3 * ((c1 >> 16) & 0xff)) >> 2) + 64) << 16) | \
((((3 * ((c1 >> 8) & 0xff)) >> 2) + 64) << 8) | \
((((3 * ( c1 & 0xff)) >> 2) + 64) << 0))
 
/* Lighten a colour by taking nine sixteenths of each channel's intensity and
* adding a full intensity 7/16ths */
#define double_lighten_colour(c1) \
(((((9 * ((c1 >> 16) & 0xff)) >> 4) + 112) << 16) | \
((((9 * ((c1 >> 8) & 0xff)) >> 4) + 112) << 8) | \
((((9 * ( c1 & 0xff)) >> 4) + 112) << 0))
 
/* Blend two colours by taking half the intensity of each channel in the first
* colour and adding them to half the intensity of each channel in the second
* colour */
#define blend_colour(c0, c1) \
(((((c0 >> 16) & 0xff) + ((c1 >> 16) & 0xff)) >> 1) << 16) | \
(((((c0 >> 8) & 0xff) + ((c1 >> 8) & 0xff)) >> 1) << 8) | \
(((( c0 & 0xff) + ( c1 & 0xff)) >> 1) << 0)
 
/* get a bitmap pixel (image/bitmap.h) into a plot colour */
#define pixel_to_colour(b) \
b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)
 
/**
* Colour type: XBGR
*/
typedef uint32_t colour;
 
/**
* Magical transparent value
*/
#define NS_TRANSPARENT 0x01000000
 
/**
* Type of plot operation
*/
typedef enum {
PLOT_OP_TYPE_NONE = 0, /**< No operation */
PLOT_OP_TYPE_SOLID, /**< Solid colour */
PLOT_OP_TYPE_DOT, /**< Dotted plot */
PLOT_OP_TYPE_DASH, /**< Dashed plot */
} plot_operation_type_t;
 
/**
* Plot style for stroke/fill plotters
*/
typedef struct {
plot_operation_type_t stroke_type; /**< Stroke plot type */
int stroke_width; /**< Width of stroke, in pixels */
colour stroke_colour; /**< Colour of stroke */
plot_operation_type_t fill_type; /**< Fill plot type */
colour fill_colour; /**< Colour of fill */
} plot_style_t;
 
/**
* Generic font family type
*/
typedef enum {
PLOT_FONT_FAMILY_SANS_SERIF = 0,
PLOT_FONT_FAMILY_SERIF,
PLOT_FONT_FAMILY_MONOSPACE,
PLOT_FONT_FAMILY_CURSIVE,
PLOT_FONT_FAMILY_FANTASY,
PLOT_FONT_FAMILY_COUNT /**< Number of generic families */
} plot_font_generic_family_t;
 
/**
* Font plot flags
*/
typedef unsigned long plot_font_flags_t;
#define FONTF_NONE 0
#define FONTF_ITALIC 1
#define FONTF_OBLIQUE 2
#define FONTF_SMALLCAPS 4
 
/**
* Scaling factor for font sizes
*/
#define FONT_SIZE_SCALE 1024
 
/**
* Font style for plotting
*/
typedef struct {
plot_font_generic_family_t family; /**< Generic family to plot with */
int size; /**< Font size, in points * FONT_SIZE_SCALE */
int weight; /**< Font weight: value in range [100,900] as per CSS */
plot_font_flags_t flags; /**< Font flags */
colour background; /**< Background colour to blend to, if appropriate */
colour foreground; /**< Colour of text */
} plot_font_style_t;
 
/* global fill styles */
extern plot_style_t *plot_style_fill_white;
extern plot_style_t *plot_style_fill_red;
extern plot_style_t *plot_style_fill_black;
 
/* Box model debug outline styles for content, padding and margin edges */
extern plot_style_t const * const plot_style_content_edge;
extern plot_style_t const * const plot_style_padding_edge;
extern plot_style_t const * const plot_style_margin_edge;
 
/* Broken object replacement styles */
extern plot_style_t const * const plot_style_broken_object;
extern plot_font_style_t const * const plot_fstyle_broken_object;
 
 
/* other styles */
extern plot_style_t *plot_style_caret;
extern plot_style_t *plot_style_stroke_history;
extern plot_style_t *plot_style_fill_wbasec;
extern plot_style_t *plot_style_fill_darkwbasec;
extern plot_style_t *plot_style_fill_lightwbasec;
extern plot_style_t *plot_style_fill_wblobc;
extern plot_style_t *plot_style_stroke_wblobc;
extern plot_style_t *plot_style_stroke_darkwbasec;
extern plot_style_t *plot_style_stroke_lightwbasec;
 
/* Default font style */
extern plot_font_style_t const * const plot_style_font;
 
#ifndef HISTORY_COLOUR_SELECTED
#define HISTORY_COLOUR_SELECTED 0xFF0000
#endif
 
#ifndef HISTORY_COLOUR_FOREGROUND
#define HISTORY_COLOUR_FOREGROUND 0x333333
#endif
 
#ifndef HISTORY_COLOUR_BACKGROUND
#define HISTORY_COLOUR_BACKGROUND 0xFFFFFF
#endif
 
#ifndef HISTORY_COLOUR_LINES
#define HISTORY_COLOUR_LINES HISTORY_COLOUR_FOREGROUND
#endif
 
#endif
/programs/network/netsurf/netsurf/desktop/plotters.h
0,0 → 1,147
/*
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Target independent plotting (interface).
*/
 
#ifndef _NETSURF_DESKTOP_PLOTTERS_H_
#define _NETSURF_DESKTOP_PLOTTERS_H_
 
#include <stdbool.h>
#include "css/css.h"
#include "content/content.h"
#include "desktop/plot_style.h"
 
struct bitmap;
 
typedef unsigned long bitmap_flags_t;
#define BITMAPF_NONE 0
#define BITMAPF_REPEAT_X 1
#define BITMAPF_REPEAT_Y 2
 
 
/** Set of target specific plotting functions.
*
* The functions are:
* arc - Plots an arc, around (x,y), from anticlockwise from angle1 to
* angle2. Angles are measured anticlockwise from horizontal, in
* degrees.
* disc - Plots a circle, centered on (x,y), which is optionally filled.
* line - Plots a line from (x0,y0) to (x1,y1). Coordinates are at
* centre of line width/thickness.
* path - Plots a path consisting of cubic Bezier curves. Line colour is
* given by c and fill colour is given by fill.
* polygon - Plots a filled polygon with straight lines between points.
* The lines around the edge of the ploygon are not plotted. The
* polygon is filled with the non-zero winding rule.
* rectangle - Plots a rectangle outline. The line can be solid, dotted or
* dashed. Top left corner at (x0,y0) and rectangle has given
* width and height.
* fill - Plots a filled rectangle. Top left corner at (x0,y0), bottom
* right corner at (x1,y1). Note: (x0,y0) is inside filled area,
* but (x1,y1) is below and to the right. See diagram below.
* clip - Sets a clip rectangle for subsequent plots.
* text - Plots text. (x,y) is the coordinate of the left hand side of
* the text's baseline. The text is UTF-8 encoded. The colour, c,
* is the colour of the text. Background colour, bg, may be used
* optionally to attempt to provide anti-aliased text without
* screen reads. Font information is provided in the style.
* bitmap - Tiled plot of a bitmap image. (x,y) gives the top left
* coordinate of an explicitly placed tile. From this tile the
* image can repeat in all four directions -- up, down, left and
* right -- to the extents given by the current clip rectangle.
* The bitmap_flags say whether to tile in the x and y
* directions. If not tiling in x or y directions, the single
* image is plotted. The width and height give the dimensions
* the image is to be scaled to.
* group_start - Start of a group of objects. Used when plotter implements
* export to a vector graphics file format. (Optional.)
* group_end - End of the most recently started group. (Optional.)
* flush - Only used internally by the knockout code. Should be NULL in
* any front end display plotters or export plotters.
*
* Plotter options:
* option_knockout - Optimisation particularly for unaccelerated screen
* redraw. It tries to avoid plotting to the same area
* more than once. See desktop/knockout.c
*
* Coordinates are from top left of canvas and (0,0) is the top left grid
* denomination. If a "fill" is drawn from (0,0) to (4,3), the result is:
*
* 0 1 2 3 4 5
* +-+-+-+-+-+-
* 0 |#|#|#|#| |
* +-+-+-+-+-+-
* 1 |#|#|#|#| |
* +-+-+-+-+-+-
* 2 |#|#|#|#| |
* +-+-+-+-+-+-
* 3 | | | | | |
*/
struct plotter_table {
/* clipping operations */
bool (*clip)(const struct rect *clip);
 
/* shape primatives */
bool (*arc)(int x, int y, int radius, int angle1, int angle2, const plot_style_t *pstyle);
bool (*disc)(int x, int y, int radius, const plot_style_t *pstyle);
bool (*line)(int x0, int y0, int x1, int y1, const plot_style_t *pstyle);
bool (*rectangle)(int x0, int y0, int x1, int y1, const plot_style_t *pstyle);
bool (*polygon)(const int *p, unsigned int n, const plot_style_t *pstyle);
 
/* complex path (for SVG) */
bool (*path)(const float *p, unsigned int n, colour fill, float width,
colour c, const float transform[6]);
 
/* Image */
bool (*bitmap)(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bitmap_flags_t flags);
 
/**
* Text.
*
* \param x x coordinate
* \param y y coordinate
* \param text UTF-8 string to plot
* \param length length of string, in bytes
* \param fstyle plot style for this text
* \return true on success, false on error and error reported
*/
bool (*text)(int x, int y, const char *text, size_t length,
const plot_font_style_t *fstyle);
 
/* optional callbacks */
bool (*group_start)(const char *name); /**< optional, may be NULL */
bool (*group_end)(void); /**< optional, may be NULL */
bool (*flush)(void); /**< optional, may be NULL */
 
/* flags */
bool option_knockout; /**< set if knockout rendering is required */
};
 
enum path_command {
PLOTTER_PATH_MOVE,
PLOTTER_PATH_CLOSE,
PLOTTER_PATH_LINE,
PLOTTER_PATH_BEZIER,
};
 
 
#endif
/programs/network/netsurf/netsurf/desktop/print.c
0,0 → 1,327
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Output-in-pages implementation
*/
 
#include "utils/config.h"
 
#include <assert.h>
#include <string.h>
 
#include <dom/dom.h>
 
#include "content/content.h"
#include "content/hlcache.h"
#include "css/utils.h"
#include "desktop/options.h"
#include "desktop/print.h"
#include "desktop/printer.h"
#include "render/box.h"
#include "utils/log.h"
#include "utils/talloc.h"
#include "utils/types.h"
 
/* Default print settings */
#define DEFAULT_PAGE_WIDTH 595
#define DEFAULT_PAGE_HEIGHT 840
#define DEFAULT_COPIES 1
 
static hlcache_handle *print_init(hlcache_handle *, struct print_settings *);
static bool print_apply_settings(hlcache_handle *, struct print_settings *);
 
static float page_content_width, page_content_height;
static hlcache_handle *printed_content;
static float done_height;
 
bool html_redraw_printing = false;
int html_redraw_printing_border = 0;
int html_redraw_printing_top_cropped = 0;
 
/**
* This function calls print setup, prints page after page until the whole
* content is printed calls cleaning up afterwise.
*
* \param content The content to be printed
* \param printer The printer interface for the printer to be used
* \param settings The settings for printing to use
* \return true if successful, false otherwise
*/
bool print_basic_run(hlcache_handle *content,
const struct printer *printer,
struct print_settings *settings)
{
bool ret = true;
 
assert(content != NULL && printer != NULL && settings != NULL);
if (print_set_up(content, printer, settings, NULL))
return false;
 
while (ret && (done_height < content_get_height(printed_content)) ) {
ret = print_draw_next_page(printer, settings);
}
 
print_cleanup(content, printer, settings);
return ret;
}
 
/**
* This function prepares the content to be printed. The current browser content
* is duplicated and resized, printer initialization is called.
*
* \param content The content to be printed
* \param printer The printer interface for the printer to be used
* \param settings The settings for printing to use
* \param height updated to the height of the printed content
* \return true if successful, false otherwise
*/
bool print_set_up(hlcache_handle *content,
const struct printer *printer, struct print_settings *settings,
double *height)
{
printed_content = print_init(content, settings);
if (printed_content == NULL)
return false;
print_apply_settings(printed_content, settings);
 
if (height)
*height = content_get_height(printed_content);
printer->print_begin(settings);
 
done_height = 0;
return true;
}
 
/**
* This function draws one page, beginning with the height offset of done_height
*
* \param printer The printer interface for the printer to be used
* \param settings The settings for printing to use
* \return true if successful, false otherwise
*/
bool print_draw_next_page(const struct printer *printer,
struct print_settings *settings)
{
struct rect clip;
struct content_redraw_data data;
struct redraw_context ctx = {
.interactive = false,
.background_images = !nsoption_bool(remove_backgrounds),
.plot = printer->plotter
};
 
html_redraw_printing_top_cropped = INT_MAX;
 
clip.x0 = 0;
clip.y0 = 0;
clip.x1 = page_content_width * settings->scale;
clip.y1 = page_content_height * settings->scale;
 
data.x = 0;
data.y = -done_height;
data.width = 0;
data.height = 0;
data.background_colour = 0xFFFFFF;
data.scale = settings->scale;
data.repeat_x = false;
data.repeat_y = false;
 
html_redraw_printing = true;
html_redraw_printing_border = clip.y1;
 
printer->print_next_page();
if (!content_redraw(printed_content, &data, &clip, &ctx))
return false;
 
done_height += page_content_height -
(html_redraw_printing_top_cropped != INT_MAX ?
clip.y1 - html_redraw_printing_top_cropped : 0) /
settings->scale;
 
return true;
}
 
/**
* The content passed to the function is duplicated with its boxes, font
* measuring functions are being set.
*
* \param content The content to be printed
* \param settings The settings for printing to use
* \return true if successful, false otherwise
*/
hlcache_handle *print_init(hlcache_handle *content,
struct print_settings *settings)
{
hlcache_handle* printed_content;
hlcache_handle_clone(content, &printed_content);
return printed_content;
}
 
/**
* The content is resized to fit page width.
*
* \param content The content to be printed
* \param settings The settings for printing to use
* \return true if successful, false otherwise
*/
bool print_apply_settings(hlcache_handle *content,
struct print_settings *settings)
{
if (settings == NULL)
return false;
/*Apply settings - adjust page size etc*/
 
page_content_width = (settings->page_width -
FIXTOFLT(FSUB(settings->margins[MARGINLEFT],
settings->margins[MARGINRIGHT]))) / settings->scale;
page_content_height = (settings->page_height -
FIXTOFLT(FSUB(settings->margins[MARGINTOP],
settings->margins[MARGINBOTTOM]))) / settings->scale;
content_reformat(content, false, page_content_width, 0);
 
LOG(("New layout applied.New height = %d ; New width = %d ",
content_get_height(content),
content_get_width(content)));
return true;
}
 
/**
* Memory allocated during printing is being freed here.
*
* \param content The original content
* \param printer The printer interface for the printer to be used
* \return true if successful, false otherwise
*/
bool print_cleanup(hlcache_handle *content, const struct printer *printer,
struct print_settings *settings)
{
printer->print_end();
html_redraw_printing = false;
if (printed_content) {
hlcache_handle_release(printed_content);
}
free((void *)settings->output);
free(settings);
return true;
}
 
/**
* Generates one of the predefined print settings sets.
*
* \param configuration the requested configuration
* \param filename the filename or NULL
* \param font handling functions
* \return print_settings in case if successful, NULL if unknown configuration \
* or lack of memory.
*/
struct print_settings *print_make_settings(print_configuration configuration,
const char *filename, const struct font_functions *font_func)
{
struct print_settings *settings;
css_fixed length = 0;
css_unit unit = CSS_UNIT_MM;
switch (configuration){
case PRINT_DEFAULT:
settings = (struct print_settings*)
malloc(sizeof(struct print_settings));
if (settings == NULL)
return NULL;
settings->page_width = DEFAULT_PAGE_WIDTH;
settings->page_height = DEFAULT_PAGE_HEIGHT;
settings->copies = DEFAULT_COPIES;
 
settings->scale = DEFAULT_EXPORT_SCALE;
length = INTTOFIX(DEFAULT_MARGIN_LEFT_MM);
settings->margins[MARGINLEFT] =
nscss_len2px(length, unit, NULL);
length = INTTOFIX(DEFAULT_MARGIN_RIGHT_MM);
settings->margins[MARGINRIGHT] =
nscss_len2px(length, unit, NULL);
length = INTTOFIX(DEFAULT_MARGIN_TOP_MM);
settings->margins[MARGINTOP] =
nscss_len2px(length, unit, NULL);
length = INTTOFIX(DEFAULT_MARGIN_BOTTOM_MM);
settings->margins[MARGINBOTTOM] =
nscss_len2px(length, unit, NULL);
break;
/* use settings from the Export options tab */
case PRINT_OPTIONS:
settings = (struct print_settings*)
malloc(sizeof(struct print_settings));
if (settings == NULL)
return NULL;
settings->page_width = DEFAULT_PAGE_WIDTH;
settings->page_height = DEFAULT_PAGE_HEIGHT;
settings->copies = DEFAULT_COPIES;
settings->scale = (float)nsoption_int(export_scale) / 100;
length = INTTOFIX(nsoption_int(margin_left));
settings->margins[MARGINLEFT] =
nscss_len2px(length, unit, NULL);
length = INTTOFIX(nsoption_int(margin_right));
settings->margins[MARGINRIGHT] =
nscss_len2px(length, unit, NULL);
length = INTTOFIX(nsoption_int(margin_top));
settings->margins[MARGINTOP] =
nscss_len2px(length, unit, NULL);
length = INTTOFIX(nsoption_int(margin_bottom));
settings->margins[MARGINBOTTOM] =
nscss_len2px(length, unit, NULL);
break;
default:
return NULL;
}
 
/* Set font functions */
settings->font_func = font_func;
 
/* Output filename, or NULL if printing */
if (filename != NULL) {
settings->output = strdup(filename);
if (settings->output == NULL) {
free(settings);
return NULL;
}
} else
settings->output = NULL;
 
return settings;
}
 
/programs/network/netsurf/netsurf/desktop/print.h
0,0 → 1,87
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Conception:
* Generalized output-in-pages. Allows the current content to be 'printed':
* either into a pdf file (any other later?) or to any kind of other output
* destination that divides the website into pages - as a printer.
* The basic usage is calling print_basic_run which sets everything up,
* prints page after page until the whole content is printed and cleans
* everyting up.
* If there are any other, printer specific routines to be performed in the
* meantime - there can be set up any other printing funcion, which can use
* print_set_up, print_draw_next_page and print_cleanup directly.
*/
 
#ifndef NETSURF_DESKTOP_PRINT_H
#define NETSURF_DESKTOP_PRINT_H
 
#include <stdbool.h>
 
#include "css/css.h"
 
struct hlcache_handle;
struct printer;
 
enum { MARGINLEFT = 0, MARGINRIGHT = 1, MARGINTOP = 2, MARGINBOTTOM = 3};
 
/** Predefined printing configuration names*/
typedef enum { PRINT_DEFAULT, PRINT_OPTIONS } print_configuration;
 
/** Settings for a print - filled in by print_make_settings or
* 'manually' by the caller
*/
struct print_settings{
/*Standard parameters*/
float page_width, page_height;
css_fixed margins[4];
float scale;
 
unsigned int copies;
 
/*Output destinations - file/printer name*/
const char *output;
 
/*the functions used to measure fonts*/
const struct font_functions *font_func;
};
 
 
bool print_basic_run(struct hlcache_handle *, const struct printer *,
struct print_settings *);
bool print_set_up(struct hlcache_handle *content, const struct printer *printer,
struct print_settings *settings, double *height);
bool print_draw_next_page(const struct printer *printer,
struct print_settings *settings);
bool print_cleanup(struct hlcache_handle *, const struct printer *,
struct print_settings *settings);
 
struct print_settings *print_make_settings(print_configuration configuration,
const char *url, const struct font_functions *font_func);
 
/*is the content currently redrawn for printing?*/
extern bool html_redraw_printing;
/*if something is partially under this Y coordinate it won't be drawn...*/
extern int html_redraw_printing_border;
/*...and the highest of the tops of all cropped elements will be remembered*/
extern int html_redraw_printing_top_cropped;
 
#endif
 
/programs/network/netsurf/netsurf/desktop/printer.h
0,0 → 1,41
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Printer interface - contains plotter to use, functions for
* initialization, handling pages and cleaning up.
*/
 
#ifndef NETSURF_DESKTOP_PRINTER_H
#define NETSURF_DESKTOP_PRINTER_H
 
#include "desktop/plotters.h"
#include "desktop/print.h"
 
/** Printer interface */
struct printer{
const struct plotter_table *plotter;
 
bool (*print_begin) (struct print_settings*);
 
bool (*print_next_page)(void);
 
void (*print_end)(void);
};
 
#endif
/programs/network/netsurf/netsurf/desktop/save_complete.c
0,0 → 1,1212
/*
* Copyright 2012 John-Mark Bell <jmb@netsurf-browser.org>
* Copyright 2004-2007 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Save HTML document with dependencies (implementation).
*/
 
#include "utils/config.h"
 
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>
 
#include <dom/dom.h>
 
#include "content/content.h"
#include "content/hlcache.h"
#include "css/css.h"
#include "desktop/save_complete.h"
#include "render/box.h"
#include "render/html.h"
#include "utils/corestrings.h"
#include "utils/log.h"
#include "utils/nsurl.h"
#include "utils/utf8.h"
#include "utils/utils.h"
 
regex_t save_complete_import_re;
 
/** An entry in save_complete_list. */
typedef struct save_complete_entry {
hlcache_handle *content;
struct save_complete_entry *next; /**< Next entry in list */
} save_complete_entry;
 
typedef struct save_complete_ctx {
const char *path;
save_complete_entry *list;
save_complete_set_type_cb set_type;
 
nsurl *base;
FILE *fp;
enum { STATE_NORMAL, STATE_IN_STYLE } iter_state;
} save_complete_ctx;
 
typedef enum {
EVENT_ENTER,
EVENT_LEAVE
} save_complete_event_type;
 
 
static bool save_complete_save_html(save_complete_ctx *ctx, hlcache_handle *c,
bool index);
static bool save_complete_save_imported_sheets(save_complete_ctx *ctx,
struct nscss_import *imports, uint32_t import_count);
 
 
static void save_complete_ctx_initialise(save_complete_ctx *ctx,
const char *path, save_complete_set_type_cb set_type)
{
ctx->path = path;
ctx->list = NULL;
ctx->set_type = set_type;
}
 
static void save_complete_ctx_finalise(save_complete_ctx *ctx)
{
save_complete_entry *list = ctx->list;
 
while (list != NULL) {
save_complete_entry *next = list->next;
free(list);
list = next;
}
}
 
static bool save_complete_ctx_add_content(save_complete_ctx *ctx,
hlcache_handle *content)
{
save_complete_entry *entry;
 
entry = malloc(sizeof (*entry));
if (entry == NULL)
return false;
 
entry->content = content;
entry->next = ctx->list;
ctx->list = entry;
 
return true;
}
 
 
static hlcache_handle *save_complete_ctx_find_content(save_complete_ctx *ctx,
const nsurl *url)
{
save_complete_entry *entry;
 
for (entry = ctx->list; entry != NULL; entry = entry->next)
if (nsurl_compare(url,
hlcache_handle_get_url(entry->content),
NSURL_COMPLETE))
return entry->content;
 
return NULL;
}
 
 
static bool save_complete_ctx_has_content(save_complete_ctx *ctx,
hlcache_handle *content)
{
save_complete_entry *entry;
 
for (entry = ctx->list; entry != NULL; entry = entry->next)
if (entry->content == content)
return true;
 
return false;
}
 
static bool save_complete_save_buffer(save_complete_ctx *ctx,
const char *leafname, const char *data, size_t data_len,
lwc_string *mime_type)
{
FILE *fp;
bool error;
char fullpath[PATH_MAX];
 
strncpy(fullpath, ctx->path, sizeof fullpath);
error = path_add_part(fullpath, sizeof fullpath, leafname);
if (error == false) {
warn_user("NoMemory", NULL);
return false;
}
 
fp = fopen(fullpath, "wb");
if (fp == NULL) {
LOG(("fopen(): errno = %i", errno));
warn_user("SaveError", strerror(errno));
return false;
}
 
fwrite(data, sizeof(*data), data_len, fp);
 
fclose(fp);
 
if (ctx->set_type != NULL)
ctx->set_type(fullpath, mime_type);
 
return true;
}
 
/**
* Rewrite stylesheet \@import rules for save complete.
*
* \param source stylesheet source
* \param size size of source
* \param base url of stylesheet
* \param osize updated with the size of the result
* \return converted source, or NULL on out of memory
*/
 
static char *save_complete_rewrite_stylesheet_urls(save_complete_ctx *ctx,
const char *source, unsigned long size, const nsurl *base,
unsigned long *osize)
{
char *rewritten;
unsigned long offset = 0;
unsigned int imports = 0;
nserror error;
 
/* count number occurrences of @import to (over)estimate result size */
/* can't use strstr because source is not 0-terminated string */
for (offset = 0; SLEN("@import") < size &&
offset <= size - SLEN("@import"); offset++) {
if (source[offset] == '@' &&
tolower(source[offset + 1]) == 'i' &&
tolower(source[offset + 2]) == 'm' &&
tolower(source[offset + 3]) == 'p' &&
tolower(source[offset + 4]) == 'o' &&
tolower(source[offset + 5]) == 'r' &&
tolower(source[offset + 6]) == 't')
imports++;
}
 
rewritten = malloc(size + imports * 20);
if (rewritten == NULL)
return NULL;
*osize = 0;
 
offset = 0;
while (offset < size) {
const char *import_url = NULL;
char *import_url_copy;
int import_url_len = 0;
nsurl *url = NULL;
regmatch_t match[11];
int m = regexec(&save_complete_import_re, source + offset,
11, match, 0);
if (m)
break;
 
if (match[2].rm_so != -1) {
import_url = source + offset + match[2].rm_so;
import_url_len = match[2].rm_eo - match[2].rm_so;
} else if (match[4].rm_so != -1) {
import_url = source + offset + match[4].rm_so;
import_url_len = match[4].rm_eo - match[4].rm_so;
} else if (match[6].rm_so != -1) {
import_url = source + offset + match[6].rm_so;
import_url_len = match[6].rm_eo - match[6].rm_so;
} else if (match[8].rm_so != -1) {
import_url = source + offset + match[8].rm_so;
import_url_len = match[8].rm_eo - match[8].rm_so;
} else if (match[10].rm_so != -1) {
import_url = source + offset + match[10].rm_so;
import_url_len = match[10].rm_eo - match[10].rm_so;
}
assert(import_url != NULL);
 
import_url_copy = strndup(import_url, import_url_len);
if (import_url_copy == NULL) {
free(rewritten);
return NULL;
}
 
error = nsurl_join(base, import_url_copy, &url);
free(import_url_copy);
if (error == NSERROR_NOMEM) {
free(rewritten);
return NULL;
}
 
/* copy data before match */
memcpy(rewritten + *osize, source + offset, match[0].rm_so);
*osize += match[0].rm_so;
 
if (url != NULL) {
hlcache_handle *content;
content = save_complete_ctx_find_content(ctx, url);
if (content != NULL) {
/* replace import */
char buf[64];
snprintf(buf, sizeof buf, "@import '%p'",
content);
memcpy(rewritten + *osize, buf, strlen(buf));
*osize += strlen(buf);
} else {
/* copy import */
memcpy(rewritten + *osize,
source + offset + match[0].rm_so,
match[0].rm_eo - match[0].rm_so);
*osize += match[0].rm_eo - match[0].rm_so;
}
nsurl_unref(url);
} else {
/* copy import */
memcpy(rewritten + *osize,
source + offset + match[0].rm_so,
match[0].rm_eo - match[0].rm_so);
*osize += match[0].rm_eo - match[0].rm_so;
}
 
assert(0 < match[0].rm_eo);
offset += match[0].rm_eo;
}
 
/* copy rest of source */
if (offset < size) {
memcpy(rewritten + *osize, source + offset, size - offset);
*osize += size - offset;
}
 
return rewritten;
}
 
static bool save_complete_save_stylesheet(save_complete_ctx *ctx,
hlcache_handle *css)
{
const char *css_data;
unsigned long css_size;
char *source;
unsigned long source_len;
struct nscss_import *imports;
uint32_t import_count;
lwc_string *type;
char filename[32];
bool result;
 
if (save_complete_ctx_has_content(ctx, css))
return true;
 
if (save_complete_ctx_add_content(ctx, css) == false) {
warn_user("NoMemory", 0);
return false;
}
 
imports = nscss_get_imports(css, &import_count);
if (save_complete_save_imported_sheets(ctx,
imports, import_count) == false)
return false;
 
css_data = content_get_source_data(css, &css_size);
source = save_complete_rewrite_stylesheet_urls(ctx, css_data, css_size,
hlcache_handle_get_url(css), &source_len);
if (source == NULL) {
warn_user("NoMemory", 0);
return false;
}
 
type = content_get_mime_type(css);
if (type == NULL) {
free(source);
return false;
}
 
snprintf(filename, sizeof filename, "%p", css);
 
result = save_complete_save_buffer(ctx, filename,
source, source_len, type);
 
lwc_string_unref(type);
free(source);
 
return result;
}
 
static bool save_complete_save_imported_sheets(save_complete_ctx *ctx,
struct nscss_import *imports, uint32_t import_count)
{
uint32_t i;
 
for (i = 0; i < import_count; i++) {
if (save_complete_save_stylesheet(ctx, imports[i].c) == false)
return false;
}
 
return true;
}
 
static bool save_complete_save_html_stylesheet(save_complete_ctx *ctx,
struct html_stylesheet *sheet)
{
if (sheet->type == HTML_STYLESHEET_INTERNAL) {
if (save_complete_save_imported_sheets(ctx,
sheet->data.internal->imports,
sheet->data.internal->import_count) == false)
return false;
 
return true;
}
 
if (sheet->data.external == NULL)
return true;
 
return save_complete_save_stylesheet(ctx, sheet->data.external);
}
 
static bool save_complete_save_html_stylesheets(save_complete_ctx *ctx,
hlcache_handle *c)
{
struct html_stylesheet *sheets;
unsigned int i, count;
 
sheets = html_get_stylesheets(c, &count);
 
for (i = STYLESHEET_START; i != count; i++) {
if (save_complete_save_html_stylesheet(ctx,
&sheets[i]) == false)
return false;
}
 
return true;
}
 
static bool save_complete_save_html_object(save_complete_ctx *ctx,
hlcache_handle *obj)
{
const char *obj_data;
unsigned long obj_size;
lwc_string *type;
bool result;
char filename[32];
 
if (content_get_type(obj) == CONTENT_NONE)
return true;
 
obj_data = content_get_source_data(obj, &obj_size);
if (obj_data == NULL)
return true;
 
if (save_complete_ctx_has_content(ctx, obj))
return true;
 
if (save_complete_ctx_add_content(ctx, obj) == false) {
warn_user("NoMemory", 0);
return false;
}
 
if (content_get_type(obj) == CONTENT_HTML) {
return save_complete_save_html(ctx, obj, false);
}
 
snprintf(filename, sizeof filename, "%p", obj);
 
type = content_get_mime_type(obj);
if (type == NULL)
return false;
 
result = save_complete_save_buffer(ctx, filename,
obj_data, obj_size, type);
 
lwc_string_unref(type);
 
return result;
}
 
static bool save_complete_save_html_objects(save_complete_ctx *ctx,
hlcache_handle *c)
{
struct content_html_object *object;
unsigned int count;
 
object = html_get_objects(c, &count);
 
for (; object != NULL; object = object->next) {
if (object->content != NULL) {
if (save_complete_save_html_object(ctx,
object->content) == false)
return false;
}
}
 
return true;
}
 
static bool save_complete_libdom_treewalk(dom_node *root,
bool (*callback)(dom_node *node,
save_complete_event_type event_type, void *ctx),
void *ctx)
{
dom_node *node;
 
node = dom_node_ref(root); /* tree root */
 
while (node != NULL) {
dom_node *next = NULL;
dom_exception exc;
 
exc = dom_node_get_first_child(node, &next);
if (exc != DOM_NO_ERR) {
dom_node_unref(node);
break;
}
 
if (next != NULL) { /* 1. children */
dom_node_unref(node);
node = next;
} else {
exc = dom_node_get_next_sibling(node, &next);
if (exc != DOM_NO_ERR) {
dom_node_unref(node);
break;
}
 
if (next != NULL) { /* 2. siblings */
if (callback(node, EVENT_LEAVE, ctx) == false) {
return false;
}
dom_node_unref(node);
node = next;
} else { /* 3. ancestor siblings */
while (node != NULL) {
exc = dom_node_get_next_sibling(node,
&next);
if (exc != DOM_NO_ERR) {
dom_node_unref(node);
node = NULL;
break;
}
 
if (next != NULL) {
dom_node_unref(next);
break;
}
 
exc = dom_node_get_parent_node(node,
&next);
if (exc != DOM_NO_ERR) {
dom_node_unref(node);
node = NULL;
break;
}
 
if (callback(node, EVENT_LEAVE,
ctx) == false) {
return false;
}
dom_node_unref(node);
node = next;
}
 
if (node == NULL)
break;
 
exc = dom_node_get_next_sibling(node, &next);
if (exc != DOM_NO_ERR) {
dom_node_unref(node);
break;
}
 
if (callback(node, EVENT_LEAVE, ctx) == false) {
return false;
}
dom_node_unref(node);
node = next;
}
}
 
assert(node != NULL);
 
if (callback(node, EVENT_ENTER, ctx) == false) {
return false; /* callback caused early termination */
}
 
}
 
return true;
}
 
static bool save_complete_rewrite_url_value(save_complete_ctx *ctx,
const char *value, size_t value_len)
{
nsurl *url;
hlcache_handle *content;
char *escaped;
nserror error;
utf8_convert_ret ret;
 
error = nsurl_join(ctx->base, value, &url);
if (error == NSERROR_NOMEM)
return false;
 
if (url != NULL) {
content = save_complete_ctx_find_content(ctx, url);
if (content != NULL) {
/* found a match */
nsurl_unref(url);
 
fprintf(ctx->fp, "\"%p\"", content);
} else {
/* no match found */
ret = utf8_to_html(nsurl_access(url), "UTF-8",
nsurl_length(url), &escaped);
nsurl_unref(url);
 
if (ret != UTF8_CONVERT_OK)
return false;
 
fprintf(ctx->fp, "\"%s\"", escaped);
 
free(escaped);
}
} else {
ret = utf8_to_html(value, "UTF-8", value_len, &escaped);
if (ret != UTF8_CONVERT_OK)
return false;
 
fprintf(ctx->fp, "\"%s\"", escaped);
 
free(escaped);
}
 
return true;
}
 
static bool save_complete_write_value(save_complete_ctx *ctx,
const char *value, size_t value_len)
{
char *escaped;
utf8_convert_ret ret;
 
ret = utf8_to_html(value, "UTF-8", value_len, &escaped);
if (ret != UTF8_CONVERT_OK)
return false;
 
fprintf(ctx->fp, "\"%s\"", escaped);
 
free(escaped);
 
return true;
}
 
static bool save_complete_handle_attr_value(save_complete_ctx *ctx,
dom_string *node_name, dom_string *attr_name,
dom_string *attr_value)
{
const char *node_data = dom_string_data(node_name);
size_t node_len = dom_string_byte_length(node_name);
const char *name_data = dom_string_data(attr_name);
size_t name_len = dom_string_byte_length(attr_name);
const char *value_data = dom_string_data(attr_value);
size_t value_len = dom_string_byte_length(attr_value);
 
/**
* We only need to consider the following cases:
*
* Attribute: Elements:
*
* 1) data <object>
* 2) href <a> <area> <link>
* 3) src <script> <input> <frame> <iframe> <img>
* 4) background any (except those above)
*/
/* 1 */
if (name_len == SLEN("data") &&
strncasecmp(name_data, "data", name_len) == 0) {
if (node_len == SLEN("object") &&
strncasecmp(node_data,
"object", node_len) == 0) {
return save_complete_rewrite_url_value(ctx,
value_data, value_len);
} else {
return save_complete_write_value(ctx,
value_data, value_len);
}
}
/* 2 */
else if (name_len == SLEN("href") &&
strncasecmp(name_data, "href", name_len) == 0) {
if ((node_len == SLEN("a") &&
strncasecmp(node_data, "a", node_len) == 0) ||
(node_len == SLEN("area") &&
strncasecmp(node_data, "area",
node_len) == 0) ||
(node_len == SLEN("link") &&
strncasecmp(node_data, "link",
node_len) == 0)) {
return save_complete_rewrite_url_value(ctx,
value_data, value_len);
} else {
return save_complete_write_value(ctx,
value_data, value_len);
}
}
/* 3 */
else if (name_len == SLEN("src") &&
strncasecmp(name_data, "src", name_len) == 0) {
if ((node_len == SLEN("frame") &&
strncasecmp(node_data, "frame",
node_len) == 0) ||
(node_len == SLEN("iframe") &&
strncasecmp(node_data, "iframe",
node_len) == 0) ||
(node_len == SLEN("input") &&
strncasecmp(node_data, "input",
node_len) == 0) ||
(node_len == SLEN("img") &&
strncasecmp(node_data, "img",
node_len) == 0) ||
(node_len == SLEN("script") &&
strncasecmp(node_data, "script",
node_len) == 0)) {
return save_complete_rewrite_url_value(ctx,
value_data, value_len);
} else {
return save_complete_write_value(ctx,
value_data, value_len);
}
}
/* 4 */
else if (name_len == SLEN("background") &&
strncasecmp(name_data, "background", name_len) == 0) {
return save_complete_rewrite_url_value(ctx,
value_data, value_len);
} else {
return save_complete_write_value(ctx,
value_data, value_len);
}
}
 
static bool save_complete_handle_attr(save_complete_ctx *ctx,
dom_string *node_name, dom_attr *attr)
{
dom_string *name;
const char *name_data;
size_t name_len;
dom_string *value;
dom_exception error;
 
error = dom_attr_get_name(attr, &name);
if (error != DOM_NO_ERR)
return false;
 
if (name == NULL)
return true;
 
error = dom_attr_get_value(attr, &value);
if (error != DOM_NO_ERR) {
dom_string_unref(name);
return false;
}
 
name_data = dom_string_data(name);
name_len = dom_string_byte_length(name);
 
fputc(' ', ctx->fp);
fwrite(name_data, sizeof(*name_data), name_len, ctx->fp);
 
if (value != NULL) {
fputc('=', ctx->fp);
if (save_complete_handle_attr_value(ctx, node_name,
name, value) == false) {
dom_string_unref(value);
dom_string_unref(name);
return false;
}
}
 
dom_string_unref(name);
 
return true;
}
 
static bool save_complete_handle_attrs(save_complete_ctx *ctx,
dom_string *node_name, dom_namednodemap *attrs)
{
uint32_t length, i;
dom_exception error;
 
error = dom_namednodemap_get_length(attrs, &length);
if (error != DOM_NO_ERR)
return false;
 
for (i = 0; i < length; i++) {
dom_attr *attr;
 
error = dom_namednodemap_item(attrs, i, (void *) &attr);
if (error != DOM_NO_ERR)
return false;
 
if (attr == NULL)
continue;
 
if (save_complete_handle_attr(ctx, node_name, attr) == false) {
dom_node_unref(attr);
return false;
}
 
dom_node_unref(attr);
}
 
return true;
}
 
static bool save_complete_handle_element(save_complete_ctx *ctx,
dom_node *node, save_complete_event_type event_type)
{
dom_string *name;
dom_namednodemap *attrs;
const char *name_data;
size_t name_len;
bool process = true;
dom_exception error;
 
ctx->iter_state = STATE_NORMAL;
 
error = dom_node_get_node_name(node, &name);
if (error != DOM_NO_ERR)
return false;
 
if (name == NULL)
return true;
 
name_data = dom_string_data(name);
name_len = dom_string_byte_length(name);
 
if (name_len == SLEN("base") &&
strncasecmp(name_data, "base", name_len) == 0) {
/* Elide BASE elements from the output */
process = false;
} else if (name_len == SLEN("meta") &&
strncasecmp(name_data, "meta", name_len) == 0) {
/* Don't emit close tags for META elements */
if (event_type == EVENT_LEAVE) {
process = false;
} else {
/* Elide meta charsets */
dom_string *value;
error = dom_element_get_attribute(node,
corestring_dom_http_equiv, &value);
if (error != DOM_NO_ERR) {
dom_string_unref(name);
return false;
}
 
if (value != NULL) {
if (dom_string_length(value) ==
SLEN("Content-Type") &&
strncasecmp(dom_string_data(value),
"Content-Type",
SLEN("Content-Type")) == 0)
process = false;
 
dom_string_unref(value);
} else {
bool yes;
 
error = dom_element_has_attribute(node,
corestring_dom_charset, &yes);
if (error != DOM_NO_ERR) {
dom_string_unref(name);
return false;
}
 
if (yes)
process = false;
}
}
} else if (event_type == EVENT_LEAVE &&
((name_len == SLEN("link") &&
strncasecmp(name_data, "link", name_len) == 0))) {
/* Don't emit close tags for void elements */
process = false;
}
 
if (process == false) {
dom_string_unref(name);
return true;
}
 
fputc('<', ctx->fp);
if (event_type == EVENT_LEAVE)
fputc('/', ctx->fp);
fwrite(name_data, sizeof(*name_data), name_len, ctx->fp);
 
if (event_type == EVENT_ENTER) {
error = dom_node_get_attributes(node, &attrs);
if (error != DOM_NO_ERR) {
dom_string_unref(name);
return false;
}
 
if (save_complete_handle_attrs(ctx, name, attrs) == false) {
dom_namednodemap_unref(attrs);
dom_string_unref(name);
return false;
}
 
dom_namednodemap_unref(attrs);
}
 
fputc('>', ctx->fp);
 
/* Rewrite contents of style elements */
if (event_type == EVENT_ENTER && name_len == SLEN("style") &&
strncasecmp(name_data, "style", name_len) == 0) {
dom_string *content;
 
error = dom_node_get_text_content(node, &content);
if (error != DOM_NO_ERR) {
dom_string_unref(name);
return false;
}
 
if (content != NULL) {
char *rewritten;
unsigned long len;
 
/* Rewrite @import rules */
rewritten = save_complete_rewrite_stylesheet_urls(
ctx,
dom_string_data(content),
dom_string_byte_length(content),
ctx->base,
&len);
if (rewritten == NULL) {
dom_string_unref(content);
dom_string_unref(name);
return false;
}
 
dom_string_unref(content);
 
fwrite(rewritten, sizeof(*rewritten), len, ctx->fp);
 
free(rewritten);
}
 
ctx->iter_state = STATE_IN_STYLE;
} else if (event_type == EVENT_ENTER && name_len == SLEN("head") &&
strncasecmp(name_data, "head", name_len) == 0) {
/* If this is a HEAD element, insert a meta charset */
fputs("<META http-equiv=\"Content-Type\" "
"content=\"text/html; charset=utf-8\">",
ctx->fp);
}
 
dom_string_unref(name);
 
return true;
}
 
static bool save_complete_node_handler(dom_node *node,
save_complete_event_type event_type, void *ctxin)
{
save_complete_ctx *ctx = ctxin;
dom_node_type type;
dom_exception error;
utf8_convert_ret ret;
 
error = dom_node_get_node_type(node, &type);
if (error != DOM_NO_ERR)
return false;
 
if (type == DOM_ELEMENT_NODE) {
return save_complete_handle_element(ctx, node, event_type);
} else if (type == DOM_TEXT_NODE || type == DOM_COMMENT_NODE) {
if (event_type != EVENT_ENTER)
return true;
 
if (ctx->iter_state != STATE_IN_STYLE) {
/* Emit text content */
dom_string *text;
const char *text_data;
size_t text_len;
 
error = dom_characterdata_get_data(node, &text);
if (error != DOM_NO_ERR) {
return false;
}
 
if (type == DOM_COMMENT_NODE)
fwrite("<!--", 1, sizeof("<!--") - 1, ctx->fp);
 
if (text != NULL) {
char *escaped;
 
text_data = dom_string_data(text);
text_len = dom_string_byte_length(text);
 
ret = utf8_to_html(text_data, "UTF-8",
text_len, &escaped);
if (ret != UTF8_CONVERT_OK)
return false;
 
fwrite(escaped, sizeof(*escaped),
strlen(escaped), ctx->fp);
 
free(escaped);
 
dom_string_unref(text);
}
 
if (type == DOM_COMMENT_NODE) {
fwrite("-->", 1, sizeof("-->") - 1, ctx->fp);
}
}
 
} else if (type == DOM_DOCUMENT_TYPE_NODE) {
dom_string *name;
const char *name_data;
size_t name_len;
 
if (event_type != EVENT_ENTER)
return true;
 
error = dom_document_type_get_name(node, &name);
if (error != DOM_NO_ERR)
return false;
 
if (name == NULL)
return true;
 
name_data = dom_string_data(name);
name_len = dom_string_byte_length(name);
 
fputs("<!DOCTYPE ", ctx->fp);
fwrite(name_data, sizeof(*name_data), name_len, ctx->fp);
 
dom_string_unref(name);
 
error = dom_document_type_get_public_id(node, &name);
if (error != DOM_NO_ERR)
return false;
 
if (name != NULL) {
name_data = dom_string_data(name);
name_len = dom_string_byte_length(name);
 
if (name_len > 0)
fprintf(ctx->fp, " PUBLIC \"%.*s\"",
(int) name_len, name_data);
 
dom_string_unref(name);
}
 
error = dom_document_type_get_system_id(node, &name);
if (error != DOM_NO_ERR)
return false;
 
if (name != NULL) {
name_data = dom_string_data(name);
name_len = dom_string_byte_length(name);
 
if (name_len > 0)
fprintf(ctx->fp, " \"%.*s\"",
(int) name_len, name_data);
 
dom_string_unref(name);
}
 
fputc('>', ctx->fp);
} else if (type == DOM_DOCUMENT_NODE) {
/* Do nothing */
} else {
LOG(("Unhandled node type: %d", type));
}
 
return true;
}
 
static bool save_complete_save_html_document(save_complete_ctx *ctx,
hlcache_handle *c, bool index)
{
bool error;
FILE *fp;
dom_document *doc;
lwc_string *mime_type;
char filename[32];
char fullpath[PATH_MAX];
 
strncpy(fullpath, ctx->path, sizeof fullpath);
 
if (index)
snprintf(filename, sizeof filename, "index");
else
snprintf(filename, sizeof filename, "%p", c);
 
error = path_add_part(fullpath, sizeof fullpath, filename);
if (error == false) {
warn_user("NoMemory", NULL);
return false;
}
 
fp = fopen(fullpath, "wb");
if (fp == NULL) {
warn_user("NoMemory", NULL);
return false;
}
 
ctx->base = html_get_base_url(c);
ctx->fp = fp;
ctx->iter_state = STATE_NORMAL;
 
doc = html_get_document(c);
 
if (save_complete_libdom_treewalk((dom_node *) doc,
save_complete_node_handler, ctx) == false) {
warn_user("NoMemory", 0);
fclose(fp);
return false;
}
 
fclose(fp);
 
mime_type = content_get_mime_type(c);
if (mime_type != NULL) {
if (ctx->set_type != NULL)
ctx->set_type(fullpath, mime_type);
 
lwc_string_unref(mime_type);
}
 
return true;
}
 
/**
* Save an HTML page with all dependencies, recursing through imported pages.
*
* \param ctx Save complete context
* \param c Content to save
* \param index true to save as "index"
* \return true on success, false on error and error reported
*/
static bool save_complete_save_html(save_complete_ctx *ctx, hlcache_handle *c,
bool index)
{
if (content_get_type(c) != CONTENT_HTML)
return false;
 
if (save_complete_ctx_has_content(ctx, c))
return true;
 
if (save_complete_save_html_stylesheets(ctx, c) == false)
return false;
 
if (save_complete_save_html_objects(ctx, c) == false)
return false;
 
return save_complete_save_html_document(ctx, c, index);
}
 
 
/**
* Create the inventory file listing original URLs.
*/
 
static bool save_complete_inventory(save_complete_ctx *ctx)
{
FILE *fp;
bool error;
save_complete_entry *entry;
char fullpath[PATH_MAX];
 
strncpy(fullpath, ctx->path, sizeof fullpath);
error = path_add_part(fullpath, sizeof fullpath, "Inventory");
if (error == false) {
warn_user("NoMemory", NULL);
return false;
}
 
fp = fopen(fullpath, "w");
if (fp == NULL) {
LOG(("fopen(): errno = %i", errno));
warn_user("SaveError", strerror(errno));
return false;
}
 
for (entry = ctx->list; entry != NULL; entry = entry->next) {
fprintf(fp, "%p %s\n", entry->content,
nsurl_access(hlcache_handle_get_url(
entry->content)));
}
 
fclose(fp);
 
return true;
}
 
/* Documented in save_complete.h */
void save_complete_init(void)
{
/* Match an @import rule - see CSS 2.1 G.1. */
regcomp_wrapper(&save_complete_import_re,
"@import" /* IMPORT_SYM */
"[ \t\r\n\f]*" /* S* */
/* 1 */
"(" /* [ */
/* 2 3 */
"\"(([^\"]|[\\]\")*)\"" /* STRING (approximated) */
"|"
/* 4 5 */
"'(([^']|[\\]')*)'"
"|" /* | */
"url\\([ \t\r\n\f]*" /* URI (approximated) */
/* 6 7 */
"\"(([^\"]|[\\]\")*)\""
"[ \t\r\n\f]*\\)"
"|"
"url\\([ \t\r\n\f]*"
/* 8 9 */
"'(([^']|[\\]')*)'"
"[ \t\r\n\f]*\\)"
"|"
"url\\([ \t\r\n\f]*"
/* 10 */
"([^) \t\r\n\f]*)"
"[ \t\r\n\f]*\\)"
")", /* ] */
REG_EXTENDED | REG_ICASE);
}
 
/* Documented in save_complete.h */
bool save_complete(hlcache_handle *c, const char *path,
save_complete_set_type_cb set_type)
{
bool result;
save_complete_ctx ctx;
 
save_complete_ctx_initialise(&ctx, path, set_type);
result = save_complete_save_html(&ctx, c, true);
 
if (result)
result = save_complete_inventory(&ctx);
 
save_complete_ctx_finalise(&ctx);
 
return result;
}
 
/programs/network/netsurf/netsurf/desktop/save_complete.h
0,0 → 1,58
/*
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Save HTML document with dependencies (interface).
*/
 
#ifndef _NETSURF_DESKTOP_SAVE_COMPLETE_H_
#define _NETSURF_DESKTOP_SAVE_COMPLETE_H_
 
#include <stdbool.h>
 
#include <libwapcaplet/libwapcaplet.h>
 
struct hlcache_handle;
 
/**
* Callback to set type of a file
*
* \param path Native path of file
* \param mime_type MIME type of file content
*/
typedef void (*save_complete_set_type_cb)(const char *path,
lwc_string *mime_type);
 
/**
* Initialise save complete module.
*/
void save_complete_init(void);
 
/**
* Save an HTML page with all dependencies.
*
* \param c CONTENT_HTML to save
* \param path Native path to directory to save in to (must exist)
* \param set_type Callback to set type of a file, or NULL
* \return true on success, false on error and error reported
*/
bool save_complete(struct hlcache_handle *c, const char *path,
save_complete_set_type_cb set_type);
 
#endif
/programs/network/netsurf/netsurf/desktop/save_pdf/TODO
0,0 → 1,19
- finish all graphic primitives
- allow adding raw bitmaps
- make image-aware (embed the image in its native/original type if possible)
 
- adjust content width to page width
- divide output into multiple pages (not just the first one)
- rearrange file structure
 
- separate print-plotting as much as possible from window redrawing
- add text-scaling (if not yet using the original font - make the default one
have the same width)
- add a save file.. dialogue
- add utf support to Haru ( doable? )
- wait for browser to end fetching?
- analyze and deal with performance issues(huge file hangs some pdf viewers,
for example kpdf when viewing plotted http://www.onet.pl)
- deal with to wide pages - when window layouting adds a horizontal scrollbar,
we should treat it otherwise - either print horizontal or scale or,
better, find a new layout.
/programs/network/netsurf/netsurf/desktop/save_pdf/font_haru.c
0,0 → 1,376
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
* Copyright 2009 John Tytgat <joty@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Font handling in Haru pdf documents (implementation).
*
* The functions were written to implement the same interface as the Pango ones
* so that the usage of the latter wouldn't have to be modified.
*/
 
#include "utils/config.h"
#ifdef WITH_PDF_EXPORT
 
/*#define FONT_HARU_DEBUG */
#include <assert.h>
#include <float.h>
#include <math.h>
#include <string.h>
 
#include <hpdf.h>
 
#include "css/css.h"
#include "css/utils.h"
 
#include "desktop/options.h"
#include "desktop/save_pdf/font_haru.h"
#include "render/font.h"
#include "utils/log.h"
 
 
static bool haru_nsfont_init(HPDF_Doc *pdf, HPDF_Page *page,
const char *string, char **string_nt, int length);
 
static bool haru_nsfont_width(const plot_font_style_t *fstyle,
const char *string, size_t length,
int *width);
 
static bool haru_nsfont_position_in_string(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x);
 
static bool haru_nsfont_split(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x);
static float pdf_text_scale = DEFAULT_EXPORT_SCALE;
 
const struct font_functions haru_nsfont = {
haru_nsfont_width,
haru_nsfont_position_in_string,
haru_nsfont_split
};
 
/**
* Haru error handler
* for debugging purposes - it immediately exits the program on the first error,
* as it would otherwise flood the user with all resulting complications,
* covering the most important error source.
*/
static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no,
void *user_data)
{
LOG(("ERROR: in font_haru \n\terror_no=%x\n\tdetail_no=%d\n",
(HPDF_UINT)error_no, (HPDF_UINT)detail_no));
#ifdef FONT_HARU_DEBUG
exit(1);
#endif
}
 
static bool haru_nsfont_init(HPDF_Doc *pdf, HPDF_Page *page,
const char *string, char **string_nt, int length)
{
*pdf = HPDF_New(error_handler, NULL);
if (*pdf == NULL)
return false;
 
*page = HPDF_AddPage(*pdf);
if (*page == NULL) {
HPDF_Free(*pdf);
return false;
}
*string_nt = malloc((length + 1) * sizeof(char));
if (*string_nt == NULL) {
HPDF_Free(*pdf);
return false;
}
memcpy(*string_nt, string, length);
(*string_nt)[length] = '\0';
return true;
}
 
/**
* Measure the width of a string.
*
* \param fstyle style for this text
* \param string string to measure (no UTF-8 currently)
* \param length length of string
* \param width updated to width of string[0..length]
* \return true on success, false on error and error reported
*/
bool haru_nsfont_width(const plot_font_style_t *fstyle,
const char *string, size_t length,
int *width)
{
HPDF_Doc pdf;
HPDF_Page page;
char *string_nt;
HPDF_REAL width_real;
 
*width = 0;
 
if (length == 0)
return true;
 
if (!haru_nsfont_init(&pdf, &page, string, &string_nt, length))
return false;
 
if (!haru_nsfont_apply_style(fstyle, pdf, page, NULL, NULL)) {
free(string_nt);
HPDF_Free(pdf);
return false;
}
 
width_real = HPDF_Page_TextWidth(page, string_nt);
*width = width_real;
 
#ifdef FONT_HARU_DEBUG
LOG(("Measuring string: %s ; Calculated width: %f %i",string_nt, width_real, *width));
#endif
free(string_nt);
HPDF_Free(pdf);
 
return true;
}
 
 
/**
* Find the position in a string where an x coordinate falls.
*
* \param fstyle style for this text
* \param string string to measure (no UTF-8 currently)
* \param length length of string
* \param x x coordinate to search for
* \param char_offset updated to offset in string of actual_x, [0..length]
* \param actual_x updated to x coordinate of character closest to x
* \return true on success, false on error and error reported
*/
 
bool haru_nsfont_position_in_string(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
HPDF_Doc pdf;
HPDF_Page page;
char *string_nt;
HPDF_UINT offset;
HPDF_REAL real_width;
if (!haru_nsfont_init(&pdf, &page, string, &string_nt, length))
return false;
if (HPDF_Page_SetWidth(page, x) != HPDF_OK
|| !haru_nsfont_apply_style(fstyle, pdf, page, NULL, NULL)) {
free(string_nt);
HPDF_Free(pdf);
return false;
}
 
offset = HPDF_Page_MeasureText(page, string_nt, x,
HPDF_FALSE, &real_width);
 
if (real_width < x)
*char_offset = offset;
else {
assert(fabs(real_width - x) < FLT_EPSILON);
assert(offset > 0);
*char_offset = offset - 1;
}
/*TODO: this is only the right edge of the character*/
*actual_x = real_width;
#ifdef FONT_HARU_DEBUG
LOG(("Position in string: %s at x: %i; Calculated position: %i",
string_nt, x, *char_offset));
#endif
free(string_nt);
HPDF_Free(pdf);
return true;
}
 
/**
* Find where to split a string to make it fit a width.
*
* \param fstyle style for this text
* \param string string to measure (no UTF-8 currently)
* \param length length of string
* \param x width available
* \param char_offset updated to offset in string of actual_x, [0..length]
* \param actual_x updated to x coordinate of character closest to x
* \return true on success, false on error and error reported
*/
 
bool haru_nsfont_split(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
HPDF_Doc pdf;
HPDF_Page page;
char *string_nt;
HPDF_REAL real_width;
HPDF_UINT offset;
if (!haru_nsfont_init(&pdf, &page, string, &string_nt, length))
return false;
if (HPDF_Page_SetWidth(page, x) != HPDF_OK
|| !haru_nsfont_apply_style(fstyle, pdf, page, NULL, NULL)) {
free(string_nt);
HPDF_Free(pdf);
return false;
}
offset = HPDF_Page_MeasureText(page, string_nt, x,
HPDF_TRUE, &real_width);
#ifdef FONT_HARU_DEBUG
LOG(("Splitting string: %s for width: %i ; Calculated position: %i Calculated real_width: %f",
string_nt, x, *char_offset, real_width));
#endif
*char_offset = offset - 1;
/*TODO: this is only the right edge of the character*/
*actual_x = real_width;
free(string_nt);
HPDF_Free(pdf);
return true;
}
 
/**
* Apply font style to a Haru HPDF_Page
*
* \param fstyle plot style for this page
* \param doc document owning the page
* \param page the page to apply the style to
* \param font if this is non NULL it is updated to the font based
* on given style
* \param font_size if this is non NULL it is updated to the font size
* based on given style
* \return true on success, false on error and error reported
*
* When both font and font_size are NULL, the HPDF_Page is updated for given
* style, otherwise it is left to the called to do this.
*/
bool haru_nsfont_apply_style(const plot_font_style_t *fstyle,
HPDF_Doc doc, HPDF_Page page,
HPDF_Font *font, HPDF_REAL *font_size)
{
HPDF_Font pdf_font;
HPDF_REAL size;
char font_name[50];
bool roman = false;
bool bold = false;
bool styled = false;
 
/*TODO: style handling, we are mapping the
styles on the basic 14 fonts only
*/
switch (fstyle->family) {
case PLOT_FONT_FAMILY_SERIF:
strcpy(font_name, "Times");
roman = true;
break;
case PLOT_FONT_FAMILY_MONOSPACE:
strcpy(font_name, "Courier");
break;
case PLOT_FONT_FAMILY_SANS_SERIF:
strcpy(font_name, "Helvetica");
break;
case PLOT_FONT_FAMILY_CURSIVE:
case PLOT_FONT_FAMILY_FANTASY:
default:
strcpy(font_name, "Times");
roman=true;
break;
}
if (fstyle->weight == 700) {
strcat(font_name, "-Bold");
bold = true;
}
 
if ((fstyle->flags & FONTF_ITALIC) || (fstyle->flags & FONTF_OBLIQUE)) {
if (!bold)
strcat(font_name,"-");
if (roman)
strcat(font_name,"Italic");
else
strcat(font_name,"Oblique");
styled = true;
}
if (roman && !styled && !bold)
strcat(font_name, "-Roman");
 
#ifdef FONT_HARU_DEBUG
LOG(("Setting font: %s", font_name));
#endif
 
size = fstyle->size;
 
if (font != NULL)
size *= pdf_text_scale;
 
if (size <= 0)
return true;
 
size /= FONT_SIZE_SCALE;
 
if (size > HPDF_MAX_FONTSIZE)
size = HPDF_MAX_FONTSIZE;
 
if (font_size)
*font_size = size;
 
pdf_font = HPDF_GetFont(doc, font_name, "StandardEncoding");
if (pdf_font == NULL)
return false;
if (font != NULL)
*font = pdf_font;
 
if (font == NULL || font_size == NULL)
HPDF_Page_SetFontAndSize(page, pdf_font, size);
return true;
}
 
/**
* Sync the text scale with the scale for the whole content
*/
void haru_nsfont_set_scale(float s)
{
pdf_text_scale = s;
}
 
#endif /* WITH_PDF_EXPORT */
 
/programs/network/netsurf/netsurf/desktop/save_pdf/font_haru.h
0,0 → 1,40
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
* Copyright 2009 John Tytgat <joty@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Font handling in Haru pdf documents (interface).
*/
#ifndef _NETSURF_RENDER_FONT_HARU_H_
#define _NETSURF_RENDER_FONT_HARU_H_
 
#include <hpdf.h>
 
#include "render/font.h"
#include "desktop/plot_style.h"
bool haru_nsfont_apply_style(const plot_font_style_t *fstyle,
HPDF_Doc doc, HPDF_Page page,
HPDF_Font *font, HPDF_REAL *font_size);
 
void haru_nsfont_set_scale(float s);
 
extern const struct font_functions haru_nsfont;
 
#endif
/programs/network/netsurf/netsurf/desktop/save_pdf/pdf_plotters.c
0,0 → 1,963
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
* Copyright 2009 John Tytgat <joty@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Target independent PDF plotting using Haru Free PDF Library.
*/
 
#include "utils/config.h"
#ifdef WITH_PDF_EXPORT
 
#include <assert.h>
#include <stdlib.h>
#include <string.h>
 
#include <hpdf.h>
 
#include "content/hlcache.h"
#include "desktop/options.h"
#include "desktop/plotters.h"
#include "desktop/print.h"
#include "desktop/printer.h"
#include "desktop/save_pdf/pdf_plotters.h"
#include "image/bitmap.h"
#include "utils/log.h"
#include "utils/utils.h"
#include "utils/useragent.h"
 
#include "font_haru.h"
 
/* #define PDF_DEBUG */
/* #define PDF_DEBUG_DUMPGRID */
 
static bool pdf_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style);
static bool pdf_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle);
static bool pdf_plot_polygon(const int *p, unsigned int n, const plot_style_t *style);
static bool pdf_plot_clip(const struct rect *clip);
static bool pdf_plot_text(int x, int y, const char *text, size_t length,
const plot_font_style_t *fstyle);
static bool pdf_plot_disc(int x, int y, int radius, const plot_style_t *style);
static bool pdf_plot_arc(int x, int y, int radius, int angle1, int angle2,
const plot_style_t *style);
static bool pdf_plot_bitmap_tile(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bitmap_flags_t flags);
static bool pdf_plot_path(const float *p, unsigned int n, colour fill, float width,
colour c, const float transform[6]);
 
static HPDF_Image pdf_extract_image(struct bitmap *bitmap);
 
static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no,
void *user_data);
 
#ifdef PDF_DEBUG_DUMPGRID
static void pdf_plot_grid(int x_dist,int y_dist,unsigned int colour);
#endif
 
typedef enum {
DashPattern_eNone,
DashPattern_eDash,
DashPattern_eDotted
} DashPattern_e;
 
/* Wrapper routines to minimize gstate updates in the produced PDF file. */
static void pdfw_gs_init(void);
static void pdfw_gs_save(HPDF_Page page);
static void pdfw_gs_restore(HPDF_Page page);
static void pdfw_gs_fillcolour(HPDF_Page page, colour col);
static void pdfw_gs_strokecolour(HPDF_Page page, colour col);
static void pdfw_gs_linewidth(HPDF_Page page, float lineWidth);
static void pdfw_gs_font(HPDF_Page page, HPDF_Font font, HPDF_REAL font_size);
static void pdfw_gs_dash(HPDF_Page page, DashPattern_e dash);
 
/**
* Our PDF gstate mirror which we use to minimize gstate updates
* in the PDF file.
*/
typedef struct {
colour fillColour; /**< Current fill colour. */
colour strokeColour; /**< Current stroke colour. */
float lineWidth; /**< Current line width. */
HPDF_Font font; /**< Current font. */
HPDF_REAL font_size; /**< Current font size. */
DashPattern_e dash; /**< Current dash state. */
} PDFW_GState;
 
static void apply_clip_and_mode(bool selectTextMode, colour fillCol,
colour strokeCol, float lineWidth, DashPattern_e dash);
 
#define PDFW_MAX_GSTATES 4
static PDFW_GState pdfw_gs[PDFW_MAX_GSTATES];
static unsigned int pdfw_gs_level;
 
static HPDF_Doc pdf_doc; /**< Current PDF document. */
static HPDF_Page pdf_page; /**< Current page. */
 
/*PDF Page size*/
static HPDF_REAL page_height, page_width;
 
static bool in_text_mode; /**< true if we're currently in text mode or not. */
static bool clip_update_needed; /**< true if pdf_plot_clip was invoked for
current page and not yet synced with PDF output. */
static int last_clip_x0, last_clip_y0, last_clip_x1, last_clip_y1;
 
static const struct print_settings *settings;
 
static const struct plotter_table pdf_plotters = {
.rectangle = pdf_plot_rectangle,
.line = pdf_plot_line,
.polygon = pdf_plot_polygon,
.clip = pdf_plot_clip,
.text = pdf_plot_text,
.disc = pdf_plot_disc,
.arc = pdf_plot_arc,
.bitmap = pdf_plot_bitmap_tile,
.path = pdf_plot_path,
.option_knockout = false,
};
 
const struct printer pdf_printer = {
&pdf_plotters,
pdf_begin,
pdf_next_page,
pdf_end
};
 
static char *owner_pass;
static char *user_pass;
 
bool pdf_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *pstyle)
{
DashPattern_e dash;
#ifdef PDF_DEBUG
LOG(("%d %d %d %d %f %X", x0, y0, x1, y1, page_height - y0, pstyle->fill_colour));
#endif
 
if (pstyle->fill_type != PLOT_OP_TYPE_NONE) {
 
apply_clip_and_mode(false, pstyle->fill_colour, NS_TRANSPARENT, 0., DashPattern_eNone);
 
/* Normalize boundaries of the area - to prevent
overflows. It is needed only in a few functions,
where integers are subtracted. When the whole
browser window is meant min and max int values are
used what must be handled in paged output.
*/
x0 = min(max(x0, 0), page_width);
y0 = min(max(y0, 0), page_height);
x1 = min(max(x1, 0), page_width);
y1 = min(max(y1, 0), page_height);
 
HPDF_Page_Rectangle(pdf_page, x0, page_height - y1, x1 - x0, y1 - y0);
HPDF_Page_Fill(pdf_page);
 
}
 
if (pstyle->stroke_type != PLOT_OP_TYPE_NONE) {
 
switch (pstyle->stroke_type) {
case PLOT_OP_TYPE_DOT:
dash = DashPattern_eDotted;
break;
 
case PLOT_OP_TYPE_DASH:
dash = DashPattern_eDash;
break;
 
default:
dash = DashPattern_eNone;
break;
 
}
 
apply_clip_and_mode(false,
NS_TRANSPARENT,
pstyle->stroke_colour,
pstyle->stroke_width,
dash);
 
HPDF_Page_Rectangle(pdf_page, x0, page_height - y0, x1 - x0, -(y1 - y0));
HPDF_Page_Stroke(pdf_page);
}
 
return true;
}
 
bool pdf_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle)
{
DashPattern_e dash;
 
switch (pstyle->stroke_type) {
case PLOT_OP_TYPE_DOT:
dash = DashPattern_eDotted;
break;
 
case PLOT_OP_TYPE_DASH:
dash = DashPattern_eDash;
break;
 
default:
dash = DashPattern_eNone;
break;
 
}
 
apply_clip_and_mode(false,
NS_TRANSPARENT,
pstyle->stroke_colour,
pstyle->stroke_width,
dash);
 
HPDF_Page_MoveTo(pdf_page, x0, page_height - y0);
HPDF_Page_LineTo(pdf_page, x1, page_height - y1);
HPDF_Page_Stroke(pdf_page);
 
return true;
}
 
bool pdf_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
{
unsigned int i;
#ifdef PDF_DEBUG
int pmaxx = p[0], pmaxy = p[1];
int pminx = p[0], pminy = p[1];
LOG(("."));
#endif
if (n == 0)
return true;
 
apply_clip_and_mode(false, style->fill_colour, NS_TRANSPARENT, 0., DashPattern_eNone);
 
HPDF_Page_MoveTo(pdf_page, p[0], page_height - p[1]);
for (i = 1 ; i<n ; i++) {
HPDF_Page_LineTo(pdf_page, p[i*2], page_height - p[i*2+1]);
#ifdef PDF_DEBUG
pmaxx = max(pmaxx, p[i*2]);
pmaxy = max(pmaxy, p[i*2+1]);
pminx = min(pminx, p[i*2]);
pminy = min(pminy, p[i*2+1]);
#endif
}
 
#ifdef PDF_DEBUG
LOG(("%d %d %d %d %f", pminx, pminy, pmaxx, pmaxy, page_height - pminy));
#endif
 
HPDF_Page_Fill(pdf_page);
 
return true;
}
 
 
/**here the clip is only queried */
bool pdf_plot_clip(const struct rect *clip)
{
#ifdef PDF_DEBUG
LOG(("%d %d %d %d", clip->x0, clip->y0, clip->x1, clip->y1));
#endif
 
/*Normalize cllipping area - to prevent overflows.
See comment in pdf_plot_fill.
*/
last_clip_x0 = min(max(clip->x0, 0), page_width);
last_clip_y0 = min(max(clip->y0, 0), page_height);
last_clip_x1 = min(max(clip->x1, 0), page_width);
last_clip_y1 = min(max(clip->y1, 0), page_height);
 
clip_update_needed = true;
 
return true;
}
 
bool pdf_plot_text(int x, int y, const char *text, size_t length,
const plot_font_style_t *fstyle)
{
#ifdef PDF_DEBUG
LOG((". %d %d %.*s", x, y, (int)length, text));
#endif
char *word;
HPDF_Font pdf_font;
HPDF_REAL size;
 
if (length == 0)
return true;
 
apply_clip_and_mode(true, fstyle->foreground, NS_TRANSPARENT, 0.,
DashPattern_eNone);
 
haru_nsfont_apply_style(fstyle, pdf_doc, pdf_page, &pdf_font, &size);
pdfw_gs_font(pdf_page, pdf_font, size);
 
/* FIXME: UTF-8 to current font encoding needs to done. Or the font
* encoding needs to be UTF-8 or other Unicode encoding. */
word = (char *)malloc( sizeof(char) * (length+1) );
if (word == NULL)
return false;
memcpy(word, text, length);
word[length] = '\0';
 
HPDF_Page_TextOut (pdf_page, x, page_height - y, word);
 
free(word);
 
return true;
}
 
bool pdf_plot_disc(int x, int y, int radius, const plot_style_t *style)
{
#ifdef PDF_DEBUG
LOG(("."));
#endif
if (style->fill_type != PLOT_OP_TYPE_NONE) {
apply_clip_and_mode(false,
style->fill_colour,
NS_TRANSPARENT,
1., DashPattern_eNone);
 
HPDF_Page_Circle(pdf_page, x, page_height - y, radius);
 
HPDF_Page_Fill(pdf_page);
}
 
if (style->stroke_type != PLOT_OP_TYPE_NONE) {
/* FIXME: line width 1 is ok ? */
apply_clip_and_mode(false,
NS_TRANSPARENT,
style->stroke_colour,
1., DashPattern_eNone);
 
HPDF_Page_Circle(pdf_page, x, page_height - y, radius);
 
HPDF_Page_Stroke(pdf_page);
}
 
return true;
}
 
bool pdf_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
{
#ifdef PDF_DEBUG
LOG(("%d %d %d %d %d %X", x, y, radius, angle1, angle2, style->stroke_colour));
#endif
 
/* FIXME: line width 1 is ok ? */
apply_clip_and_mode(false, NS_TRANSPARENT, style->fill_colour, 1., DashPattern_eNone);
 
/* Normalize angles */
angle1 %= 360;
angle2 %= 360;
if (angle1 > angle2)
angle1 -= 360;
 
HPDF_Page_Arc(pdf_page, x, page_height - y, radius, angle1, angle2);
 
HPDF_Page_Stroke(pdf_page);
return true;
}
 
 
bool pdf_plot_bitmap_tile(int x, int y, int width, int height,
struct bitmap *bitmap, colour bg,
bitmap_flags_t flags)
{
HPDF_Image image;
HPDF_REAL current_x, current_y ;
HPDF_REAL max_width, max_height;
 
#ifdef PDF_DEBUG
LOG(("%d %d %d %d %p 0x%x", x, y, width, height,
bitmap, bg));
#endif
if (width == 0 || height == 0)
return true;
 
apply_clip_and_mode(false, NS_TRANSPARENT, NS_TRANSPARENT, 0., DashPattern_eNone);
 
image = pdf_extract_image(bitmap);
if (!image)
return false;
 
/*The position of the next tile*/
max_width = (flags & BITMAPF_REPEAT_X) ? page_width : width;
max_height = (flags & BITMAPF_REPEAT_Y) ? page_height : height;
 
for (current_y = 0; current_y < max_height; current_y += height)
for (current_x = 0; current_x < max_width; current_x += width)
HPDF_Page_DrawImage(pdf_page, image,
current_x + x,
page_height - current_y - y - height,
width, height);
 
return true;
}
 
HPDF_Image pdf_extract_image(struct bitmap *bitmap)
{
HPDF_Image image = NULL;
hlcache_handle *content = NULL;
 
/* TODO - get content from bitmap pointer */
 
if (content) {
const char *source_data;
unsigned long source_size;
 
/*Not sure if I don't have to check if downloading has been
finished.
Other way - lock pdf plotting while fetching a website
*/
source_data = content_get_source_data(content, &source_size);
 
switch(content_get_type(content)){
/*Handle "embeddable" types of images*/
case CONTENT_JPEG:
image = HPDF_LoadJpegImageFromMem(pdf_doc,
(const HPDF_BYTE *) source_data,
source_size);
break;
 
/*Disabled until HARU PNG support will be more stable.
 
case CONTENT_PNG:
image = HPDF_LoadPngImageFromMem(pdf_doc,
(const HPDF_BYTE *)content->source_data,
content->total_size);
break;*/
default:
break;
}
}
 
if (!image) {
HPDF_Image smask;
unsigned char *img_buffer, *rgb_buffer, *alpha_buffer;
int img_width, img_height, img_rowstride;
int i, j;
 
/*Handle pixmaps*/
img_buffer = bitmap_get_buffer(bitmap);
img_width = bitmap_get_width(bitmap);
img_height = bitmap_get_height(bitmap);
img_rowstride = bitmap_get_rowstride(bitmap);
 
rgb_buffer = (unsigned char *)malloc(3 * img_width * img_height);
alpha_buffer = (unsigned char *)malloc(img_width * img_height);
if (rgb_buffer == NULL || alpha_buffer == NULL) {
LOG(("Not enough memory to create RGB buffer"));
free(rgb_buffer);
free(alpha_buffer);
return NULL;
}
 
for (i = 0; i < img_height; i++)
for (j = 0; j < img_width; j++) {
rgb_buffer[((i * img_width) + j) * 3] =
img_buffer[(i * img_rowstride) + (j * 4)];
 
rgb_buffer[(((i * img_width) + j) * 3) + 1] =
img_buffer[(i * img_rowstride) + (j * 4) + 1];
 
rgb_buffer[(((i * img_width) + j) * 3) + 2] =
img_buffer[(i * img_rowstride) + (j * 4) + 2];
 
alpha_buffer[(i * img_width)+j] =
img_buffer[(i * img_rowstride) + (j * 4) + 3];
}
 
smask = HPDF_LoadRawImageFromMem(pdf_doc, alpha_buffer,
img_width, img_height,
HPDF_CS_DEVICE_GRAY, 8);
 
image = HPDF_LoadRawImageFromMem(pdf_doc, rgb_buffer,
img_width, img_height,
HPDF_CS_DEVICE_RGB, 8);
 
if (HPDF_Image_AddSMask(image, smask) != HPDF_OK)
image = NULL;
 
free(rgb_buffer);
free(alpha_buffer);
}
 
return image;
}
 
/**
* Enter/leave text mode and update PDF gstate for its clip, fill & stroke
* colour, line width and dash pattern parameters.
* \param selectTextMode true if text mode needs to be entered if required;
* false otherwise.
* \param fillCol Desired fill colour, use NS_TRANSPARENT if no update is
* required.
* \param strokeCol Desired stroke colour, use NS_TRANSPARENT if no update is
* required.
* \param lineWidth Desired line width. Only taken into account when strokeCol
* is different from NS_TRANSPARENT.
* \param dash Desired dash pattern. Only taken into account when strokeCol
* is different from NS_TRANSPARENT.
*/
static void apply_clip_and_mode(bool selectTextMode, colour fillCol,
colour strokeCol, float lineWidth, DashPattern_e dash)
{
/* Leave text mode when
* 1) we're not setting text anymore
* 2) or we need to update the current clippath
* 3) or we need to update any fill/stroke colour, linewidth or dash.
* Note: the test on stroke parameters (stroke colour, line width and
* dash) is commented out as if these need updating we want to be
* outside the text mode anyway (i.e. selectTextMode is false).
*/
if (in_text_mode && (!selectTextMode || clip_update_needed
|| (fillCol != NS_TRANSPARENT
&& fillCol != pdfw_gs[pdfw_gs_level].fillColour)
/* || (strokeCol != NS_TRANSPARENT
&& (strokeCol != pdfw_gs[pdfw_gs_level].strokeColour
|| lineWidth != pdfw_gs[pdfw_gs_level].lineWidth
|| dash != pdfw_gs[pdfw_gs_level].dash)) */)) {
HPDF_Page_EndText(pdf_page);
in_text_mode = false;
}
 
if (clip_update_needed)
pdfw_gs_restore(pdf_page);
 
/* Update fill/stroke colour, linewidth and dash when needed. */
if (fillCol != NS_TRANSPARENT)
pdfw_gs_fillcolour(pdf_page, fillCol);
if (strokeCol != NS_TRANSPARENT) {
pdfw_gs_strokecolour(pdf_page, strokeCol);
pdfw_gs_linewidth(pdf_page, lineWidth);
pdfw_gs_dash(pdf_page, dash);
}
 
if (clip_update_needed) {
pdfw_gs_save(pdf_page);
 
HPDF_Page_Rectangle(pdf_page, last_clip_x0,
page_height - last_clip_y1,
last_clip_x1 - last_clip_x0,
last_clip_y1 - last_clip_y0);
HPDF_Page_Clip(pdf_page);
HPDF_Page_EndPath(pdf_page);
 
clip_update_needed = false;
}
 
if (selectTextMode && !in_text_mode) {
HPDF_Page_BeginText(pdf_page);
in_text_mode = true;
}
}
 
static inline float transform_x(const float transform[6], float x, float y)
{
return transform[0] * x + transform[2] * y + transform[4];
}
 
static inline float transform_y(const float transform[6], float x, float y)
{
return page_height
- (transform[1] * x + transform[3] * y + transform[5]);
}
 
bool pdf_plot_path(const float *p, unsigned int n, colour fill, float width,
colour c, const float transform[6])
{
unsigned int i;
bool empty_path;
 
#ifdef PDF_DEBUG
LOG(("."));
#endif
 
if (n == 0)
return true;
 
if (c == NS_TRANSPARENT && fill == NS_TRANSPARENT)
return true;
 
if (p[0] != PLOTTER_PATH_MOVE)
return false;
 
apply_clip_and_mode(false, fill, c, width, DashPattern_eNone);
 
empty_path = true;
for (i = 0 ; i < n ; ) {
if (p[i] == PLOTTER_PATH_MOVE) {
HPDF_Page_MoveTo(pdf_page,
transform_x(transform, p[i+1], p[i+2]),
transform_y(transform, p[i+1], p[i+2]));
i+= 3;
} else if (p[i] == PLOTTER_PATH_CLOSE) {
if (!empty_path)
HPDF_Page_ClosePath(pdf_page);
i++;
} else if (p[i] == PLOTTER_PATH_LINE) {
HPDF_Page_LineTo(pdf_page,
transform_x(transform, p[i+1], p[i+2]),
transform_y(transform, p[i+1], p[i+2]));
i+=3;
empty_path = false;
} else if (p[i] == PLOTTER_PATH_BEZIER) {
HPDF_Page_CurveTo(pdf_page,
transform_x(transform, p[i+1], p[i+2]),
transform_y(transform, p[i+1], p[i+2]),
transform_x(transform, p[i+3], p[i+4]),
transform_y(transform, p[i+3], p[i+4]),
transform_x(transform, p[i+5], p[i+6]),
transform_y(transform, p[i+5], p[i+6]));
i += 7;
empty_path = false;
} else {
LOG(("bad path command %f", p[i]));
return false;
}
}
 
if (empty_path) {
HPDF_Page_EndPath(pdf_page);
return true;
}
 
if (fill != NS_TRANSPARENT) {
if (c != NS_TRANSPARENT)
HPDF_Page_FillStroke(pdf_page);
else
HPDF_Page_Fill(pdf_page);
}
else
HPDF_Page_Stroke(pdf_page);
 
return true;
}
 
/**
* Begin pdf plotting - initialize a new document
* \param path Output file path
* \param pg_width page width
* \param pg_height page height
*/
bool pdf_begin(struct print_settings *print_settings)
{
pdfw_gs_init();
 
if (pdf_doc != NULL)
HPDF_Free(pdf_doc);
pdf_doc = HPDF_New(error_handler, NULL);
if (!pdf_doc) {
LOG(("Error creating pdf_doc"));
return false;
}
 
settings = print_settings;
 
page_width = settings->page_width -
FIXTOFLT(FSUB(settings->margins[MARGINLEFT],
settings->margins[MARGINRIGHT]));
 
page_height = settings->page_height -
FIXTOFLT(settings->margins[MARGINTOP]);
 
 
#ifndef PDF_DEBUG
if (option_enable_PDF_compression)
HPDF_SetCompressionMode(pdf_doc, HPDF_COMP_ALL); /*Compression on*/
#endif
HPDF_SetInfoAttr(pdf_doc, HPDF_INFO_CREATOR, user_agent_string());
 
pdf_page = NULL;
 
#ifdef PDF_DEBUG
LOG(("pdf_begin finishes"));
#endif
return true;
}
 
 
bool pdf_next_page(void)
{
#ifdef PDF_DEBUG
LOG(("pdf_next_page begins"));
#endif
clip_update_needed = false;
if (pdf_page != NULL) {
apply_clip_and_mode(false, NS_TRANSPARENT, NS_TRANSPARENT, 0.,
DashPattern_eNone);
pdfw_gs_restore(pdf_page);
}
 
#ifdef PDF_DEBUG_DUMPGRID
if (pdf_page != NULL) {
pdf_plot_grid(10, 10, 0xCCCCCC);
pdf_plot_grid(100, 100, 0xCCCCFF);
}
#endif
pdf_page = HPDF_AddPage(pdf_doc);
if (pdf_page == NULL)
return false;
 
HPDF_Page_SetWidth (pdf_page, settings->page_width);
HPDF_Page_SetHeight(pdf_page, settings->page_height);
 
HPDF_Page_Concat(pdf_page, 1, 0, 0, 1,
FIXTOFLT(settings->margins[MARGINLEFT]), 0);
 
pdfw_gs_save(pdf_page);
 
#ifdef PDF_DEBUG
LOG(("%f %f", page_width, page_height));
#endif
 
return true;
}
 
 
void pdf_end(void)
{
#ifdef PDF_DEBUG
LOG(("pdf_end begins"));
#endif
clip_update_needed = false;
if (pdf_page != NULL) {
apply_clip_and_mode(false, NS_TRANSPARENT, NS_TRANSPARENT, 0.,
DashPattern_eNone);
pdfw_gs_restore(pdf_page);
}
 
#ifdef PDF_DEBUG_DUMPGRID
if (pdf_page != NULL) {
pdf_plot_grid(10, 10, 0xCCCCCC);
pdf_plot_grid(100, 100, 0xCCCCFF);
}
#endif
 
assert(settings->output != NULL);
 
/*Encryption on*/
if (option_enable_PDF_password)
PDF_Password(&owner_pass, &user_pass,
(void *)settings->output);
else
save_pdf(settings->output);
#ifdef PDF_DEBUG
LOG(("pdf_end finishes"));
#endif
}
 
/** saves the pdf optionally encrypting it before*/
void save_pdf(const char *path)
{
bool success = false;
 
if (option_enable_PDF_password && owner_pass != NULL ) {
HPDF_SetPassword(pdf_doc, owner_pass, user_pass);
HPDF_SetEncryptionMode(pdf_doc, HPDF_ENCRYPT_R3, 16);
free(owner_pass);
free(user_pass);
}
 
if (path != NULL) {
if (HPDF_SaveToFile(pdf_doc, path) != HPDF_OK)
remove(path);
else
success = true;
}
 
if (!success)
warn_user("Unable to save PDF file.", 0);
 
HPDF_Free(pdf_doc);
pdf_doc = NULL;
}
 
 
/**
* Haru error handler
* for debugging purposes - it immediately exits the program on the first error,
* as it would otherwise flood the user with all resulting complications,
* covering the most important error source.
*/
static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no,
void *user_data)
{
LOG(("ERROR:\n\terror_no=%x\n\tdetail_no=%d\n", (HPDF_UINT)error_no,
(HPDF_UINT)detail_no));
#ifdef PDF_DEBUG
exit(1);
#endif
}
 
/**
* This function plots a grid - used for debug purposes to check if all
* elements' final coordinates are correct.
*/
#ifdef PDF_DEBUG_DUMPGRID
void pdf_plot_grid(int x_dist, int y_dist, unsigned int colour)
{
for (int i = x_dist ; i < page_width ; i += x_dist)
pdf_plot_line(i, 0, i, page_height, 1, colour, false, false);
 
for (int i = y_dist ; i < page_height ; i += x_dist)
pdf_plot_line(0, i, page_width, i, 1, colour, false, false);
}
#endif
 
/**
* Initialize the gstate wrapper code.
*/
void pdfw_gs_init()
{
pdfw_gs_level = 0;
pdfw_gs[0].fillColour = 0x00000000; /* Default PDF fill colour is black. */
pdfw_gs[0].strokeColour = 0x00000000; /* Default PDF stroke colour is black. */
pdfw_gs[0].lineWidth = 1.0; /* Default PDF line width is 1. */
pdfw_gs[0].font = NULL;
pdfw_gs[0].font_size = 0.;
pdfw_gs[0].dash = DashPattern_eNone; /* Default dash state is a solid line. */
}
 
/**
* Increase gstate level.
* \param page PDF page where the update needs to happen.
*/
void pdfw_gs_save(HPDF_Page page)
{
if (pdfw_gs_level == PDFW_MAX_GSTATES)
abort();
pdfw_gs[pdfw_gs_level + 1] = pdfw_gs[pdfw_gs_level];
++pdfw_gs_level;
HPDF_Page_GSave(page);
}
 
/**
* Decrease gstate level and restore the gstate to its value at last save
* operation.
* \param page PDF page where the update needs to happen.
*/
void pdfw_gs_restore(HPDF_Page page)
{
if (pdfw_gs_level == 0)
abort();
--pdfw_gs_level;
HPDF_Page_GRestore(page);
}
 
#define RBYTE(x) (((x) & 0x0000FF) >> 0)
#define GBYTE(x) (((x) & 0x00FF00) >> 8)
#define BBYTE(x) (((x) & 0xFF0000) >> 16)
#define R(x) (RBYTE(x) / 255.)
#define G(x) (GBYTE(x) / 255.)
#define B(x) (BBYTE(x) / 255.)
 
/**
* Checks if given fill colour is already set in PDF gstate and if not,
* update the gstate accordingly.
* \param page PDF page where the update needs to happen.
* \param col Wanted fill colour.
*/
void pdfw_gs_fillcolour(HPDF_Page page, colour col)
{
if (col == pdfw_gs[pdfw_gs_level].fillColour)
return;
pdfw_gs[pdfw_gs_level].fillColour = col;
if (RBYTE(col) == GBYTE(col) && GBYTE(col) == BBYTE(col))
HPDF_Page_SetGrayFill(pdf_page, R(col));
else
HPDF_Page_SetRGBFill(pdf_page, R(col), G(col), B(col));
}
 
/**
* Checks if given stroke colour is already set in PDF gstate and if not,
* update the gstate accordingly.
* \param page PDF page where the update needs to happen.
* \param col Wanted stroke colour.
*/
void pdfw_gs_strokecolour(HPDF_Page page, colour col)
{
if (col == pdfw_gs[pdfw_gs_level].strokeColour)
return;
pdfw_gs[pdfw_gs_level].strokeColour = col;
if (RBYTE(col) == GBYTE(col) && GBYTE(col) == BBYTE(col))
HPDF_Page_SetGrayStroke(pdf_page, R(col));
else
HPDF_Page_SetRGBStroke(pdf_page, R(col), G(col), B(col));
}
 
/**
* Checks if given line width is already set in PDF gstate and if not, update
* the gstate accordingly.
* \param page PDF page where the update needs to happen.
* \param lineWidth Wanted line width.
*/
void pdfw_gs_linewidth(HPDF_Page page, float lineWidth)
{
if (lineWidth == pdfw_gs[pdfw_gs_level].lineWidth)
return;
pdfw_gs[pdfw_gs_level].lineWidth = lineWidth;
HPDF_Page_SetLineWidth(page, lineWidth);
}
 
/**
* Checks if given font and font size is already set in PDF gstate and if not,
* update the gstate accordingly.
* \param page PDF page where the update needs to happen.
* \param font Wanted PDF font.
* \param font_size Wanted PDF font size.
*/
void pdfw_gs_font(HPDF_Page page, HPDF_Font font, HPDF_REAL font_size)
{
if (font == pdfw_gs[pdfw_gs_level].font
&& font_size == pdfw_gs[pdfw_gs_level].font_size)
return;
pdfw_gs[pdfw_gs_level].font = font;
pdfw_gs[pdfw_gs_level].font_size = font_size;
HPDF_Page_SetFontAndSize(page, font, font_size);
}
 
/**
* Checks if given dash pattern is already set in PDF gstate and if not,
* update the gstate accordingly.
* \param page PDF page where the update needs to happen.
* \param dash Wanted dash pattern.
*/
void pdfw_gs_dash(HPDF_Page page, DashPattern_e dash)
{
if (dash == pdfw_gs[pdfw_gs_level].dash)
return;
pdfw_gs[pdfw_gs_level].dash = dash;
switch (dash) {
case DashPattern_eNone: {
HPDF_Page_SetDash(page, NULL, 0, 0);
break;
}
case DashPattern_eDash: {
const HPDF_UINT16 dash_ptn[] = {3};
HPDF_Page_SetDash(page, dash_ptn, 1, 1);
break;
}
case DashPattern_eDotted: {
const HPDF_UINT16 dash_ptn[] = {1};
HPDF_Page_SetDash(page, dash_ptn, 1, 1);
break;
}
}
}
 
#endif /* WITH_PDF_EXPORT */
 
/programs/network/netsurf/netsurf/desktop/save_pdf/pdf_plotters.h
0,0 → 1,41
/*
* Copyright 2008 Adam Blokus <adamblokus@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
PDF Plotting
*/
 
#ifndef NETSURF_PDF_PLOTTERS_H
#define NETSURF_PDF_PLOTTERS_H
 
#include "desktop/print.h"
 
extern const struct printer pdf_printer;
 
/**Start plotting a pdf file*/
bool pdf_begin(struct print_settings *settings);
 
/**Finish the current page and start a new one*/
bool pdf_next_page(void);
 
/**Close pdf document and save changes to file*/
void pdf_end(void);
 
void save_pdf(const char *path);
 
#endif /*NETSURF_PDF_PLOTTERS_H*/
/programs/network/netsurf/netsurf/desktop/save_text.c
0,0 → 1,305
/*
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Text export of HTML (implementation).
*/
 
#include <assert.h>
#include <stdbool.h>
#include <string.h>
 
#include <dom/dom.h>
 
#include "utils/config.h"
#include "content/content.h"
#include "content/hlcache.h"
#include "desktop/save_text.h"
#include "render/box.h"
#include "render/html.h"
#include "utils/log.h"
#include "utils/utf8.h"
#include "utils/utils.h"
 
static void extract_text(struct box *box, bool *first,
save_text_whitespace *before, struct save_text_state *save);
static bool save_text_add_to_buffer(const char *text, size_t length,
struct box *box, const char *whitespace_text,
size_t whitespace_length, struct save_text_state *save);
 
 
/**
* Extract the text from an HTML content and save it as a text file. Text is
* converted to the local encoding.
*
* \param c An HTML content.
* \param path Path to save text file too.
*/
 
void save_as_text(hlcache_handle *c, char *path)
{
FILE *out;
struct save_text_state save = { NULL, 0, 0 };
save_text_whitespace before = WHITESPACE_NONE;
bool first = true;
utf8_convert_ret ret;
char *result;
 
if (!c || content_get_type(c) != CONTENT_HTML) {
return;
}
 
extract_text(html_get_box_tree(c), &first, &before, &save);
if (!save.block)
return;
 
ret = utf8_to_local_encoding(save.block, save.length, &result);
free(save.block);
 
if (ret != UTF8_CONVERT_OK) {
LOG(("failed to convert to local encoding, return %d", ret));
return;
}
 
out = fopen(path, "w");
if (out) {
int res = fputs(result, out);
 
if (res < 0) {
LOG(("Warning: write failed"));
}
 
res = fputs("\n", out);
if (res < 0) {
LOG(("Warning: failed writing trailing newline"));
}
 
fclose(out);
}
 
free(result);
}
 
 
/**
* Decide what whitespace to place before the next bit of content-related text
* that is saved. Any existing whitespace is overridden if the whitespace for
* this box is more "significant".
*
* \param box Pointer to box.
* \param first Whether this is before the first bit of content-related
* text to be saved.
* \param before Type of whitespace currently intended to be placed
* before the next bit of content-related text to be saved.
* Updated if this box is worthy of more significant
* whitespace.
* \param whitespace_text Whitespace to place before next bit of
* content-related text to be saved.
* Updated if this box is worthy of more significant
* whitespace.
* \param whitespace_length Length of whitespace_text.
* Updated if this box is worthy of more significant
* whitespace.
*/
 
void save_text_solve_whitespace(struct box *box, bool *first,
save_text_whitespace *before, const char **whitespace_text,
size_t *whitespace_length)
{
/* work out what whitespace should be placed before the next bit of
* text */
if (*before < WHITESPACE_TWO_NEW_LINES &&
/* significant box type */
(box->type == BOX_BLOCK ||
box->type == BOX_TABLE ||
box->type == BOX_FLOAT_LEFT ||
box->type == BOX_FLOAT_RIGHT) &&
/* and not a list element */
!box->list_marker &&
/* and not a marker... */
(!(box->parent && box->parent->list_marker == box) ||
/* ...unless marker follows WHITESPACE_TAB */
((box->parent && box->parent->list_marker == box) &&
*before == WHITESPACE_TAB))) {
*before = WHITESPACE_TWO_NEW_LINES;
} else if (*before <= WHITESPACE_ONE_NEW_LINE &&
(box->type == BOX_TABLE_ROW ||
box->type == BOX_BR ||
(box->type != BOX_INLINE &&
(box->parent && box->parent->list_marker == box)) ||
(box->parent && box->parent->style &&
(css_computed_white_space(box->parent->style) ==
CSS_WHITE_SPACE_PRE ||
css_computed_white_space(box->parent->style) ==
CSS_WHITE_SPACE_PRE_WRAP) &&
box->type == BOX_INLINE_CONTAINER))) {
if (*before == WHITESPACE_ONE_NEW_LINE)
*before = WHITESPACE_TWO_NEW_LINES;
else
*before = WHITESPACE_ONE_NEW_LINE;
}
else if (*before < WHITESPACE_TAB &&
(box->type == BOX_TABLE_CELL ||
box->list_marker)) {
*before = WHITESPACE_TAB;
}
 
if (*first) {
/* before the first bit of text to be saved; there is
* no preceding whitespace */
*whitespace_text = "";
*whitespace_length = 0;
} else {
/* set the whitespace that has been decided on */
switch (*before) {
case WHITESPACE_TWO_NEW_LINES:
*whitespace_text = "\n\n";
*whitespace_length = 2;
break;
case WHITESPACE_ONE_NEW_LINE:
*whitespace_text = "\n";
*whitespace_length = 1;
break;
case WHITESPACE_TAB:
*whitespace_text = "\t";
*whitespace_length = 1;
break;
case WHITESPACE_NONE:
*whitespace_text = "";
*whitespace_length = 0;
break;
default:
*whitespace_text = "";
*whitespace_length = 0;
break;
}
}
}
 
 
/**
* Traverse though the box tree and add all text to a save buffer.
*
* \param box Pointer to box.
* \param first Whether this is before the first bit of content-related
* text to be saved.
* \param before Type of whitespace currently intended to be placed
* before the next bit of content-related text to be saved.
* Updated if this box is worthy of more significant
* whitespace.
* \param save our save_text_state workspace pointer
* \return true iff the file writing succeeded and traversal should continue.
*/
 
void extract_text(struct box *box, bool *first, save_text_whitespace *before,
struct save_text_state *save)
{
struct box *child;
const char *whitespace_text = "";
size_t whitespace_length = 0;
 
assert(box);
 
/* If box has a list marker */
if (box->list_marker) {
/* do the marker box before continuing with the rest of the
* list element */
extract_text(box->list_marker, first, before, save);
}
 
/* read before calling the handler in case it modifies the tree */
child = box->children;
 
save_text_solve_whitespace(box, first, before, &whitespace_text,
&whitespace_length);
 
if (box->type != BOX_BR && !((box->type == BOX_FLOAT_LEFT ||
box->type == BOX_FLOAT_RIGHT) && !box->text) &&
box->length > 0 && box->text) {
/* Box meets criteria for export; add text to buffer */
save_text_add_to_buffer(box->text, box->length, box,
whitespace_text, whitespace_length, save);
*first = false;
*before = WHITESPACE_NONE;
}
 
/* Work though the children of this box, extracting any text */
while (child) {
extract_text(child, first, before, save);
child = child->next;
}
 
return;
}
 
 
/**
* Add text to save text buffer. Any preceding whitespace or following space is
* also added to the buffer.
*
* \param text Pointer to text being added.
* \param length Length of text to be appended (bytes).
* \param box Pointer to text box.
* \param whitespace_text Whitespace to place before text for formatting
* may be NULL.
* \param whitespace_length Length of whitespace_text.
* \param save Our save_text_state workspace pointer.
* \return true iff the file writing succeeded and traversal should continue.
*/
 
bool save_text_add_to_buffer(const char *text, size_t length, struct box *box,
const char *whitespace_text, size_t whitespace_length,
struct save_text_state *save)
{
size_t new_length;
int space = 0;
 
assert(save);
 
if (box->space > 0)
space = 1;
 
if (whitespace_text)
length += whitespace_length;
 
new_length = save->length + whitespace_length + length + space;
if (new_length >= save->alloc) {
size_t new_alloc = save->alloc + (save->alloc / 4);
char *new_block;
 
if (new_alloc < new_length) new_alloc = new_length;
 
new_block = realloc(save->block, new_alloc);
if (!new_block) return false;
 
save->block = new_block;
save->alloc = new_alloc;
}
if (whitespace_text) {
memcpy(save->block + save->length, whitespace_text,
whitespace_length);
}
memcpy(save->block + save->length + whitespace_length, text, length);
save->length += length;
 
if (space == 1)
save->block[save->length++] = ' ';
 
return true;
}
/programs/network/netsurf/netsurf/desktop/save_text.h
0,0 → 1,49
/*
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Text export of HTML (interface).
*/
 
#ifndef _NETSURF_DESKTOP_SAVE_TEXT_H_
#define _NETSURF_DESKTOP_SAVE_TEXT_H_
 
struct box;
struct hlcache_handle;
 
/* text currently being saved */
struct save_text_state {
char *block;
size_t length;
size_t alloc;
};
 
typedef enum {
WHITESPACE_NONE,
WHITESPACE_TAB,
WHITESPACE_ONE_NEW_LINE,
WHITESPACE_TWO_NEW_LINES
} save_text_whitespace;
 
void save_as_text(struct hlcache_handle *c, char *path);
void save_text_solve_whitespace(struct box *box, bool *first,
save_text_whitespace *before, const char **whitespace_text,
size_t *whitespace_length);
 
#endif
/programs/network/netsurf/netsurf/desktop/scrollbar.c
0,0 → 1,803
/*
* Copyright 2004-2008 James Bursa <bursa@users.sourceforge.net>
* Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Scrollbar widget (implementation).
*/
 
#include <stdbool.h>
#include <stdlib.h>
 
#include "desktop/mouse.h"
#include "desktop/scrollbar.h"
#include "desktop/options.h"
#include "desktop/plotters.h"
#include "desktop/plot_style.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
 
 
struct scrollbar {
bool horizontal; /* Horizontal scrollbar if true, else vertical
*/
int length; /* Length of the scrollbar widget */
 
int full_size; /* Length of the full scrollable area */
int visible_size; /* Length visible part of the scrollable area */
 
int offset; /* Current scroll offset to visible area */
 
int bar_pos; /* Position of the scrollbar */
int bar_len; /* Length of the scrollbar */
 
scrollbar_client_callback client_callback; /* Callback receiving
* scrollbar events */
void *client_data; /* User data passed to the callback */
 
bool dragging; /* Flag indicating drag at progess */
int drag_start_coord; /* Coordinate value at drag start */
int drag_start_pos; /* Scrollbar offset or bar_pos at drag start */
bool drag_content; /* Flag indicating that the drag corresponds to
* a dragged content area, rather than a dragged
* scrollbar. */
 
struct scrollbar *pair; /* Parpendicular scrollbar, or NULL */
bool pair_drag; /* Flag indicating that the current drag affects
the perpendicular scrollbar too */
};
 
 
 
/*
* Exported function. Documented in scrollbar.h
*/
bool scrollbar_create(bool horizontal, int length, int full_size,
int visible_size, void *client_data,
scrollbar_client_callback client_callback,
struct scrollbar **s)
{
struct scrollbar *scrollbar;
int well_length;
 
scrollbar = malloc(sizeof(struct scrollbar));
if (scrollbar == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
*s = NULL;
return false;
}
 
scrollbar->horizontal = horizontal;
scrollbar->length = length;
scrollbar->full_size = full_size;
scrollbar->visible_size = visible_size;
scrollbar->offset = 0;
scrollbar->bar_pos = 0;
scrollbar->pair = NULL;
scrollbar->pair_drag = false;
 
well_length = length - 2 * SCROLLBAR_WIDTH;
scrollbar->bar_len = (full_size == 0) ? 0 :
((well_length * visible_size) / full_size);
 
scrollbar->client_callback = client_callback;
scrollbar->client_data = client_data;
 
scrollbar->dragging = false;
scrollbar->drag_content = false;
 
*s = scrollbar;
 
return true;
}
 
 
/*
* Exported function. Documented in scrollbar.h
*/
void scrollbar_destroy(struct scrollbar *s)
{
if (s->pair != NULL)
s->pair->pair = NULL;
free(s);
}
 
 
/**
* Draw an outline rectangle common to a several scrollbar elements.
*
* \param x0 left border of the outline
* \param y0 top border of the outline
* \param x1 right border of the outline
* \param y1 bottom border of the outline
* \param c base colour of the outline, the other colours are created by
* lightening or darkening this one
* \param ctx current redraw context
* \param inset true for inset outline, false for an outset one
* \return
*/
 
static inline bool scrollbar_redraw_scrollbar_rectangle(int x0, int y0,
int x1, int y1, colour c, bool inset,
const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
 
static plot_style_t c0 = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_width = 1,
};
 
static plot_style_t c1 = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_width = 1,
};
 
static plot_style_t c2 = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_width = 1,
};
 
if (inset) {
c0.stroke_colour = darken_colour(c);
c1.stroke_colour = lighten_colour(c);
} else {
c0.stroke_colour = lighten_colour(c);
c1.stroke_colour = darken_colour(c);
}
c2.stroke_colour = blend_colour(c0.stroke_colour, c1.stroke_colour);
 
/* Plot the outline */
if (!plot->line(x0, y0, x1, y0, &c0)) return false;
if (!plot->line(x1, y0, x1, y1 + 1, &c1)) return false;
if (!plot->line(x1, y0, x1, y0 + 1, &c2)) return false;
if (!plot->line(x1, y1, x0, y1, &c1)) return false;
if (!plot->line(x0, y1, x0, y0, &c0)) return false;
if (!plot->line(x0, y1, x0, y1 + 1, &c2)) return false;
 
return true;
}
 
 
/*
* Exported function. Documented in scrollbar.h
*/
bool scrollbar_redraw(struct scrollbar *s, int x, int y,
const struct rect *clip, float scale,
const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
int w = SCROLLBAR_WIDTH;
int bar_pos, bar_c0, bar_c1;
int v[6]; /* array of triangle vertices */
int x0, y0, x1, y1;
 
colour bg_fill_colour = gui_system_colour_char("Scrollbar");
colour fg_fill_colour = gui_system_colour_char("ButtonFace");
colour arrow_fill_colour = gui_system_colour_char("ButtonText");
 
plot_style_t bg_fill_style = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = bg_fill_colour
};
plot_style_t fg_fill_style = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = fg_fill_colour
};
plot_style_t arrow_fill_style = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = arrow_fill_colour
};
 
x0 = x;
y0 = y;
x1 = x + (s->horizontal ? s->length : SCROLLBAR_WIDTH) - 1;
y1 = y + (s->horizontal ? SCROLLBAR_WIDTH : s->length) - 1;
bar_pos = s->bar_pos;
bar_c1 = (s->horizontal ? x0 : y0) + SCROLLBAR_WIDTH +
s->bar_pos + s->bar_len - 1;
 
if (scale != 1.0) {
w *= scale;
x0 *= scale;
y0 *= scale;
x1 *= scale;
y1 *= scale;
bar_pos *= scale;
bar_c1 *= scale;
}
 
bar_c0 = (s->horizontal ? x0 : y0) + w + bar_pos;
 
if (x1 < clip->x0 || y1 < clip->y0 || clip->x1 < x0 || clip->y1 < y0)
/* scrollbar is outside the clipping rectangle, nothing to
* render */
return true;
 
if (s->horizontal) {
/* scrollbar is horizontal */
/* scrollbar outline */
if (!scrollbar_redraw_scrollbar_rectangle(x0, y0, x1, y1,
bg_fill_colour, true, ctx))
return false;
/* left arrow icon border */
if (!scrollbar_redraw_scrollbar_rectangle(x0 + 1,
y0 + 1,
x0 + w - 2,
y1 - 1,
fg_fill_colour, false, ctx))
return false;
/* left arrow icon background */
if (!plot->rectangle(x0 + 2,
y0 + 2,
x0 + w - 2,
y1 - 1,
&fg_fill_style))
return false;
/* left arrow */
v[0] = x0 + w / 4;
v[1] = y0 + w / 2;
v[2] = x0 + w * 3 / 4;
v[3] = y0 + w / 4;
v[4] = x0 + w * 3 / 4;
v[5] = y0 + w * 3 / 4;
if (!plot->polygon(v, 3, &arrow_fill_style))
return false;
/* scrollbar well background */
if (!plot->rectangle(x0 + w - 1,
y0 + 1,
x1 - w + 2,
y1,
&bg_fill_style))
return false;
/* scrollbar position indicator bar */
if (!scrollbar_redraw_scrollbar_rectangle(bar_c0,
y0 + 1,
bar_c1,
y1 - 1,
fg_fill_colour, false, ctx))
return false;
if (!plot->rectangle(bar_c0 + 1,
y0 + 2,
bar_c1,
y1 - 1,
&fg_fill_style))
return false;
/* right arrow icon border */
if (!scrollbar_redraw_scrollbar_rectangle(x1 - w + 2,
y0 + 1,
x1 - 1,
y1 - 1,
fg_fill_colour, false, ctx))
return false;
/* right arrow icon background */
if (!plot->rectangle(x1 - w + 3,
y0 + 2,
x1 - 1,
y1 - 1,
&fg_fill_style))
return false;
/* right arrow */
v[0] = x1 - w / 4 + 1;
v[1] = y0 + w / 2;
v[2] = x1 - w * 3 / 4 + 1;
v[3] = y0 + w / 4;
v[4] = x1 - w * 3 / 4 + 1;
v[5] = y0 + w * 3 / 4;
if (!plot->polygon(v, 3, &arrow_fill_style))
return false;
} else {
/* scrollbar is vertical */
/* outline */
if (!scrollbar_redraw_scrollbar_rectangle(x0, y0, x1, y1,
bg_fill_colour, true, ctx))
return false;
/* top arrow background */
if (!scrollbar_redraw_scrollbar_rectangle(x0 + 1,
y0 + 1,
x1 - 1,
y0 + w - 2,
fg_fill_colour, false, ctx))
return false;
if (!plot->rectangle(x0 + 2,
y0 + 2,
x1 - 1,
y0 + w - 2,
&fg_fill_style))
return false;
/* up arrow */
v[0] = x0 + w / 2;
v[1] = y0 + w / 4;
v[2] = x0 + w / 4;
v[3] = y0 + w * 3 / 4;
v[4] = x0 + w * 3 / 4;
v[5] = y0 + w * 3 / 4;
if (!plot->polygon(v, 3, &arrow_fill_style))
return false;
/* scrollbar well background */
if (!plot->rectangle(x0 + 1,
y0 + w - 1,
x1,
y1 - w + 2,
&bg_fill_style))
return false;
/* scrollbar position indicator bar */
if (!scrollbar_redraw_scrollbar_rectangle(x0 + 1,
bar_c0,
x1 - 1,
bar_c1,
fg_fill_colour, false, ctx))
return false;
if (!plot->rectangle(x0 + 2,
bar_c0 + 1,
x1 - 1,
bar_c1,
&fg_fill_style))
return false;
/* bottom arrow background */
if (!scrollbar_redraw_scrollbar_rectangle(x0 + 1,
y1 - w + 2,
x1 - 1,
y1 - 1,
fg_fill_colour, false, ctx))
return false;
if (!plot->rectangle(x0 + 2,
y1 - w + 3,
x1 - 1,
y1 - 1,
&fg_fill_style))
return false;
/* down arrow */
v[0] = x0 + w / 2;
v[1] = y1 - w / 4 + 1;
v[2] = x0 + w / 4;
v[3] = y1 - w * 3 / 4 + 1;
v[4] = x0 + w * 3 / 4;
v[5] = y1 - w * 3 / 4 + 1;
if (!plot->polygon(v, 3, &arrow_fill_style))
return false;
}
 
return true;
}
 
 
/*
* Exported function. Documented in scrollbar.h
*/
void scrollbar_set(struct scrollbar *s, int value, bool bar_pos)
{
int well_length;
int old_offset = s->offset;
struct scrollbar_msg_data msg;
 
if (value < 0)
value = 0;
 
if (s->full_size == s->visible_size)
return;
 
well_length = s->length - 2 * SCROLLBAR_WIDTH;
if (bar_pos) {
if (value > well_length - s->bar_len)
s->bar_pos = well_length - s->bar_len;
else
s->bar_pos = value;
 
s->offset = ((well_length - s->bar_len) < 1) ? 0 :
(((s->full_size - s->visible_size) *
s->bar_pos) / (well_length - s->bar_len));
 
} else {
if (value > s->full_size - s->visible_size)
s->offset = s->full_size - s->visible_size;
else
s->offset = value;
 
s->bar_pos = (s->full_size < 1) ? 0 :
((well_length * s->offset) / s->full_size);
}
 
if (s->offset == old_offset)
/* Nothing happened */
return;
 
msg.scrollbar = s;
msg.msg = SCROLLBAR_MSG_MOVED;
msg.scroll_offset = s->offset;
s->client_callback(s->client_data, &msg);
}
 
 
/*
* Exported function. Documented in scrollbar.h
*/
bool scrollbar_scroll(struct scrollbar *s, int change)
{
int well_length;
int old_offset = s->offset;
struct scrollbar_msg_data msg;
 
if (change == 0 || s->full_size <= s->visible_size)
/* zero scroll step, or unscrollable */
return false;
 
/* Convert named change values to appropriate pixel offset value */
switch (change) {
case SCROLL_TOP:
change = -s->full_size;
break;
 
case SCROLL_PAGE_UP:
change = -s->visible_size;
break;
 
case SCROLL_PAGE_DOWN:
change = s->visible_size;
break;
 
case SCROLL_BOTTOM:
change = s->full_size;
break;
 
default:
/* Change value is already a pixel offset */
break;
}
 
/* Get new offset */
if (s->offset + change > s->full_size - s->visible_size)
s->offset = s->full_size - s->visible_size;
else if (s->offset + change < 0)
s->offset = 0;
else
s->offset += change;
 
if (s->offset == old_offset)
/* Nothing happened */
return false;
 
/* Update scrollbar */
well_length = s->length - 2 * SCROLLBAR_WIDTH;
s->bar_pos = (s->full_size < 1) ? 0 :
((well_length * s->offset) / s->full_size);
 
msg.scrollbar = s;
msg.msg = SCROLLBAR_MSG_MOVED;
msg.scroll_offset = s->offset;
s->client_callback(s->client_data, &msg);
 
return true;
}
 
 
/*
* Exported function. Documented in scrollbar.h
*/
int scrollbar_get_offset(struct scrollbar *s)
{
if (s == NULL)
return 0;
return s->offset;
}
 
 
/*
* Exported function. Documented in scrollbar.h
*/
void scrollbar_set_extents(struct scrollbar *s, int length,
int visible_size, int full_size)
{
int well_length;
int cur_excess = s->full_size - s->visible_size;
 
if (length != -1)
s->length = length;
if (visible_size != -1)
s->visible_size = visible_size;
if (full_size != -1)
s->full_size = full_size;
 
if (s->full_size < s->visible_size)
s->full_size = s->visible_size;
 
/* Update scroll offset (scaled in proportion with change in excess) */
s->offset = (cur_excess < 1) ? 0 :
((s->full_size - s->visible_size) * s->offset /
cur_excess);
 
well_length = s->length - 2 * SCROLLBAR_WIDTH;
 
if (s->full_size < 1) {
s->bar_len = well_length;
s->bar_pos = 0;
} else {
s->bar_len = (well_length * s->visible_size) / s->full_size;
s->bar_pos = (well_length * s->offset) / s->full_size;
}
}
 
 
/*
* Exported function. Documented in scrollbar.h
*/
bool scrollbar_is_horizontal(struct scrollbar *s)
{
return s->horizontal;
}
 
 
/**
* Internal procedure used for starting a drag scroll for a scrollbar.
*
* \param s the scrollbar to start the drag for
* \param x the X coordinate of the drag start
* \param y the Y coordinate of the drag start
* \param content_drag whether this should be a reverse drag (used when the
* user drags the content area, rather than the scrollbar)
* \param pair whether the drag is a '2D' scroll
*/
 
static void scrollbar_drag_start_internal(struct scrollbar *s, int x, int y,
bool content_drag, bool pair)
{
struct scrollbar_msg_data msg;
 
s->drag_start_coord = s->horizontal ? x : y;
s->drag_start_pos = (content_drag) ? s->offset : s->bar_pos;
 
s->dragging = true;
s->drag_content = content_drag;
 
msg.scrollbar = s;
 
/* \todo - some proper numbers please! */
if (s->horizontal) {
msg.x0 = -2048;
msg.x1 = 2048;
msg.y0 = 0;
msg.y1 = 0;
} else {
msg.x0 = 0;
msg.x1 = 0;
msg.y0 = -2048;
msg.y1 = 2048;
}
 
if (pair && s->pair != NULL) {
s->pair_drag = true;
 
s->pair->drag_start_coord =
s->pair->horizontal ? x : y;
 
s->pair->drag_start_pos = (content_drag) ? s->pair->offset :
s->pair->bar_pos;
 
s->pair->dragging = true;
s->pair->drag_content = content_drag;
 
if (s->pair->horizontal) {
msg.x0 = -2048;
msg.x1 = 2048;
} else {
msg.y0 = -2048;
msg.y1 = 2048;
}
}
msg.msg = SCROLLBAR_MSG_SCROLL_START;
s->client_callback(s->client_data, &msg);
}
 
 
/*
* Exported function. Documented in scrollbar.h
*/
const char *scrollbar_mouse_action(struct scrollbar *s,
browser_mouse_state mouse, int x, int y)
{
int x0, y0, x1, y1;
int val;
const char *status;
bool h;
 
/* we want mouse presses and mouse drags that were not started at the
* scrollbar indication bar to be launching actions on the scroll area
*/
bool but1 = ((mouse & BROWSER_MOUSE_PRESS_1) ||
((mouse & BROWSER_MOUSE_HOLDING_1) &&
(mouse & BROWSER_MOUSE_DRAG_ON) &&
!s->dragging));
bool but2 = ((mouse & BROWSER_MOUSE_PRESS_2) ||
((mouse & BROWSER_MOUSE_HOLDING_2) &&
(mouse & BROWSER_MOUSE_DRAG_ON) &&
!s->dragging));
 
h = s->horizontal;
 
x0 = 0;
y0 = 0;
x1 = h ? s->length : SCROLLBAR_WIDTH;
y1 = h ? SCROLLBAR_WIDTH : s->length;
 
if (!s->dragging && !(x >= x0 && x <= x1 && y >= y0 && y <= y1)) {
/* Not a drag and mouse outside scrollbar widget */
return NULL;
}
 
 
if (h)
val = x;
else
val = y;
 
if (s->dragging) {
val -= s->drag_start_coord;
if (s->drag_content)
val = -val;
if (val != 0)
scrollbar_set(s, s->drag_start_pos + val,
!(s->drag_content));
if (s->pair_drag) {
scrollbar_mouse_action(s->pair, mouse, x, y);
status = messages_get("ScrollBoth");
} else
status = messages_get(h ? "ScrollH" : "ScrollV");
 
return status;
}
 
if (val < SCROLLBAR_WIDTH) {
/* left/up arrow */
status = messages_get(h ? "ScrollLeft" : "ScrollUp");
if (but1)
scrollbar_set(s, s->offset - SCROLLBAR_WIDTH, false);
else if (but2)
scrollbar_set(s, s->offset + SCROLLBAR_WIDTH, false);
 
} else if (val < SCROLLBAR_WIDTH + s->bar_pos) {
/* well between left/up arrow and bar */
 
status = messages_get(h ? "ScrollPLeft" : "ScrollPUp");
 
if (but1)
scrollbar_set(s, s->offset - s->length, false);
else if (but2)
scrollbar_set(s, s->offset + s->length, false);
 
} else if (val > s->length - SCROLLBAR_WIDTH) {
/* right/down arrow */
 
status = messages_get(h ? "ScrollRight" : "ScrollDown");
 
if (but1)
scrollbar_set(s, s->offset + SCROLLBAR_WIDTH, false);
else if (but2)
scrollbar_set(s, s->offset - SCROLLBAR_WIDTH, false);
 
} else if (val > SCROLLBAR_WIDTH + s->bar_pos +
s->bar_len) {
/* well between right/down arrow and bar */
 
status = messages_get(h ? "ScrollPRight" : "ScrollPDown");
if (but1)
scrollbar_set(s, s->offset + s->length, false);
else if (but2)
scrollbar_set(s, s->offset - s->length, false);
}
else {
/* scrollbar position indication bar */
status = messages_get(h ? "ScrollH" : "ScrollV");
}
 
if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2) &&
(val >= SCROLLBAR_WIDTH + s->bar_pos
&& val < SCROLLBAR_WIDTH + s->bar_pos +
s->bar_len))
/* The mouse event is a drag start on the scrollbar position
* indication bar. */
scrollbar_drag_start_internal(s, x, y, false,
(mouse & BROWSER_MOUSE_DRAG_2) ? true : false);
 
return status;
}
 
 
/*
* Exported function. Documented in scrollbar.h
*/
void scrollbar_mouse_drag_end(struct scrollbar *s,
browser_mouse_state mouse, int x, int y)
{
struct scrollbar_msg_data msg;
int val, drag_start_pos;
 
assert(s->dragging);
 
drag_start_pos = s->drag_start_pos;
val = (s->horizontal ? x : y) - s->drag_start_coord;
 
if (s->drag_content)
val = -val;
if (val != 0)
scrollbar_set(s, drag_start_pos + val, !(s->drag_content));
 
s->dragging = false;
s->drag_content = false;
 
if (s->pair_drag) {
s->pair_drag = false;
 
drag_start_pos = s->pair->drag_start_pos;
val = (s->pair->horizontal ? x : y) - s->pair->drag_start_coord;
 
if (s->pair->drag_content)
val = -val;
if (val != 0)
scrollbar_set(s->pair, drag_start_pos + val,
!(s->pair->drag_content));
 
s->pair->dragging = false;
s->pair->drag_content = false;
}
 
msg.scrollbar = s;
msg.msg = SCROLLBAR_MSG_SCROLL_FINISHED;
s->client_callback(s->client_data, &msg);
}
 
 
/*
* Exported function. Documented in scrollbar.h
*/
void scrollbar_start_content_drag(struct scrollbar *s, int x, int y)
{
scrollbar_drag_start_internal(s, x, y, true, true);
}
 
 
/*
* Exported function. Documented in scrollbar.h
*/
void scrollbar_make_pair(struct scrollbar *horizontal,
struct scrollbar *vertical)
{
assert(horizontal->horizontal &&
!vertical->horizontal);
 
horizontal->pair = vertical;
vertical->pair = horizontal;
}
 
 
/*
* Exported function. Documented in scrollbar.h
*/
void *scrollbar_get_data(struct scrollbar *s)
{
return s->client_data;
}
 
/programs/network/netsurf/netsurf/desktop/scrollbar.h
0,0 → 1,208
/*
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Scrollbar widget (interface).
*/
 
#ifndef _NETSURF_DESKTOP_SCROLLBAR_H_
#define _NETSURF_DESKTOP_SCROLLBAR_H_
 
#include <stdbool.h>
#include <limits.h>
 
#include "desktop/browser.h"
 
#define SCROLLBAR_WIDTH 16
 
/* Region dependent values for scrollbar_scroll function */
#define SCROLL_TOP INT_MIN
#define SCROLL_PAGE_UP INT_MIN + 1
#define SCROLL_PAGE_DOWN INT_MAX - 1
#define SCROLL_BOTTOM INT_MAX
 
struct scrollbar;
 
typedef enum {
SCROLLBAR_MSG_MOVED, /* the scroll value has changed */
SCROLLBAR_MSG_SCROLL_START, /* a scrollbar drag has started, all
* mouse events should be passed to
* the scrollbar regardless of the
* coordinates
*/
SCROLLBAR_MSG_SCROLL_FINISHED, /* cancel the above */
} scrollbar_msg;
 
struct scrollbar_msg_data {
struct scrollbar *scrollbar;
scrollbar_msg msg;
int scroll_offset;
int x0, y0, x1, y1;
};
 
/**
* Client callback for the scrollbar.
*
* \param client_data user data passed at scroll creation
* \param scrollbar_data scrollbar message data
*/
typedef void(*scrollbar_client_callback)(void *client_data,
struct scrollbar_msg_data *scrollbar_data);
 
 
/**
* Create a scrollbar.
*
* \param horizontal true = horizontal scrollbar, false = vertical
* \param length length of scrollbar widget
* \param full_size length of contained scrollable area
* \param visible_size length of visible part of scrollable area
* \param client_data data for the client callback
* \param client_callback client callback for scrollbar events
* \param s updated to point at the newly created scrollbar
* \return true if scrollbar has been created succesfully or false on
* memory exhaustion
*/
bool scrollbar_create(bool horizontal, int length, int full_size,
int visible_size, void *client_data,
scrollbar_client_callback client_callback,
struct scrollbar **s);
 
/**
* Destroy a scrollbar.
*
* \param s the scrollbar to be destroyed
*/
void scrollbar_destroy(struct scrollbar *s);
 
/**
* Redraw a part of the scrollbar.
*
* \param s the scrollbar to be redrawn
* \param x the X coordinate to draw the scrollbar at
* \param y the Y coordinate to draw the scrollbar at
* \param clip the clipping rectangle
* \param scale scale for the redraw
* \param ctx current redraw context
* \return true on succes false otherwise
*/
bool scrollbar_redraw(struct scrollbar *s, int x, int y,
const struct rect *clip, float scale,
const struct redraw_context *ctx);
 
/**
* Set the scroll value of the scrollbar.
*
* \param s the scrollbar to have the value set
* \param value the new value to be set
* \param bar_pos true if the value is for the scrollbar indication bar
* position, false if it is for the scrolled area offset
*/
void scrollbar_set(struct scrollbar *s, int value, bool bar_pos);
 
/**
* Scroll the scrollbar by given amount.
*
* \param s the scrollbar to be scrolled
* \param change the change in scroll offset required (in px)
* \return true iff the scrollbar was moved.
*/
bool scrollbar_scroll(struct scrollbar *s, int change);
 
/**
* Get the current scroll offset to the visible part of the full area.
*
* \param s the scrollbar to get the scroll offset value from
* \return current scroll offset
*/
int scrollbar_get_offset(struct scrollbar *s);
 
/**
* Set the length of the scrollbar widget, the size of the visible area, and the
* size of the full area.
*
* \param s the scrollbar to set the values for
* \param length -1 or the new scrollbar widget length
* \param visible_size -1 or the new size of the visible area
* \param full_size -1 or the new size of the full contained area
*/
void scrollbar_set_extents(struct scrollbar *s, int length,
int visible_size, int full_size);
 
/**
* Check orientation of the scrollbar.
*
* \param s the scrollbar to check the orientation of
* \return true for a horizontal scrollbar, else false (vertical)
*/
bool scrollbar_is_horizontal(struct scrollbar *s);
 
/**
* Handle mouse actions other then drag ends.
*
* \param s the scrollbar which gets the mouse action
* \param mouse mouse state
* \param x X coordinate of the mouse
* \param y Y coordinate of the mouse
* \return message for the status bar or NULL on failure
*/
const char *scrollbar_mouse_action(struct scrollbar *s,
browser_mouse_state mouse, int x, int y);
 
/**
* Handle end of mouse drags.
*
* \param s the scrollbar for which the drag ends
* \param mouse mouse state
* \param x X coordinate of the mouse
* \param y Y coordinate of the mouse
*/
void scrollbar_mouse_drag_end(struct scrollbar *s,
browser_mouse_state mouse, int x, int y);
 
/**
* Called when the content is being dragged to the scrollbars have to adjust.
* If the content has both scrollbars, and scrollbar_make_pair has beed called
* before, only the one scroll which will receive further mouse events has to be
* passed.
*
* \param s one of the the scrollbars owned by the dragged content
* \param x X coordinate of mouse during drag start
* \param y Y coordinate of mouse during drag start
*/
void scrollbar_start_content_drag(struct scrollbar *s, int x, int y);
 
/**
* Connect a horizontal and a vertical scrollbar into a pair so that they
* co-operate during 2D drags.
*
* \param horizontal the scrollbar used for horizontal scrolling
* \param vertical the scrollbar used for vertical scrolling
*/
void scrollbar_make_pair(struct scrollbar *horizontal,
struct scrollbar *vertical);
 
/**
* Get the scrollbar's client data
*
* \param s the scrollbar to get the client data from
* \return client data
*/
void *scrollbar_get_data(struct scrollbar *s);
 
#endif
/programs/network/netsurf/netsurf/desktop/search.c
0,0 → 1,136
/*
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
* Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Free text search (core)
*/
#include "utils/config.h"
 
#include <ctype.h>
#include <string.h>
#include <dom/dom.h>
#include "content/content.h"
#include "content/hlcache.h"
#include "desktop/browser_private.h"
#include "desktop/gui.h"
#include "desktop/options.h"
#include "desktop/search.h"
#include "desktop/selection.h"
#include "render/box.h"
#include "render/html.h"
#include "render/search.h"
#include "render/textplain.h"
#include "utils/config.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/utils.h"
 
 
/* callback informing us that a search context is nolonger valid */
static void browser_window_search_invalidate(struct search_context *context,
void *p)
{
struct browser_window *bw = p;
assert(bw != NULL);
 
if (bw->cur_search != NULL && bw->cur_search == context) {
/* The browser's current search is the one being invalidated */
bw->cur_search = NULL;
}
}
 
 
bool browser_window_search_create_context(struct browser_window *bw,
struct gui_search_callbacks *gui_callbacks, void *gui_p)
{
struct search_callbacks callbacks;
assert(bw != NULL);
assert(gui_callbacks != NULL);
 
if (bw->cur_search != NULL)
search_destroy_context(bw->cur_search);
bw->cur_search = NULL;
 
if (!bw->current_content)
return false;
 
callbacks.gui = gui_callbacks;
callbacks.gui_p = gui_p;
callbacks.invalidate = browser_window_search_invalidate;
callbacks.p = bw;
bw->cur_search = search_create_context(bw->current_content, callbacks);
 
if (bw->cur_search == NULL)
return false;
 
return true;
}
 
 
void browser_window_search_destroy_context(struct browser_window *bw)
{
assert(bw != NULL);
 
if (bw->cur_search != NULL)
search_destroy_context(bw->cur_search);
bw->cur_search = NULL;
}
 
 
/**
* to simplify calls to search_step(); checks that the browser_window is
* non-NULL, creates a new search_context in case of a new search
* \param bw the browser_window the search refers to
* \param callbacks the callbacks to modify appearance according to results
* \param gui_p a pointer returned to the callbacks
* \return true for success
*/
bool browser_window_search_verify_new(struct browser_window *bw,
struct gui_search_callbacks *gui_callbacks, void *gui_p)
{
if (bw == NULL)
return false;
if (bw->cur_search == NULL)
return browser_window_search_create_context(bw,
gui_callbacks, gui_p);
 
return true;
}
 
 
void browser_window_search_step(struct browser_window *bw,
search_flags_t flags, const char *string)
{
assert(bw != NULL);
 
if (bw->cur_search != NULL)
search_step(bw->cur_search, flags, string);
}
 
 
void browser_window_search_show_all(bool all, struct browser_window *bw)
{
assert(bw != NULL);
 
if (bw->cur_search != NULL)
search_show_all(all, bw->cur_search);
}
 
/programs/network/netsurf/netsurf/desktop/search.h
0,0 → 1,86
/*
* Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef _NETSURF_DESKTOP_SEARCH_H_
#define _NETSURF_DESKTOP_SEARCH_H_
 
#include <ctype.h>
#include <string.h>
 
typedef enum {
SEARCH_FLAG_CASE_SENSITIVE = (1 << 0),
SEARCH_FLAG_FORWARDS = (1 << 1),
SEARCH_FLAG_SHOWALL = (1 << 2)
} search_flags_t;
 
/**
* Change the displayed search status.
* \param found search pattern matched in text
* \param p gui private data pointer provided with search callbacks
*/
typedef void (*gui_search_status)(bool found, void *p);
 
/**
* display hourglass while searching
* \param active start/stop indicator
* \param p gui private data pointer provided with search callbacks
*/
typedef void (*gui_search_hourglass)(bool active, void *p);
 
/**
* add search string to recent searches list
* front has full liberty how to implement the bare notification;
* core gives no guarantee of the integrity of the const char *
* \param string search pattern
* \param p gui private data pointer provided with search callbacks
*/
typedef void (*gui_search_add_recent)(const char *string, void *p);
 
/**
* activate search forwards button in gui
* \param active activate/inactivate
* \param p gui private data pointer provided with search callbacks
*/
typedef void (*gui_search_forward_state)(bool active, void *p);
 
/**
* activate search back button in gui
* \param active activate/inactivate
* \param p gui private data pointer provided with search callbacks
*/
typedef void (*gui_search_back_state)(bool active, void *p);
 
struct gui_search_callbacks {
gui_search_forward_state forward_state;
gui_search_back_state back_state;
gui_search_status status;
gui_search_hourglass hourglass;
gui_search_add_recent add_recent;
};
 
 
bool browser_window_search_create_context(struct browser_window *bw,
struct gui_search_callbacks *gui_callbacks, void *gui_p);
void browser_window_search_destroy_context(struct browser_window *bw);
bool browser_window_search_verify_new(struct browser_window *bw,
struct gui_search_callbacks *gui_callbacks, void *gui_p);
void browser_window_search_step(struct browser_window *bw,
search_flags_t flags, const char *string);
void browser_window_search_show_all(bool all, struct browser_window *bw);
 
#endif
/programs/network/netsurf/netsurf/desktop/searchweb.c
0,0 → 1,316
/*
* Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* web search (core)
*/
#include "utils/config.h"
 
#include <ctype.h>
#include <string.h>
#include "content/content.h"
#include "content/hlcache.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
#include "desktop/options.h"
#include "desktop/searchweb.h"
#include "utils/config.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/utils.h"
 
static struct search_provider {
char *name; /**< readable name such as 'google', 'yahoo', etc */
char *hostname; /**< host address such as www.google.com */
char *searchstring; /** < such as "www.google.com?search=%s" */
char *ico; /** < location of domain's favicon */
} current_search_provider;
 
static hlcache_handle *search_ico = NULL;
char *search_engines_file_location;
char *search_default_ico_location;
 
#ifdef WITH_BMP
static nserror search_web_ico_callback(hlcache_handle *ico,
const hlcache_event *event, void *pw);
#endif
 
/**
* creates a new browser window according to the search term
* \param searchterm such as "my search term"
*/
 
bool search_web_new_window(struct browser_window *bw, const char *searchterm)
{
char *encsearchterm;
char *url;
if (url_escape(searchterm,0, true, NULL, &encsearchterm) !=
URL_FUNC_OK)
return false;
url = search_web_get_url(encsearchterm);
free(encsearchterm);
browser_window_create(url, bw, NULL, true, true);
free(url);
return true;
}
 
/** simplistic way of checking whether an entry from the url bar is an
* url / a search; could be improved to properly test terms
*/
 
bool search_is_url(const char *url)
{
/** \todo Implement this properly */
 
/* For now, everything is an URL */
return true;
}
 
/**
* caches the details of the current web search provider
* \param reference the enum value of the provider
* browser init code [as well as changing preferences code] should call
* search_web_provider_details(option_search_provider)
*/
 
void search_web_provider_details(int reference)
{
char buf[300];
int ref = 0;
FILE *f;
if (search_engines_file_location == NULL)
return;
f = fopen(search_engines_file_location, "r");
if (f == NULL)
return;
while (fgets(buf, sizeof(buf), f) != NULL) {
if (buf[0] == '\0')
continue;
buf[strlen(buf)-1] = '\0';
if (ref++ == (int)reference)
break;
}
fclose(f);
if (current_search_provider.name != NULL)
free(current_search_provider.name);
current_search_provider.name = strdup(strtok(buf, "|"));
if (current_search_provider.hostname != NULL)
free(current_search_provider.hostname);
current_search_provider.hostname = strdup(strtok(NULL, "|"));
if (current_search_provider.searchstring != NULL)
free(current_search_provider.searchstring);
current_search_provider.searchstring = strdup(strtok(NULL, "|"));
if (current_search_provider.ico != NULL)
free(current_search_provider.ico);
current_search_provider.ico = strdup(strtok(NULL, "|"));
return;
}
 
/**
* escapes a search term then creates the appropriate url from it
*/
 
char *search_web_from_term(const char *searchterm)
{
char *encsearchterm, *url;
if (url_escape(searchterm, 0, true, NULL, &encsearchterm)
!= URL_FUNC_OK)
return strdup(searchterm);
url = search_web_get_url(encsearchterm);
free(encsearchterm);
return url;
}
 
/** accessor for global search provider name */
 
char *search_web_provider_name(void)
{
if (current_search_provider.name)
return strdup(current_search_provider.name);
return strdup("google");
}
 
/** accessor for global search provider hostname */
 
char *search_web_provider_host(void)
{
if (current_search_provider.hostname)
return strdup(current_search_provider.hostname);
return strdup("www.google.com");
}
 
/** accessor for global search provider ico name */
 
char *search_web_ico_name(void)
{
if (current_search_provider.ico)
return strdup(current_search_provider.ico);
return strdup("http://www.google.com/favicon.ico");
}
 
/**
* creates a full url from an encoded search term
*/
 
char *search_web_get_url(const char *encsearchterm)
{
char *pref, *ret;
int len;
if (current_search_provider.searchstring)
pref = strdup(current_search_provider.searchstring);
else
pref = strdup("http://www.google.com/search?q=%s");
if (pref == NULL) {
warn_user(messages_get("NoMemory"), 0);
return NULL;
}
len = strlen(encsearchterm) + strlen(pref);
ret = malloc(len -1); /* + '\0' - "%s" */
if (ret == NULL) {
warn_user(messages_get("NoMemory"), 0);
free(pref);
return NULL;
}
snprintf(ret, len-1, pref, encsearchterm);
free(pref);
return ret;
}
 
/**
* function to retrieve the search web ico, from cache / from local
* filesystem / from the web
* \param localdefault true when there is no appropriate favicon
* update the search_ico cache else delay until fetcher callback
*/
 
void search_web_retrieve_ico(bool localdefault)
{
#if !defined(WITH_BMP)
/* This function is of limited use when no BMP support
* is enabled, given the icons it is fetching are BMPs
* more often than not. This also avoids an issue where
* all this code goes mad if BMP support is not enabled.
*/
return;
#else
content_type accept = CONTENT_IMAGE;
char *url;
nserror error;
nsurl *icon_nsurl;
 
if (localdefault) {
if (search_default_ico_location == NULL)
return;
url = malloc(SLEN("file://") + strlen(
search_default_ico_location) + 1);
if (url == NULL) {
warn_user(messages_get("NoMemory"), 0);
return;
}
strcpy(url, "file://");
strcat(url, search_default_ico_location);
} else {
url = search_web_ico_name();
}
 
if (url == NULL) {
warn_user(messages_get("NoMemory"), 0);
return;
}
 
error = nsurl_create(url, &icon_nsurl);
if (error != NSERROR_OK) {
free(url);
search_ico = NULL;
return;
}
 
error = hlcache_handle_retrieve(icon_nsurl, 0, NULL, NULL,
search_web_ico_callback, NULL, NULL, accept,
&search_ico);
 
nsurl_unref(icon_nsurl);
 
if (error != NSERROR_OK)
search_ico = NULL;
 
free(url);
#endif /* WITH_BMP */
}
 
/**
* returns a reference to the static global search_ico [ / NULL]
* caller may adjust ico's settings; clearing / free()ing is the core's
* responsibility
*/
 
hlcache_handle *search_web_ico(void)
{
return search_ico;
}
 
/**
* Cleans up any remaining resources during shutdown.
*/
void search_web_cleanup(void)
{
if (search_ico != NULL) {
hlcache_handle_release(search_ico);
search_ico = NULL;
}
}
 
/**
* callback function to cache ico then notify front when successful
* else retry default from local file system
*/
 
#ifdef WITH_BMP
nserror search_web_ico_callback(hlcache_handle *ico,
const hlcache_event *event, void *pw)
{
switch (event->type) {
case CONTENT_MSG_LOADING:
case CONTENT_MSG_READY:
break;
 
case CONTENT_MSG_DONE:
LOG(("got favicon '%s'", nsurl_access(hlcache_handle_get_url(ico))));
gui_window_set_search_ico(search_ico);
break;
 
case CONTENT_MSG_ERROR:
LOG(("favicon %s error: %s",
nsurl_access(hlcache_handle_get_url(ico)),
event->data.error));
hlcache_handle_release(search_ico);
search_ico = NULL;
search_web_retrieve_ico(true);
break;
 
case CONTENT_MSG_STATUS:
break;
 
default:
assert(0);
}
 
return NSERROR_OK;
}
#endif /* WITH_BMP */
/programs/network/netsurf/netsurf/desktop/searchweb.h
0,0 → 1,80
/*
* Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef _NETSURF_DESKTOP_SEARCH_WEB_H_
#define _NETSURF_DESKTOP_SEARCH_WEB_H_
 
#include <ctype.h>
#include <stdbool.h>
#include <string.h>
 
struct browser_window;
struct hlcache_handle;
 
extern char *search_engines_file_location;
extern char *search_default_ico_location;
 
/**
* open new tab/window for web search term
*/
bool search_web_new_window(struct browser_window *bw, const char *searchterm);
 
/**
* retrieve full search url from unencoded search term
*/
char *search_web_from_term(const char *searchterm);
 
/**
* retrieve full search url from encoded web search term
*/
char *search_web_get_url(const char *encsearchterm);
 
/**
* cache details of web search provider from file
*/
void search_web_provider_details(int reference);
 
/**
* retrieve name of web search provider
*/
char *search_web_provider_name(void);
 
/**
* retrieve hostname of web search provider
*/
char *search_web_provider_host(void);
 
/**
* retrieve name of .ico for search bar
*/
char *search_web_ico_name(void);
 
/**
* check whether an URL is in fact a search term
* \param url the url being checked
* \return true for url, false for search
*/
bool search_is_url(const char *url);
 
void search_web_retrieve_ico(bool localdefault);
 
struct hlcache_handle *search_web_ico(void);
 
void search_web_cleanup(void);
 
#endif
/programs/network/netsurf/netsurf/desktop/selection.c
0,0 → 1,1278
/*
* Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
* Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Text selection within browser windows (implementation).
*/
 
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <dom/dom.h>
 
#include "desktop/browser_private.h"
#include "desktop/gui.h"
#include "desktop/mouse.h"
#include "desktop/plotters.h"
#include "desktop/save_text.h"
#include "desktop/selection.h"
#include "render/box.h"
#include "render/font.h"
#include "render/form.h"
#include "render/html_internal.h"
#include "render/textplain.h"
#include "utils/log.h"
#include "utils/utf8.h"
#include "utils/utils.h"
 
 
/**
* Text selection works by labelling each node in the box tree with its
* start index in the textual representation of the tree's content.
*
* Text input fields and text areas have their own number spaces so that
* they can be relabelled more efficiently when editing (rather than relabel
* the entire box tree) and so that selections are either wholly within
* or wholly without the textarea/input box.
*/
 
#define IS_INPUT(box) ((box) && (box)->gadget && \
((box)->gadget->type == GADGET_TEXTAREA || \
(box)->gadget->type == GADGET_TEXTBOX || \
(box)->gadget->type == GADGET_PASSWORD))
 
/** check whether the given text box is in the same number space as the
current selection; number spaces are identified by their uppermost nybble */
 
#define NUMBER_SPACE(x) ((x) & 0xF0000000U)
#define SAME_SPACE(s, offset) (NUMBER_SPACE((s)->max_idx) == NUMBER_SPACE(offset))
 
#define SPACE_LEN(b) ((b->space == 0) ? 0 : 1)
 
 
struct rdw_info {
bool inited;
struct rect r;
};
 
struct selection_string {
char *buffer;
size_t buffer_len;
size_t length;
 
int n_styles;
nsclipboard_styles *styles;
};
 
 
typedef bool (*seln_traverse_handler)(const char *text, size_t length,
struct box *box, void *handle, const char *whitespace_text,
size_t whitespace_length);
 
 
static bool redraw_handler(const char *text, size_t length, struct box *box,
void *handle, const char *whitespace_text,
size_t whitespace_length);
static void selection_redraw(struct selection *s, unsigned start_idx,
unsigned end_idx);
static bool save_handler(const char *text, size_t length, struct box *box,
void *handle, const char *whitespace_text,
size_t whitespace_length);
static bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx,
unsigned *start_offset, unsigned *end_offset);
static bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
unsigned int num_space, seln_traverse_handler handler,
void *handle, save_text_whitespace *before, bool *first,
bool do_marker);
static struct box *get_box(struct box *b, unsigned offset, size_t *pidx);
 
 
/**
* Get the browser window containing the content a selection object belongs to.
*
* \param s selection object
* \return the browser window
*/
static struct browser_window * selection_get_browser_window(struct selection *s)
{
if (s->is_html)
return html_get_browser_window(s->c);
else
return textplain_get_browser_window(s->c);
}
 
 
/**
* Creates a new selection object associated with a browser window.
*
* \return new selection context
*/
 
struct selection *selection_create(struct content *c, bool is_html)
{
struct selection *s = calloc(1, sizeof(struct selection));
if (s) {
selection_prepare(s, c, is_html);
}
 
return s;
}
 
/**
* Prepare a newly created selection object for use.
*
* \param s selection object
* \param c content
* \param is_html true if content is html false if content is textplain
*/
 
void selection_prepare(struct selection *s, struct content *c, bool is_html)
{
if (s) {
s->c = c;
s->is_html = is_html;
s->root = NULL;
s->drag_state = DRAG_NONE;
s->max_idx = 0;
selection_clear(s, false);
}
}
 
 
/**
* Destroys a selection object, without updating the
* owning window (caller should call selection_clear()
* first if update is desired)
*
* \param s selection object
*/
 
void selection_destroy(struct selection *s)
{
if (s != NULL)
free(s);
}
 
 
/**
* Initialise the selection object to use the given box subtree as its root,
* ie. selections are confined to that subtree, whilst maintaining the current
* selection whenever possible because, for example, it's just the page being
* resized causing the layout to change.
*
* \param s selection object
* \param root the box (page/textarea) to be used as the root node for this selection
*/
 
void selection_reinit(struct selection *s, struct box *root)
{
unsigned root_idx;
 
assert(s);
 
if (IS_INPUT(root)) {
static int next_idx = 0;
if (!++next_idx) next_idx = 1;
root_idx = next_idx << 28;
}
else
root_idx = 0;
 
// if (s->root == root) {
// /* keep the same number space as before, because we want
// to keep the selection too */
// root_idx = (s->max_idx & 0xF0000000U);
// }
// else {
// static int next_idx = 0;
// root_idx = (next_idx++) << 28;
// }
 
s->root = root;
if (root) {
s->max_idx = selection_label_subtree(root, root_idx);
} else {
if (s->is_html == false)
s->max_idx = textplain_size(s->c);
else
s->max_idx = 0;
}
 
if (s->defined) {
if (s->end_idx > s->max_idx) s->end_idx = s->max_idx;
if (s->start_idx > s->max_idx) s->start_idx = s->max_idx;
s->defined = (s->end_idx > s->start_idx);
}
}
 
 
/**
* Initialise the selection object to use the given box subtree as its root,
* ie. selections are confined to that subtree.
*
* \param s selection object
* \param root the box (page/textarea) to be used as the root node for this selection
*/
 
void selection_init(struct selection *s, struct box *root)
{
if (s->defined)
selection_clear(s, true);
 
s->defined = false;
s->start_idx = 0;
s->end_idx = 0;
s->drag_state = DRAG_NONE;
 
selection_reinit(s, root);
}
 
 
/**
* Indicate whether the selected text is read only, ie. cannot be modified.
*
* \param s selection object
* \return true iff the selection is read only
*/
 
bool selection_read_only(struct selection *s)
{
return !s->root || !NUMBER_SPACE(s->root->byte_offset);
 
}
 
 
/**
* Label each text box in the given box subtree with its position
* in a textual representation of the content.
*
* \param s selection object
* \param node box at root of subtree
* \param idx current position within textual representation
* \return updated position
*/
 
unsigned selection_label_subtree(struct box *box, unsigned idx)
{
struct box *child = box->children;
 
box->byte_offset = idx;
 
if (box->text)
idx += box->length + SPACE_LEN(box);
 
while (child) {
if (!IS_INPUT(child)) {
if (child->list_marker)
idx = selection_label_subtree(
child->list_marker, idx);
 
idx = selection_label_subtree(child, idx);
}
child = child->next;
}
 
return idx;
}
 
 
/**
* Handles mouse clicks (including drag starts) in or near a selection
*
* \param s selection object
* \param mouse state of mouse buttons and modifier keys
* \param idx byte offset within textual representation
*
* \return true iff the click has been handled by the selection code
*/
 
bool selection_click(struct selection *s, browser_mouse_state mouse,
unsigned idx)
{
browser_mouse_state modkeys =
(mouse & (BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_2));
int pos = -1; /* 0 = inside selection, 1 = after it */
struct browser_window *top = selection_get_browser_window(s);
 
if (top == NULL)
return false; /* not our problem */
 
top = browser_window_get_root(top);
 
if (!SAME_SPACE(s, idx))
return false; /* not our problem */
 
if (selection_defined(s)) {
if (idx > s->start_idx) {
if (idx <= s->end_idx)
pos = 0;
else
pos = 1;
}
}
 
if (!pos &&
((mouse & BROWSER_MOUSE_DRAG_1) ||
(modkeys && (mouse & BROWSER_MOUSE_DRAG_2)))) {
/* drag-saving selection */
 
gui_drag_save_selection(s, top->window);
}
else if (!modkeys) {
if (pos && (mouse & BROWSER_MOUSE_PRESS_1)) {
/* Clear the selection if mouse is pressed outside the selection,
* Otherwise clear on release (to allow for drags) */
browser_window_set_selection(top, s);
 
selection_clear(s, true);
} else if (mouse & BROWSER_MOUSE_DRAG_1) {
/* start new selection drag */
browser_window_set_selection(top, s);
 
selection_clear(s, true);
selection_set_start(s, idx);
selection_set_end(s, idx);
 
s->drag_state = DRAG_END;
 
gui_start_selection(top->window);
}
else if (mouse & BROWSER_MOUSE_DRAG_2) {
 
/* adjust selection, but only if there is one */
if (!selection_defined(s))
return false; /* ignore Adjust drags */
 
browser_window_set_selection(top, s);
 
if (pos >= 0) {
selection_set_end(s, idx);
 
s->drag_state = DRAG_END;
}
else {
selection_set_start(s, idx);
 
s->drag_state = DRAG_START;
}
 
gui_start_selection(top->window);
}
/* Selection should be cleared when button is released but in
* the RO interface click is the same as press */
// else if (!pos && (mouse & BROWSER_MOUSE_CLICK_1)) {
// /* clear selection */
// selection_clear(s, true);
// s->drag_state = DRAG_NONE;
// }
else if (mouse & BROWSER_MOUSE_CLICK_2) {
 
/* ignore Adjust clicks when there's no selection */
if (!selection_defined(s))
return false;
 
if (pos >= 0)
selection_set_end(s, idx);
else
selection_set_start(s, idx);
s->drag_state = DRAG_NONE;
}
else
return false;
}
else {
/* not our problem */
return false;
}
 
/* this mouse click is selection-related */
return true;
}
 
 
/**
* Handles movements related to the selection, eg. dragging of start and
* end points.
*
* \param s selection object
* \param mouse state of mouse buttons and modifier keys
* \param idx byte offset within text representation
*/
 
void selection_track(struct selection *s, browser_mouse_state mouse,
unsigned idx)
{
if (!SAME_SPACE(s, idx))
return;
 
if (!mouse) {
s->drag_state = DRAG_NONE;
}
 
switch (s->drag_state) {
 
case DRAG_START:
if (idx > s->end_idx) {
unsigned old_end = s->end_idx;
selection_set_end(s, idx);
selection_set_start(s, old_end);
s->drag_state = DRAG_END;
}
else
selection_set_start(s, idx);
break;
 
case DRAG_END:
if (idx < s->start_idx) {
unsigned old_start = s->start_idx;
selection_set_start(s, idx);
selection_set_end(s, old_start);
s->drag_state = DRAG_START;
}
else
selection_set_end(s, idx);
break;
 
default:
break;
}
}
 
 
/**
* Tests whether a text box lies partially within the given range of
* byte offsets, returning the start and end indexes of the bytes
* that are enclosed.
*
* \param box box to be tested
* \param start_idx byte offset of start of range
* \param end_idx byte offset of end of range
* \param start_offset receives the start offset of the selected part
* \param end_offset receives the end offset of the selected part
* \return true iff the range encloses at least part of the box
*/
 
bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx,
unsigned *start_offset, unsigned *end_offset)
{
size_t box_length = box->length + SPACE_LEN(box);
 
if (box_length > 0) {
if (box->byte_offset >= start_idx &&
box->byte_offset + box_length <= end_idx) {
 
/* fully enclosed */
*start_offset = 0;
*end_offset = box_length;
return true;
}
else if (box->byte_offset + box_length > start_idx &&
box->byte_offset < end_idx) {
/* partly enclosed */
int offset = 0;
int len;
 
if (box->byte_offset < start_idx)
offset = start_idx - box->byte_offset;
 
len = box_length - offset;
 
if (box->byte_offset + box_length > end_idx)
len = end_idx - (box->byte_offset + offset);
 
*start_offset = offset;
*end_offset = offset + len;
 
return true;
}
}
return false;
}
 
 
/**
* Traverse the given box subtree, calling the handler function (with its handle)
* for all boxes that lie (partially) within the given range
*
* \param box box subtree
* \param start_idx start of range within textual representation (bytes)
* \param end_idx end of range
* \param num_space number space of the selection
* \param handler handler function to call
* \param handle handle to pass
* \param before type of whitespace to place before next encountered text
* \param first whether this is the first box with text
* \param do_marker whether deal enter any marker box
* \return false iff traversal abandoned part-way through
*/
 
bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
unsigned int num_space, seln_traverse_handler handler,
void *handle, save_text_whitespace *before, bool *first,
bool do_marker)
{
struct box *child;
const char *whitespace_text = "";
size_t whitespace_length = 0;
 
assert(box);
 
/* If selection starts inside marker */
if (box->parent && box->parent->list_marker == box && !do_marker) {
/* set box to main list element */
box = box->parent;
}
 
/* If box has a list marker */
if (box->list_marker) {
/* do the marker box before continuing with the rest of the
* list element */
if (!traverse_tree(box->list_marker, start_idx, end_idx,
num_space, handler, handle, before, first,
true))
return false;
}
 
/* we can prune this subtree, it's after the selection */
if (box->byte_offset >= end_idx)
return true;
 
/* read before calling the handler in case it modifies the tree */
child = box->children;
 
/* If nicely formatted output of the selected text is required, work
* out what whitespace should be placed before the next bit of text */
if (before) {
save_text_solve_whitespace(box, first, before, &whitespace_text,
&whitespace_length);
}
else {
whitespace_text = NULL;
}
if (num_space == NUMBER_SPACE(box->byte_offset) &&
box->type != BOX_BR &&
!((box->type == BOX_FLOAT_LEFT ||
box->type == BOX_FLOAT_RIGHT) &&
!box->text)) {
unsigned start_offset;
unsigned end_offset;
 
if (selected_part(box, start_idx, end_idx, &start_offset,
&end_offset)) {
if (!handler(box->text + start_offset, min(box->length,
end_offset) - start_offset,
box, handle, whitespace_text,
whitespace_length))
return false;
if (before) {
*first = false;
*before = WHITESPACE_NONE;
}
}
}
 
/* find the first child that could lie partially within the selection;
* this is important at the top-levels of the tree for pruning subtrees
* that lie entirely before the selection */
 
if (child) {
struct box *next = child->next;
 
while (next && next->byte_offset < start_idx) {
child = next;
next = child->next;
}
 
while (child) {
/* read before calling the handler in case it modifies
* the tree */
struct box *next = child->next;
 
if (!traverse_tree(child, start_idx, end_idx, num_space,
handler, handle, before, first, false))
return false;
 
child = next;
}
}
 
return true;
}
 
 
/**
* Traverse the current selection, calling the handler function (with its
* handle) for all boxes that lie (partially) within the given range
*
* \param handler handler function to call
* \param handle handle to pass
* \return false iff traversal abandoned part-way through
*/
 
static bool selection_traverse(struct selection *s,
seln_traverse_handler handler, void *handle)
{
save_text_whitespace before = WHITESPACE_NONE;
bool first = true;
const char *text;
size_t length;
 
if (!selection_defined(s))
return true; /* easy case, nothing to do */
 
if (s->root) {
/* HTML */
return traverse_tree(s->root, s->start_idx, s->end_idx,
NUMBER_SPACE(s->max_idx), handler, handle,
&before, &first, false);
}
 
/* Text */
text = textplain_get_raw_data(s->c, s->start_idx, s->end_idx, &length);
 
if (text && !handler(text, length, NULL, handle, NULL, 0))
return false;
 
return true;
}
 
 
/**
* Selection traversal handler for redrawing the screen when the selection
* has been altered.
*
* \param text pointer to text string
* \param length length of text to be appended (bytes)
* \param box pointer to text box being (partially) added
* \param handle unused handle, we don't need one
* \param whitespace_text whitespace to place before text for formatting
* may be NULL
* \param whitespace_length length of whitespace_text
* \return true iff successful and traversal should continue
*/
 
bool redraw_handler(const char *text, size_t length, struct box *box,
void *handle, const char *whitespace_text,
size_t whitespace_length)
{
if (box) {
struct rdw_info *r = (struct rdw_info*)handle;
int width, height;
int x, y;
plot_font_style_t fstyle;
 
font_plot_style_from_css(box->style, &fstyle);
 
/* \todo - it should be possible to reduce the redrawn area by
* considering the 'text', 'length' and 'space' parameters */
box_coords(box, &x, &y);
 
width = box->padding[LEFT] + box->width + box->padding[RIGHT];
height = box->padding[TOP] + box->height + box->padding[BOTTOM];
 
if (box->type == BOX_TEXT && box->space != 0)
width += box->space;
 
if (r->inited) {
if (x < r->r.x0) r->r.x0 = x;
if (y < r->r.y0) r->r.y0 = y;
if (x + width > r->r.x1) r->r.x1 = x + width;
if (y + height > r->r.y1) r->r.y1 = y + height;
}
else {
r->inited = true;
r->r.x0 = x;
r->r.y0 = y;
r->r.x1 = x + width;
r->r.y1 = y + height;
}
}
return true;
}
 
 
/**
* Redraws the given range of text.
*
* \param s selection object
* \param start_idx start offset (bytes) within the textual representation
* \param end_idx end offset (bytes) within the textual representation
*/
 
void selection_redraw(struct selection *s, unsigned start_idx, unsigned end_idx)
{
struct rdw_info rdw;
 
assert(end_idx >= start_idx);
rdw.inited = false;
 
if (s->root) {
if (!traverse_tree(s->root, start_idx, end_idx,
NUMBER_SPACE(s->max_idx), redraw_handler, &rdw,
NULL, NULL, false))
return;
}
else {
if (s->is_html == false && end_idx > start_idx) {
textplain_coords_from_range(s->c, start_idx,
end_idx, &rdw.r);
rdw.inited = true;
}
}
 
if (rdw.inited)
content__request_redraw(s->c, rdw.r.x0, rdw.r.y0,
rdw.r.x1 - rdw.r.x0, rdw.r.y1 - rdw.r.y0);
}
 
 
/**
* Append text to selection string.
*
* \param text text to be added
* \param length length of text in bytes
* \param space indicates whether a trailing space should be appended
* \param sel_string string to append to, may be resized
* \return true iff successful
*/
 
static bool selection_string_append(const char *text, size_t length, bool space,
plot_font_style_t *style, struct selection_string *sel_string)
{
size_t new_length = sel_string->length + length + (space ? 1 : 0) + 1;
 
if (style != NULL) {
/* Add text run style */
nsclipboard_styles *new_styles;
 
if (sel_string->n_styles == 0)
assert(sel_string->length == 0);
 
new_styles = realloc(sel_string->styles,
(sel_string->n_styles + 1) *
sizeof(nsclipboard_styles));
if (new_styles == NULL)
return false;
 
sel_string->styles = new_styles;
 
sel_string->styles[sel_string->n_styles].style = *style;
sel_string->styles[sel_string->n_styles].start =
sel_string->length;
 
sel_string->n_styles++;
}
 
if (new_length > sel_string->buffer_len) {
/* Need to extend buffer */
size_t new_alloc = new_length + (new_length / 4);
char *new_buff;
 
new_buff = realloc(sel_string->buffer, new_alloc);
if (new_buff == NULL)
return false;
 
sel_string->buffer = new_buff;
sel_string->buffer_len = new_alloc;
}
 
/* Copy text onto end of existing text in buffer */
memcpy(sel_string->buffer + sel_string->length, text, length);
sel_string->length += length;
 
if (space)
sel_string->buffer[sel_string->length++] = ' ';
 
/* Ensure NULL termination */
sel_string->buffer[sel_string->length] = '\0';
 
return true;
}
 
 
/**
* Selection traversal routine for appending text to a string
*
* \param text pointer to text being added, or NULL for newline
* \param length length of text to be appended (bytes)
* \param box pointer to text box, or NULL if from textplain
* \param handle selection string to append to
* \param whitespace_text whitespace to place before text for formatting
* may be NULL
* \param whitespace_length length of whitespace_text
* \return true iff successful and traversal should continue
*/
 
static bool selection_copy_handler(const char *text, size_t length,
struct box *box, void *handle, const char *whitespace_text,
size_t whitespace_length)
{
bool add_space = false;
plot_font_style_t style;
plot_font_style_t *pstyle = NULL;
 
/* add any whitespace which precedes the text from this box */
if (whitespace_text != NULL && whitespace_length > 0) {
if (!selection_string_append(whitespace_text,
whitespace_length, false, pstyle, handle)) {
return false;
}
}
 
if (box != NULL) {
/* HTML */
add_space = (box->space != 0);
 
if (box->style != NULL) {
/* Override default font style */
font_plot_style_from_css(box->style, &style);
pstyle = &style;
} else {
/* If there's no style, there must be no text */
assert(box->text == NULL);
}
}
 
/* add the text from this box */
if (!selection_string_append(text, length, add_space, pstyle, handle))
return false;
 
return true;
}
 
 
/**
* Get copy of selection as string
*
* \param s selection
* \return string of selected text, or NULL. Ownership passed to caller.
*/
 
char *selection_get_copy(struct selection *s)
{
struct selection_string sel_string = {
.buffer = NULL,
.buffer_len = 0,
.length = 0,
 
.n_styles = 0,
.styles = NULL
};
 
if (s == NULL || !s->defined)
return NULL;
 
if (!selection_traverse(s, selection_copy_handler, &sel_string)) {
free(sel_string.buffer);
free(sel_string.styles);
return NULL;
}
 
free(sel_string.styles);
 
return sel_string.buffer;
}
 
 
 
/**
* Copy the selected contents to the clipboard
*
* \param s selection
* \return true iff successful
*/
bool selection_copy_to_clipboard(struct selection *s)
{
struct selection_string sel_string = {
.buffer = NULL,
.buffer_len = 0,
.length = 0,
 
.n_styles = 0,
.styles = NULL
};
 
if (s == NULL || !s->defined)
return false;
 
if (!selection_traverse(s, selection_copy_handler, &sel_string)) {
free(sel_string.buffer);
free(sel_string.styles);
return false;
}
 
gui_set_clipboard(sel_string.buffer, sel_string.length,
sel_string.styles, sel_string.n_styles);
 
free(sel_string.buffer);
free(sel_string.styles);
 
return true;
}
 
 
/**
* Clears the current selection, optionally causing the screen to be updated.
*
* \param s selection object
* \param redraw true iff the previously selected region of the browser
* window should be redrawn
*/
 
void selection_clear(struct selection *s, bool redraw)
{
int old_start, old_end;
bool was_defined;
struct browser_window *top = selection_get_browser_window(s);
 
assert(s);
was_defined = selection_defined(s);
old_start = s->start_idx;
old_end = s->end_idx;
 
s->defined = false;
s->start_idx = 0;
s->end_idx = 0;
 
if (!top)
return;
 
top = browser_window_get_root(top);
 
gui_clear_selection(top->window);
 
if (redraw && was_defined)
selection_redraw(s, old_start, old_end);
}
 
 
/**
* Selects all the text within the box subtree controlled by
* this selection object, updating the screen accordingly.
*
* \param s selection object
*/
 
void selection_select_all(struct selection *s)
{
assert(s);
s->defined = true;
if (IS_INPUT(s->root))
selection_set_start(s, s->root->children->children->byte_offset);
else
selection_set_start(s, 0);
selection_set_end(s, s->max_idx);
}
 
 
/**
* Set the start position of the current selection, updating the screen.
*
* \param s selection object
* \param offset byte offset within textual representation
*/
 
void selection_set_start(struct selection *s, unsigned offset)
{
bool was_defined = selection_defined(s);
unsigned old_start = s->start_idx;
s->start_idx = offset;
s->defined = (s->start_idx < s->end_idx);
if (s->defined && s->root && s->root->gadget) {
/* update the caret text_box and offset so that it stays at the
* beginning of the selection */
s->root->gadget->caret_text_box = selection_get_start(s,
&s->root->gadget->caret_box_offset);
assert(s->root->gadget->caret_text_box != NULL);
}
 
if (was_defined) {
if (offset < old_start)
selection_redraw(s, s->start_idx, old_start);
else
selection_redraw(s, old_start, s->start_idx);
}
else if (selection_defined(s))
selection_redraw(s, s->start_idx, s->end_idx);
}
 
 
/**
* Set the end position of the current selection, updating the screen.
*
* \param s selection object
* \param offset byte offset within textual representation
*/
 
void selection_set_end(struct selection *s, unsigned offset)
{
bool was_defined = selection_defined(s);
unsigned old_end = s->end_idx;
 
s->end_idx = offset;
s->defined = (s->start_idx < s->end_idx);
 
if (was_defined) {
if (offset < old_end)
selection_redraw(s, s->end_idx, old_end);
else
selection_redraw(s, old_end, s->end_idx);
}
else if (selection_defined(s))
selection_redraw(s, s->start_idx, s->end_idx);
}
 
 
/**
* Get the box and index of the specified byte offset within the
* textual representation.
*
* \param b root node of search
* \param offset byte offset within textual representation
* \param pidx receives byte index of selection start point within box
* \return ptr to box, or NULL if no selection defined
*/
 
struct box *get_box(struct box *b, unsigned offset, size_t *pidx)
{
struct box *child = b->children;
 
if (b->text) {
 
if (offset >= b->byte_offset &&
offset <= b->byte_offset + b->length + SPACE_LEN(b)) {
 
/* it's in this box */
*pidx = offset - b->byte_offset;
return b;
}
}
 
/* find the first child that could contain this offset */
if (child) {
struct box *next = child->next;
while (next && next->byte_offset < offset) {
child = next;
next = child->next;
}
return get_box(child, offset, pidx);
}
 
return NULL;
}
 
 
/**
* Get the box and index of the selection start, if defined.
*
* \param s selection object
* \param pidx receives byte index of selection start point within box
* \return ptr to box, or NULL if no selection defined
*/
 
struct box *selection_get_start(struct selection *s, size_t *pidx)
{
return (s->defined ? get_box(s->root, s->start_idx, pidx) : NULL);
}
 
 
/**
* Get the box and index of the selection end, if defined.
*
* \param s selection object
* \param pidx receives byte index of selection end point within box
* \return ptr to box, or NULL if no selection defined.
*/
 
struct box *selection_get_end(struct selection *s, size_t *pidx)
{
return (s->defined ? get_box(s->root, s->end_idx, pidx) : NULL);
}
 
 
/**
* Tests whether a text range lies partially within the selection, if there is
* a selection defined, returning the start and end indexes of the bytes
* that should be selected.
*
* \param s the selection object
* \param start byte offset of start of text
* \param start_idx receives the start index (in bytes) of the highlighted portion
* \param end_idx receives the end index (in bytes)
* \return true iff part of the given box lies within the selection
*/
 
bool selection_highlighted(const struct selection *s,
unsigned start, unsigned end,
unsigned *start_idx, unsigned *end_idx)
{
/* caller should have checked first for efficiency */
assert(s);
assert(selection_defined(s));
 
if (end <= s->start_idx || start >= s->end_idx)
return false;
 
*start_idx = (s->start_idx >= start) ? (s->start_idx - start) : 0;
*end_idx = min(end, s->end_idx) - start;
 
return true;
 
// assert(box);
// assert(IS_TEXT(box));
 
// return selected_part(box, s->start_idx, s->end_idx, start_idx, end_idx);
}
 
 
/**
* Selection traversal handler for saving the text to a file.
*
* \param text pointer to text being added, or NULL for newline
* \param length length of text to be appended (bytes)
* \param box pointer to text box (or NULL for textplain content)
* \param handle our save_state workspace pointer
* \param whitespace_text whitespace to place before text for formatting
* may be NULL
* \param whitespace_length length of whitespace_text
* \return true iff the file writing succeeded and traversal should continue.
*/
 
bool save_handler(const char *text, size_t length, struct box *box,
void *handle, const char *whitespace_text,
size_t whitespace_length)
{
struct save_text_state *sv = handle;
size_t new_length;
int space = 0;
 
assert(sv);
 
if (box && (box->space > 0))
space = 1;
 
if (whitespace_text)
length += whitespace_length;
 
new_length = sv->length + whitespace_length + length + space;
if (new_length >= sv->alloc) {
size_t new_alloc = sv->alloc + (sv->alloc / 4);
char *new_block;
 
if (new_alloc < new_length) new_alloc = new_length;
 
new_block = realloc(sv->block, new_alloc);
if (!new_block) return false;
 
sv->block = new_block;
sv->alloc = new_alloc;
}
if (whitespace_text) {
memcpy(sv->block + sv->length, whitespace_text,
whitespace_length);
}
memcpy(sv->block + sv->length + whitespace_length, text, length);
sv->length += length;
 
if (space == 1)
sv->block[sv->length++] = ' ';
 
return true;
}
 
 
/**
* Save the given selection to a file.
*
* \param s selection object
* \param path pathname to be used
* \return true iff the save succeeded
*/
 
bool selection_save_text(struct selection *s, const char *path)
{
struct save_text_state sv = { NULL, 0, 0 };
utf8_convert_ret ret;
char *result;
FILE *out;
 
if (!selection_traverse(s, save_handler, &sv)) {
free(sv.block);
return false;
}
 
if (!sv.block)
return false;
 
ret = utf8_to_local_encoding(sv.block, sv.length, &result);
free(sv.block);
 
if (ret != UTF8_CONVERT_OK) {
LOG(("failed to convert to local encoding, return %d", ret));
return false;
}
 
out = fopen(path, "w");
if (out) {
int res = fputs(result, out);
if (res < 0) {
LOG(("Warning: writing data failed"));
}
 
res = fputs("\n", out);
fclose(out);
free(result);
return (res != EOF);
}
free(result);
 
return false;
}
 
 
/**
* Adjust the selection to reflect a change in the selected text,
* eg. editing in a text area/input field.
*
* \param s selection object
* \param byte_offset byte offset of insertion/removal point
* \param change byte size of change, +ve = insertion, -ve = removal
* \param redraw true iff the screen should be updated
*/
 
void selection_update(struct selection *s, size_t byte_offset,
int change, bool redraw)
{
if (selection_defined(s) &&
byte_offset >= s->start_idx &&
byte_offset < s->end_idx)
{
if (change > 0)
s->end_idx += change;
else
s->end_idx +=
max(change, (int)(byte_offset - s->end_idx));
}
}
/programs/network/netsurf/netsurf/desktop/selection.h
0,0 → 1,112
/*
* Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Text selection within browser windows (interface).
*/
 
#ifndef _NETSURF_DESKTOP_SELECTION_H_
#define _NETSURF_DESKTOP_SELECTION_H_
 
#include <stdbool.h>
#include "desktop/mouse.h"
 
struct box;
 
typedef enum {
DRAG_NONE,
DRAG_START,
DRAG_END
} seln_drag_state;
 
 
/* this structure should be treated as opaque outside selection.c
(it's defined here to accelerate selection_defined(s) for reduced
impact on redraw code) */
 
struct selection
{
struct content *c;
struct box *root;
 
unsigned max_idx; /* total bytes in text representation */
 
unsigned start_idx; /* offset in bytes within text representation */
unsigned end_idx;
 
bool defined;
bool is_html;
 
seln_drag_state drag_state;
};
 
 
struct selection *selection_create(struct content *c, bool is_html);
void selection_prepare(struct selection *s, struct content *c, bool is_html);
void selection_destroy(struct selection *s);
 
void selection_init(struct selection *s, struct box *root);
void selection_reinit(struct selection *s, struct box *root);
 
/* struct box *selection_root(struct selection *s); */
#define selection_root(s) ((s)->root)
 
/* bool selection_defined(struct selection *s); */
#define selection_defined(s) ((s)->defined)
 
/* bool selection_dragging(struct selection *s); */
#define selection_dragging(s) ((s)->drag_state != DRAG_NONE)
 
/* bool selection_dragging_start(struct selection *s); */
#define selection_dragging_start(s) ((s)->drag_state == DRAG_START)
 
bool selection_read_only(struct selection *s);
 
void selection_clear(struct selection *s, bool redraw);
void selection_select_all(struct selection *s);
 
void selection_set_start(struct selection *s, unsigned idx);
void selection_set_end(struct selection *s, unsigned idx);
 
struct box *selection_get_start(struct selection *s, size_t *pidx);
struct box *selection_get_end(struct selection *s, size_t *pidx);
 
bool selection_click(struct selection *s, browser_mouse_state mouse,
unsigned idx);
void selection_track(struct selection *s, browser_mouse_state mouse,
unsigned idx);
 
bool selection_copy_to_clipboard(struct selection *s);
char * selection_get_copy(struct selection *s);
 
/** Handles completion of a drag operation */
/* void selection_drag_end(struct selection *s); */
#define selection_drag_end(s) ((s)->drag_state = DRAG_NONE)
 
bool selection_highlighted(const struct selection *s,
unsigned start, unsigned end,
unsigned *start_idx, unsigned *end_idx);
 
bool selection_save_text(struct selection *s, const char *path);
 
void selection_update(struct selection *s, size_t byte_offset, int change,
bool redraw);
unsigned selection_label_subtree(struct box *box, unsigned idx);
 
#endif
/programs/network/netsurf/netsurf/desktop/sslcert.c
0,0 → 1,280
/*
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* SSL Certificate verification UI (implementation)
*/
 
#include "utils/config.h"
 
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include "content/content.h"
#include "content/fetch.h"
#include "content/hlcache.h"
#include "content/urldb.h"
#include "desktop/browser.h"
#include "desktop/sslcert.h"
#include "desktop/tree.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/nsurl.h"
#include "utils/utils.h"
 
/** Flags for each type of ssl tree node. */
enum tree_element_ssl {
TREE_ELEMENT_SSL_VERSION = 0x01,
TREE_ELEMENT_SSL_VALID_FROM = 0x02,
TREE_ELEMENT_SSL_VALID_TO = 0x03,
TREE_ELEMENT_SSL_CERT_TYPE = 0x04,
TREE_ELEMENT_SSL_SERIAL = 0x05,
TREE_ELEMENT_SSL_ISSUER = 0x06,
};
 
/** ssl certificate verification context. */
struct sslcert_session_data {
unsigned long num; /**< The number of ssl certificates in the chain */
nsurl *url; /**< The url of the certificate */
struct tree *tree; /**< The root of the treeview */
llcache_query_response cb; /**< callback when cert is accepted or rejected */
void *cbpw; /**< context passed to callback */
};
 
/** Handle for the window icon. */
static hlcache_handle *sslcert_icon = NULL;
 
/** Initialise ssl certificate window. */
void sslcert_init(const char* icon_name)
{
sslcert_icon = tree_load_icon(icon_name);
}
 
 
/**
* Get flags with which the sslcert tree should be created;
*
* \return the flags
*/
unsigned int sslcert_get_tree_flags(void)
{
return TREE_NO_DRAGS | TREE_NO_SELECT;
}
 
 
void sslcert_cleanup(void)
{
if (sslcert_icon != NULL)
hlcache_handle_release(sslcert_icon);
}
 
struct sslcert_session_data *
sslcert_create_session_data(unsigned long num,
nsurl *url,
llcache_query_response cb,
void *cbpw)
{
struct sslcert_session_data *data;
 
data = malloc(sizeof(struct sslcert_session_data));
if (data == NULL) {
warn_user("NoMemory", 0);
return NULL;
}
data->url = nsurl_ref(url);
if (data->url == NULL) {
free(data);
warn_user("NoMemory", 0);
return NULL;
}
data->num = num;
data->cb = cb;
data->cbpw = cbpw;
 
return data;
}
 
static node_callback_resp sslcert_node_callback(void *user_data,
struct node_msg_data *msg_data)
{
if (msg_data->msg == NODE_DELETE_ELEMENT_IMG)
return NODE_CALLBACK_HANDLED;
return NODE_CALLBACK_NOT_HANDLED;
}
 
static struct node *sslcert_create_node(const struct ssl_cert_info *cert)
{
struct node *node;
struct node_element *element;
char *text;
 
text = messages_get_buff("SSL_Certificate_Subject", cert->subject);
if (text == NULL)
return NULL;
 
node = tree_create_leaf_node(NULL, NULL, text, false, false, false);
if (node == NULL) {
free(text);
return NULL;
}
tree_set_node_user_callback(node, sslcert_node_callback, NULL);
 
/* add issuer node */
element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_SSL_ISSUER, false);
if (element != NULL) {
text = messages_get_buff("SSL_Certificate_Issuer", cert->issuer);
if (text == NULL) {
tree_delete_node(NULL, node, false);
return NULL;
}
tree_update_node_element(NULL, element, text, NULL);
}
 
/* add version node */
element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_SSL_VERSION, false);
if (element != NULL) {
text = messages_get_buff("SSL_Certificate_Version", cert->version);
if (text == NULL) {
tree_delete_node(NULL, node, false);
return NULL;
}
tree_update_node_element(NULL, element, text, NULL);
}
 
/* add valid from node */
element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_SSL_VALID_FROM, false);
if (element != NULL) {
text = messages_get_buff("SSL_Certificate_ValidFrom", cert->not_before);
if (text == NULL) {
tree_delete_node(NULL, node, false);
return NULL;
}
tree_update_node_element(NULL, element, text, NULL);
}
 
 
/* add valid to node */
element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_SSL_VALID_TO, false);
if (element != NULL) {
text = messages_get_buff("SSL_Certificate_ValidTo", cert->not_after);
if (text == NULL) {
tree_delete_node(NULL, node, false);
return NULL;
}
tree_update_node_element(NULL, element, text, NULL);
}
 
/* add certificate type */
element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_SSL_CERT_TYPE, false);
if (element != NULL) {
text = messages_get_buff("SSL_Certificate_Type", cert->cert_type);
if (text == NULL) {
tree_delete_node(NULL, node, false);
return NULL;
}
tree_update_node_element(NULL, element, text, NULL);
}
 
/* add serial node */
element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_SSL_SERIAL, false);
if (element != NULL) {
text = messages_get_buff("SSL_Certificate_Serial", cert->serial);
if (text == NULL) {
tree_delete_node(NULL, node, false);
return NULL;
}
tree_update_node_element(NULL, element, text, NULL);
}
 
/* set the display icon */
tree_set_node_icon(NULL, node, sslcert_icon);
 
return node;
}
 
bool sslcert_load_tree(struct tree *tree,
const struct ssl_cert_info *certs,
struct sslcert_session_data *data)
{
struct node *tree_root;
struct node *node;
unsigned long cert_loop;
 
assert(data != NULL && certs != NULL && tree != NULL);
 
tree_root = tree_get_root(tree);
 
for (cert_loop = 0; cert_loop < data->num; cert_loop++) {
node = sslcert_create_node(&(certs[cert_loop]));
if (node != NULL) {
/* There is no problem creating the node
* add an entry for it in the root of the
* treeview .
*/
tree_link_node(tree, tree_root, node, false);
}
}
 
data->tree = tree;
 
return true;
 
}
 
 
static void sslcert_cleanup_session(struct sslcert_session_data *session)
{
assert(session != NULL);
 
if (session->url)
nsurl_unref(session->url);
 
free(session);
}
 
 
 
bool sslcert_reject(struct sslcert_session_data *session)
{
session->cb(false, session->cbpw);
sslcert_cleanup_session(session);
return true;
}
 
 
/**
* Handle acceptance of certificate
*/
bool sslcert_accept(struct sslcert_session_data *session)
{
assert(session != NULL);
 
urldb_set_cert_permissions(session->url, true);
 
session->cb(true, session->cbpw);
 
sslcert_cleanup_session(session);
 
return true;
}
/programs/network/netsurf/netsurf/desktop/sslcert.h
0,0 → 1,43
/*
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
 
#ifndef _NETSURF_DESKTOP_SSLCERT_H_
#define _NETSURF_DESKTOP_SSLCERT_H_
 
#include <stdbool.h>
 
#include "desktop/tree.h"
 
struct sslcert_session_data;
 
void sslcert_init(const char* icon_name);
unsigned int sslcert_get_tree_flags(void);
void sslcert_cleanup(void);
 
struct sslcert_session_data *sslcert_create_session_data(unsigned long num,
nsurl *url, llcache_query_response cb, void *cbpw);
bool sslcert_load_tree(struct tree *tree,
const struct ssl_cert_info *certs,
struct sslcert_session_data *data);
bool sslcert_reject(struct sslcert_session_data *session);
bool sslcert_accept(struct sslcert_session_data *session);
 
#endif
/programs/network/netsurf/netsurf/desktop/textarea.c
0,0 → 1,2055
/*
* Copyright 2006 John-Mark Bell <jmb@netsurf-browser.org>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Single/Multi-line UTF-8 text area (implementation)
*/
 
#include <stdint.h>
#include <string.h>
#include "css/utils.h"
#include "desktop/mouse.h"
#include "desktop/textarea.h"
#include "desktop/textinput.h"
#include "desktop/plotters.h"
#include "desktop/scrollbar.h"
#include "render/font.h"
#include "utils/log.h"
#include "utils/utf8.h"
#include "utils/utils.h"
 
#define CARET_COLOR 0x0000FF
 
static plot_style_t pstyle_stroke_caret = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = CARET_COLOR,
.stroke_width = 1,
};
 
struct line_info {
unsigned int b_start; /**< Byte offset of line start */
unsigned int b_length; /**< Byte length of line */
};
struct textarea_drag {
textarea_drag_type type;
union {
struct scrollbar* scrollbar;
} data;
};
 
struct textarea_utf8 {
char *data; /**< UTF-8 text */
unsigned int alloc; /**< Size of allocated text */
unsigned int len; /**< Length of text, in bytes */
unsigned int utf8_len; /**< Length of text, in characters without
* trailing NULL */
};
 
struct textarea {
 
int scroll_x, scroll_y; /**< scroll offsets for the textarea */
 
struct scrollbar *bar_x; /**< Horizontal scroll. */
struct scrollbar *bar_y; /**< Vertical scroll. */
 
unsigned int flags; /**< Textarea flags */
int vis_width; /**< Visible width, in pixels */
int vis_height; /**< Visible height, in pixels */
 
int pad_top; /**< Top padding, inside border, in pixels */
int pad_right; /**< Right padding, inside border, in pixels */
int pad_bottom; /**< Bottom padding, inside border, in pixels */
int pad_left; /**< Left padding, inside border, in pixels */
 
int border_width; /**< Border width, in pixels */
colour border_col; /**< Border colour */
 
plot_font_style_t fstyle; /**< Text style, inc. textarea bg col */
plot_font_style_t sel_fstyle; /**< Selected text style */
 
struct textarea_utf8 text; /**< Textarea text content */
#define PASSWORD_REPLACEMENT "\xe2\x80\xa2"
struct textarea_utf8 password; /**< Text for obscured display */
 
struct textarea_utf8 *show; /**< Points at .text or .password */
 
struct {
int line; /**< Line caret is on */
int char_off; /**< Character index of caret on line */
} caret_pos;
 
int caret_x; /**< cached X coordinate of the caret */
int caret_y; /**< cached Y coordinate of the caret */
 
int sel_start; /**< Character index of sel start (inclusive) */
int sel_end; /**< Character index of sel end (exclusive) */
 
int h_extent; /**< Width of content in px */
int v_extent; /**< Height of content in px */
int line_count; /**< Count of lines */
#define LINE_CHUNK_SIZE 16
struct line_info *lines; /**< Line info array */
int line_height; /**< Line height obtained from style */
 
/** Callback function for messages to client */
textarea_client_callback callback;
 
void *data; /**< Client data for callback */
 
int drag_start_char; /**< Character index of drag start */
struct textarea_drag drag_info; /**< Drag information */
};
 
 
 
/**
* Normalises any line endings within the text, replacing CRLF or CR with
* LF as necessary. If the textarea is single line, then all linebreaks are
* converted into spaces.
*
* \param ta Text area
* \param b_start Byte offset to start at
* \param b_len Byte length to check
*/
static void textarea_normalise_text(struct textarea *ta,
unsigned int b_start, unsigned int b_len)
{
bool multi = (ta->flags & TEXTAREA_MULTILINE) ? true : false;
unsigned int index;
 
/* Remove CR characters. If it's a CRLF pair delete the CR, or replace
* CR with LF otherwise.
*/
for (index = 0; index < b_len; index++) {
if (ta->text.data[b_start + index] == '\r') {
if (b_start + index + 1 <= ta->text.len &&
ta->text.data[b_start + index + 1] ==
'\n') {
ta->text.len--;
ta->text.utf8_len--;
memmove(ta->text.data + b_start + index,
ta->text.data + b_start +
index + 1,
ta->text.len - b_start - index);
}
else
ta->text.data[b_start + index] = '\n';
}
/* Replace newlines with spaces if this is a single line
* textarea.
*/
if (!multi && (ta->text.data[b_start + index] == '\n'))
ta->text.data[b_start + index] = ' ';
}
 
}
 
 
/**
* Selects a character range in the textarea and redraws it
*
* \param ta Text area
* \param c_start First character (inclusive)
* \param c_end Last character (exclusive)
* \return true on success false otherwise
*/
static bool textarea_select(struct textarea *ta, int c_start, int c_end)
{
int swap;
struct textarea_msg msg;
 
/* Ensure start is the beginning of the selection */
if (c_start > c_end) {
swap = c_start;
c_start = c_end;
c_end = swap;
}
 
if (ta->sel_start == c_start && ta->sel_end == c_end)
return true;
 
ta->sel_start = c_start;
ta->sel_end = c_end;
 
msg.ta = ta;
msg.type = TEXTAREA_MSG_REDRAW_REQUEST;
msg.data.redraw.x0 = 0;
msg.data.redraw.y0 = 0;
msg.data.redraw.x1 = ta->vis_width;
msg.data.redraw.y1 = ta->vis_height;
 
ta->callback(ta->data, &msg);
 
return true;
}
 
 
/**
* Selects a text fragment, relative to current caret position.
*
* \param ta Text area
* \return True on success, false otherwise
*/
static bool textarea_select_fragment(struct textarea * ta)
{
int caret_pos, sel_start = 0, sel_end = 0, index;
size_t b_start, b_end;
 
/* Fragment separators must be suitable for URLs and ordinary text */
static const char *sep = " /:.\r\n";
 
caret_pos = textarea_get_caret(ta);
if (caret_pos < 0) {
return false;
}
 
/* Compute byte offset of caret position */
for (b_start = 0, index = 0; index < caret_pos;
b_start = utf8_next(ta->show->data, ta->show->len,
b_start),
index++) {
/* Cache the character offset of the last separator */
if (strchr(sep, ta->show->data[b_start]) != NULL) {
/* Add one to start to skip over separator */
sel_start = index + 1;
}
}
 
/* Search for next separator, if any */
for (b_end = b_start; b_end < ta->show->len;
b_end = utf8_next(ta->show->data, ta->show->len,
b_end),
index++) {
if (strchr(sep, ta->show->data[b_end]) != NULL) {
sel_end = index;
break;
}
}
 
if (sel_start < sel_end) {
textarea_select(ta, sel_start, sel_end);
return true;
}
 
return false;
}
 
 
/**
* Scrolls a textarea to make the caret visible (doesn't perform a redraw)
*
* \param ta The text area to be scrolled
* \return true if textarea was scrolled false otherwise
*/
static bool textarea_scroll_visible(struct textarea *ta)
{
int x0, x1, y0, y1; /* area we want caret inside */
int xc, yc; /* area centre */
int x, y; /* caret pos */
int xs = ta->scroll_x;
int ys = ta->scroll_y;
bool scrolled = false;
 
if (ta->caret_pos.char_off == -1)
return false;
 
x0 = ta->border_width + ta->pad_left;
x1 = ta->vis_width - (ta->border_width + ta->pad_right);
y0 = 0;
y1 = ta->vis_height - 2 * ta->border_width -
ta->pad_top - ta->pad_bottom;
xc = (x1 - x0) / 2 + x0;
yc = (y1 - y0) / 2 + y0;
 
x = ta->caret_x - xs;
y = ta->caret_y + ta->line_height / 2 - ys;
 
/* horizontal scroll; centre caret */
xs += x - xc;
 
/* force back into range */
if (xs < 0)
xs = 0;
else if (xs > ta->h_extent - (x1 - x0))
xs = ta->h_extent - (x1 - x0);
 
/* If scrolled, set new pos. */
if (xs != ta->scroll_x && ta->bar_x != NULL) {
scrollbar_set(ta->bar_x, xs, false);
xs = scrollbar_get_offset(ta->bar_x);
if (xs != ta->scroll_x) {
ta->scroll_x = xs;
scrolled = true;
}
 
} else if (ta->flags & TEXTAREA_MULTILINE && ta->bar_x == NULL &&
ta->scroll_x != 0) {
ta->scroll_x = 0;
scrolled = true;
 
} else if (xs != ta->scroll_x && !(ta->flags & TEXTAREA_MULTILINE)) {
ta->scroll_x = xs;
scrolled = true;
}
 
/* check and change vertical scroll */
if (ta->flags & TEXTAREA_MULTILINE) {
/* vertical scroll; centre caret */
ys += y - yc;
 
/* force back into range */
if (ys < 0)
ys = 0;
else if (ys > ta->v_extent - (y1 - y0))
ys = ta->v_extent - (y1 - y0);
 
/* If scrolled, set new pos. */
if (ys != ta->scroll_y && ta->bar_y != NULL) {
scrollbar_set(ta->bar_y, ys, false);
ys = scrollbar_get_offset(ta->bar_y);
if (ys != ta->scroll_y) {
ta->scroll_y = ys;
scrolled = true;
}
 
} else if (ta->bar_y == NULL && ta->scroll_y != 0) {
ta->scroll_y = 0;
scrolled = true;
}
}
 
return scrolled;
}
 
 
/**
* Callback for scrollbar widget.
*/
static void textarea_scrollbar_callback(void *client_data,
struct scrollbar_msg_data *scrollbar_data)
{
struct textarea *ta = client_data;
struct textarea_msg msg;
 
switch(scrollbar_data->msg) {
case SCROLLBAR_MSG_MOVED:
/* Scrolled; redraw everything */
ta->scroll_x = scrollbar_get_offset(ta->bar_x);
ta->scroll_y = scrollbar_get_offset(ta->bar_y);
 
msg.ta = ta;
msg.type = TEXTAREA_MSG_REDRAW_REQUEST;
msg.data.redraw.x0 = 0;
msg.data.redraw.y0 = 0;
msg.data.redraw.x1 = ta->vis_width;
msg.data.redraw.y1 = ta->vis_height;
 
ta->callback(ta->data, &msg);
break;
 
case SCROLLBAR_MSG_SCROLL_START:
ta->drag_info.type = TEXTAREA_DRAG_SCROLLBAR;
ta->drag_info.data.scrollbar = scrollbar_data->scrollbar;
 
msg.ta = ta;
msg.type = TEXTAREA_MSG_DRAG_REPORT;
msg.data.drag = ta->drag_info.type;
 
/* Tell client we're handling a drag */
ta->callback(ta->data, &msg);
break;
 
case SCROLLBAR_MSG_SCROLL_FINISHED:
ta->drag_info.type = TEXTAREA_DRAG_NONE;
 
msg.ta = ta;
msg.type = TEXTAREA_MSG_DRAG_REPORT;
msg.data.drag = ta->drag_info.type;
 
/* Tell client we finished handling the drag */
ta->callback(ta->data, &msg);
break;
 
default:
break;
}
}
 
 
 
/**
* Reflow a text area from the given line onwards
*
* \param ta Text area to reflow
* \param start Line number to begin reflow on
* \return true on success false otherwise
*/
static bool textarea_reflow(struct textarea *ta, unsigned int start)
{
char *text;
unsigned int len;
size_t b_off;
int x;
char *space, *para_end;
unsigned int line; /* line count */
unsigned int scroll_lines;
int avail_width;
int h_extent; /* horizontal extent */
int v_extent; /* vertical extent */
bool restart;
 
if (ta->lines == NULL) {
ta->lines =
malloc(LINE_CHUNK_SIZE * sizeof(struct line_info));
if (ta->lines == NULL) {
LOG(("malloc failed"));
return false;
}
}
 
if (!(ta->flags & TEXTAREA_MULTILINE)) {
/* Single line */
int w = ta->vis_width - 2 * ta->border_width -
ta->pad_left - ta->pad_right;
 
if (ta->flags & TEXTAREA_PASSWORD &&
ta->text.utf8_len != ta->password.utf8_len) {
/* Make password-obscured text have same number of
* characters as underlying text */
unsigned int c, b;
int diff = ta->text.utf8_len - ta->password.utf8_len;
unsigned int rep_len = sizeof(PASSWORD_REPLACEMENT) - 1;
unsigned int b_len = ta->text.utf8_len * rep_len + 1;
 
if (diff > 0 && b_len > ta->password.alloc) {
/* Increase password alloaction */
char *temp = realloc(ta->password.data,
b_len + 64);
if (temp == NULL) {
LOG(("realloc failed"));
return false;
}
 
ta->password.data = temp;
ta->password.alloc = b_len + 64;
}
 
b_len--;
for (c = 0; c < b_len; c += rep_len) {
for (b = 0; b < rep_len; b++) {
ta->password.data[c + b] =
PASSWORD_REPLACEMENT[b];
}
}
ta->password.data[b_len] = '\0';
ta->password.len = b_len + 1;
ta->password.utf8_len = ta->text.utf8_len;
}
 
ta->lines[0].b_start = 0;
ta->lines[0].b_length = ta->show->len - 1;
 
nsfont.font_width(&ta->fstyle, ta->show->data,
ta->show->len, &x);
 
if (x > w)
w = x;
 
ta->h_extent = w + ta->pad_left - ta->pad_right;
ta->line_count = 1;
 
return true;
}
 
/* Find max number of lines before vertical scrollbar is required */
scroll_lines = (ta->vis_height - 2 * ta->border_width -
ta->pad_top - ta->pad_bottom) /
ta->line_height;
 
if ((signed)start > ta->line_count)
start = 0;
/** \todo pay attention to start param, for now force start at zero */
start = 0;
 
do {
/* Set line count to start point */
line = start;
 
/* Find available width */
avail_width = ta->vis_width - 2 * ta->border_width -
ta->pad_left - ta->pad_right;
if (avail_width < 0)
avail_width = 0;
h_extent = avail_width;
 
restart = false;
for (len = ta->text.len - 1, text = ta->text.data; len > 0;
len -= b_off, text += b_off) {
 
/* Find end of paragraph */
for (para_end = text; para_end < text + len;
para_end++) {
if (*para_end == '\n')
break;
}
 
/* Wrap current line in paragraph */
nsfont.font_split(&ta->fstyle, text, para_end - text,
avail_width, &b_off, &x);
/* b_off now marks space, or end of paragraph */
 
if (x > h_extent) {
h_extent = x;
}
if (x > avail_width && ta->bar_x == NULL) {
/* We need to insert a horizontal scrollbar */
int w = ta->vis_width - 2 * ta->border_width;
if (!scrollbar_create(true, w, w, w,
ta, textarea_scrollbar_callback,
&(ta->bar_x)))
return false;
if (ta->bar_y != NULL)
scrollbar_make_pair(ta->bar_x,
ta->bar_y);
ta->pad_bottom += SCROLLBAR_WIDTH;
 
/* Find new max visible lines */
scroll_lines = (ta->vis_height -
2 * ta->border_width -
ta->pad_top - ta->pad_bottom) /
ta->line_height;
}
 
if (line > 0 && line % LINE_CHUNK_SIZE == 0) {
struct line_info *temp = realloc(ta->lines,
(line + LINE_CHUNK_SIZE) *
sizeof(struct line_info));
if (temp == NULL) {
LOG(("realloc failed"));
return false;
}
 
ta->lines = temp;
}
 
if (para_end == text + b_off && *para_end == '\n') {
/* Not found any spaces to wrap at, and we
* have a newline char */
ta->lines[line].b_start = text - ta->text.data;
ta->lines[line++].b_length = para_end - text;
 
/* Jump newline */
b_off++;
 
if (len - b_off == 0) {
/* reached end of input;
* add last line */
ta->lines[line].b_start = text +
b_off - ta->text.data;
ta->lines[line++].b_length = 0;
}
 
if (line > scroll_lines && ta->bar_y == NULL)
break;
 
continue;
 
} else if (len - b_off > 0) {
/* soft wraped, find last space (if any) */
for (space = text + b_off; space > text;
space--) {
if (*space == ' ')
break;
}
 
if (space != text)
b_off = space + 1 - text;
}
 
ta->lines[line].b_start = text - ta->text.data;
ta->lines[line++].b_length = b_off;
 
if (line > scroll_lines && ta->bar_y == NULL)
break;
}
 
if (h_extent <= avail_width && ta->bar_x != NULL) {
/* We need to remove a horizontal scrollbar */
scrollbar_destroy(ta->bar_x);
ta->bar_x = NULL;
ta->pad_bottom -= SCROLLBAR_WIDTH;
 
/* Find new max visible lines */
scroll_lines = (ta->vis_height - 2 * ta->border_width -
ta->pad_top - ta->pad_bottom) /
ta->line_height;
}
 
if (line > scroll_lines && ta->bar_y == NULL) {
/* Add vertical scrollbar */
int h = ta->vis_height - 2 * ta->border_width;
if (!scrollbar_create(false, h, h, h,
ta, textarea_scrollbar_callback,
&(ta->bar_y)))
return false;
if (ta->bar_x != NULL)
scrollbar_make_pair(ta->bar_x,
ta->bar_y);
ta->pad_right += SCROLLBAR_WIDTH;
restart = true;
 
} else if (line <= scroll_lines && ta->bar_y != NULL) {
/* Remove vertical scrollbar */
scrollbar_destroy(ta->bar_y);
ta->bar_y = NULL;
ta->pad_right -= SCROLLBAR_WIDTH;
restart = true;
}
} while (restart);
 
h_extent += ta->pad_left + ta->pad_right -
(ta->bar_y != NULL ? SCROLLBAR_WIDTH : 0);
v_extent = line * ta->line_height + ta->pad_top +
ta->pad_bottom -
(ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0);
 
if (ta->bar_x != NULL) {
/* Set horizontal scrollbar extents */
int w = ta->vis_width - 2 * ta->border_width -
(ta->bar_y != NULL ? SCROLLBAR_WIDTH : 0);
scrollbar_set_extents(ta->bar_x, w, w, h_extent);
}
 
if (ta->bar_y != NULL) {
/* Set vertical scrollbar extents */
int h = ta->vis_height - 2 * ta->border_width;
scrollbar_set_extents(ta->bar_y, h,
h - (ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0),
v_extent);
}
 
ta->h_extent = h_extent;
ta->v_extent = v_extent;
ta->line_count = line;
 
return true;
}
 
 
/**
* get byte/character offset from the beginning of the text for some coordinates
*
* \param ta Text area
* \param x X coordinate
* \param y Y coordinate
* \param b_off Updated to byte offset
* \param c_off Updated to character offset
*/
static void textarea_get_xy_offset(struct textarea *ta, int x, int y,
unsigned int *c_off)
{
size_t bpos, temp; /* Byte positions in utf8 string */
unsigned int cpos; /* Character positions in utf8 string */
int line;
 
if (!ta->line_count) {
*c_off = 0;
return;
}
 
x = x - ta->border_width - ta->pad_left + ta->scroll_x;
y = y - ta->border_width - ta->pad_top + ta->scroll_y;
 
if (x < 0)
x = 0;
 
line = y / ta->line_height;
 
if (line < 0)
line = 0;
if (ta->line_count - 1 < line)
line = ta->line_count - 1;
 
/* Get byte position */
nsfont.font_position_in_string(&ta->fstyle,
ta->show->data + ta->lines[line].b_start,
ta->lines[line].b_length, x, &bpos, &x);
 
 
/* If the calculated byte offset corresponds with the number of bytes
* in the line, and the line has been soft-wrapped, then ensure the
* caret offset is before the trailing space character, rather than
* after it. Otherwise, the caret will be placed at the start of the
* following line, which is undesirable.
*/
if (ta->flags & TEXTAREA_MULTILINE &&
bpos == (unsigned)ta->lines[line].b_length &&
ta->show->data[ta->lines[line].b_start +
ta->lines[line].b_length - 1] == ' ')
bpos--;
 
/* Get character position */
for (temp = 0, cpos = 0; temp < bpos + ta->lines[line].b_start;
temp = utf8_next(ta->show->data, ta->show->len, temp))
cpos++;
 
/* Set the return values */
*c_off = cpos;
}
 
 
/**
* Set the caret's position
*
* \param ta Text area
* \param x X position of caret in a window relative to text area top left
* \param y Y position of caret in a window relative to text area top left
* \return true on success false otherwise
*/
static bool textarea_set_caret_xy(struct textarea *ta, int x, int y)
{
unsigned int c_off;
 
if (ta->flags & TEXTAREA_READONLY)
return true;
 
textarea_get_xy_offset(ta, x, y, &c_off);
 
return textarea_set_caret(ta, c_off);
}
 
 
/**
* Insert text into the text area
*
* \param ta Text area
* \param c_index 0-based character index to insert at
* \param text UTF-8 text to insert
* \param b_len Byte length of UTF-8 text
* \return false on memory exhaustion, true otherwise
*/
static bool textarea_insert_text(struct textarea *ta, unsigned int c_index,
const char *text, size_t b_len)
{
size_t b_off;
 
if (ta->flags & TEXTAREA_READONLY)
return true;
 
/* Find insertion point */
if (c_index > ta->text.utf8_len)
c_index = ta->text.utf8_len;
 
/* find byte offset of insertion point */
for (b_off = 0; c_index > 0;
b_off = utf8_next(ta->text.data, ta->text.len, b_off))
c_index--;
 
if (b_len + ta->text.len >= ta->text.alloc) {
char *temp = realloc(ta->text.data, b_len + ta->text.len + 64);
if (temp == NULL) {
LOG(("realloc failed"));
return false;
}
 
ta->text.data = temp;
ta->text.alloc = b_len + ta->text.len + 64;
}
 
/* Shift text following up */
memmove(ta->text.data + b_off + b_len, ta->text.data + b_off,
ta->text.len - b_off);
/* Insert new text */
memcpy(ta->text.data + b_off, text, b_len);
ta->text.len += b_len;
ta->text.utf8_len += utf8_bounded_length(text, b_len);
 
textarea_normalise_text(ta, b_off, b_len);
 
/** \todo calculate line to reflow from */
return textarea_reflow(ta, 0);
 
}
 
 
static inline void textarea_char_to_byte_offset(struct textarea_utf8 *text,
unsigned int start, unsigned int end,
size_t *b_start, size_t *b_end)
{
size_t diff = end - start;
/* find byte offset of replace start */
for (*b_start = 0; start-- > 0;
*b_start = utf8_next(text->data, text->len, *b_start))
; /* do nothing */
 
/* find byte length of replaced text */
for (*b_end = *b_start; diff-- > 0;
*b_end = utf8_next(text->data, text->len, *b_end))
; /* do nothing */
}
 
 
/**
* Replace text in a text area
*
* \param ta Text area
* \param start Start character index of replaced section (inclusive)
* \param end End character index of replaced section (exclusive)
* \param rep Replacement UTF-8 text to insert
* \param rep_len Byte length of replacement UTF-8 text
* \param add_to_clipboard True iff replaced text to be added to clipboard
* \return false on memory exhaustion, true otherwise
*/
static bool textarea_replace_text(struct textarea *ta, unsigned int start,
unsigned int end, const char *rep, size_t rep_len,
bool add_to_clipboard)
{
size_t b_start, b_end;
 
if (ta->flags & TEXTAREA_READONLY)
return true;
 
if (start > ta->text.utf8_len)
start = ta->text.utf8_len;
if (end > ta->text.utf8_len)
end = ta->text.utf8_len;
 
if (start == end && rep != NULL)
return textarea_insert_text(ta, start, rep, rep_len);
 
if (start > end)
return false;
 
/* Place CUTs on clipboard */
if (add_to_clipboard) {
textarea_char_to_byte_offset(ta->show, start, end,
&b_start, &b_end);
gui_set_clipboard(ta->show->data + b_start, b_end - b_start,
NULL, 0);
}
 
textarea_char_to_byte_offset(&ta->text, start, end, &b_start, &b_end);
 
if (rep == NULL) {
/* No replacement text */
return true;
}
 
/* Ensure textarea's text buffer is large enough */
if (rep_len + ta->text.len - (b_end - b_start) >= ta->text.alloc) {
char *temp = realloc(ta->text.data,
rep_len + ta->text.len - (b_end - b_start) + 64);
if (temp == NULL) {
LOG(("realloc failed"));
return false;
}
 
ta->text.data = temp;
ta->text.alloc =
rep_len + ta->text.len - (b_end - b_start) + 64;
}
 
/* Shift text following to new position */
memmove(ta->text.data + b_start + rep_len, ta->text.data + b_end,
ta->text.len - b_end);
 
/* Insert new text */
memcpy(ta->text.data + b_start, rep, rep_len);
 
ta->text.len += (int)rep_len - (b_end - b_start);
ta->text.utf8_len = utf8_length(ta->text.data);
textarea_normalise_text(ta, b_start, rep_len);
 
/** \todo calculate line to reflow from */
return textarea_reflow(ta, 0);
}
 
 
/**
* Handles the end of a drag operation
*
* \param ta Text area
* \param mouse the mouse state at drag end moment
* \param x X coordinate
* \param y Y coordinate
* \return true if drag end was handled false otherwise
*/
static bool textarea_drag_end(struct textarea *ta, browser_mouse_state mouse,
int x, int y)
{
int c_end;
unsigned int c_off;
struct textarea_msg msg;
 
assert(ta->drag_info.type != TEXTAREA_DRAG_NONE);
 
switch (ta->drag_info.type) {
case TEXTAREA_DRAG_SCROLLBAR:
if (ta->drag_info.data.scrollbar == ta->bar_x) {
x -= ta->border_width;
y -= ta->vis_height - ta->border_width -
SCROLLBAR_WIDTH;
} else {
x -= ta->vis_width - ta->border_width -
SCROLLBAR_WIDTH;
y -= ta->border_width;
}
scrollbar_mouse_drag_end(ta->drag_info.data.scrollbar,
mouse, x, y);
assert(ta->drag_info.type == TEXTAREA_DRAG_NONE);
 
/* Return, since drag end already reported to textarea client */
return true;
 
case TEXTAREA_DRAG_SELECTION:
ta->drag_info.type = TEXTAREA_DRAG_NONE;
 
textarea_get_xy_offset(ta, x, y, &c_off);
c_end = c_off;
 
if (!textarea_select(ta, ta->drag_start_char, c_end))
return false;
 
break;
 
default:
return false;
}
 
/* Report drag end to client, if not already reported */
assert(ta->drag_info.type == TEXTAREA_DRAG_NONE);
 
msg.ta = ta;
msg.type = TEXTAREA_MSG_DRAG_REPORT;
msg.data.drag = ta->drag_info.type;
 
ta->callback(ta->data, &msg);
 
return true;
}
 
 
 
 
/* exported interface, documented in textarea.h */
struct textarea *textarea_create(const textarea_setup *setup,
textarea_client_callback callback, void *data)
{
struct textarea *ret;
 
/* Sanity check flags */
assert(!(setup->flags & TEXTAREA_MULTILINE &&
setup->flags & TEXTAREA_PASSWORD));
 
if (callback == NULL) {
LOG(("no callback provided"));
return NULL;
}
 
ret = malloc(sizeof(struct textarea));
if (ret == NULL) {
LOG(("malloc failed"));
return NULL;
}
 
ret->callback = callback;
ret->data = data;
 
ret->flags = setup->flags;
ret->vis_width = setup->width;
ret->vis_height = setup->height;
 
ret->pad_top = setup->pad_top;
ret->pad_right = setup->pad_right;
ret->pad_bottom = setup->pad_bottom;
ret->pad_left = setup->pad_left;
 
ret->border_width = setup->border_width;
ret->border_col = setup->border_col;
 
ret->fstyle = setup->text;
 
ret->sel_fstyle = setup->text;
ret->sel_fstyle.foreground = setup->selected_text;
ret->sel_fstyle.background = setup->selected_bg;
 
ret->scroll_x = 0;
ret->scroll_y = 0;
ret->bar_x = NULL;
ret->bar_y = NULL;
ret->drag_start_char = 0;
ret->drag_info.type = TEXTAREA_DRAG_NONE;
 
 
ret->text.data = malloc(64);
if (ret->text.data == NULL) {
LOG(("malloc failed"));
free(ret);
return NULL;
}
ret->text.data[0] = '\0';
ret->text.alloc = 64;
ret->text.len = 1;
ret->text.utf8_len = 0;
 
if (setup->flags & TEXTAREA_PASSWORD) {
ret->password.data = malloc(64);
if (ret->password.data == NULL) {
LOG(("malloc failed"));
free(ret->text.data);
free(ret);
return NULL;
}
ret->password.data[0] = '\0';
ret->password.alloc = 64;
ret->password.len = 1;
ret->password.utf8_len = 0;
 
ret->show = &ret->password;
 
} else {
ret->password.data = NULL;
ret->password.alloc = 0;
ret->password.len = 0;
ret->password.utf8_len = 0;
 
ret->show = &ret->text;
}
 
ret->line_height = FIXTOINT(FDIV((FMUL(FLTTOFIX(1.2),
FMUL(nscss_screen_dpi,
INTTOFIX((setup->text.size /
FONT_SIZE_SCALE))))), F_72));
 
ret->caret_pos.line = ret->caret_pos.char_off = -1;
ret->caret_x = 0;
ret->caret_y = 0;
ret->sel_start = -1;
ret->sel_end = -1;
 
ret->line_count = 0;
ret->lines = NULL;
 
return ret;
}
 
 
/* exported interface, documented in textarea.h */
void textarea_destroy(struct textarea *ta)
{
if (ta->bar_x)
scrollbar_destroy(ta->bar_x);
if (ta->bar_y)
scrollbar_destroy(ta->bar_y);
 
if (ta->flags & TEXTAREA_PASSWORD)
free(ta->password.data);
 
free(ta->text.data);
free(ta->lines);
free(ta);
}
 
 
/* exported interface, documented in textarea.h */
bool textarea_set_text(struct textarea *ta, const char *text)
{
unsigned int len = strlen(text) + 1;
 
if (len >= ta->text.alloc) {
char *temp = realloc(ta->text.data, len + 64);
if (temp == NULL) {
LOG(("realloc failed"));
return false;
}
ta->text.data = temp;
ta->text.alloc = len + 64;
}
 
memcpy(ta->text.data, text, len);
ta->text.len = len;
ta->text.utf8_len = utf8_length(ta->text.data);
 
textarea_normalise_text(ta, 0, len);
 
return textarea_reflow(ta, 0);
}
 
 
/* exported interface, documented in textarea.h */
int textarea_get_text(struct textarea *ta, char *buf, unsigned int len)
{
if (buf == NULL && len == 0) {
/* want length */
return ta->text.len;
 
} else if (buf == NULL) {
/* Can't write to NULL */
return -1;
}
 
if (len < ta->text.len) {
LOG(("buffer too small"));
return -1;
}
 
memcpy(buf, ta->text.data, ta->text.len);
 
return ta->text.len;
}
 
 
/* exported interface, documented in textarea.h */
bool textarea_set_caret(struct textarea *ta, int caret)
{
unsigned int c_len;
unsigned int b_off;
int i;
int index;
int x, y;
int x0, y0, x1, y1;
int text_y_offset;
int width, height;
struct textarea_msg msg;
 
if (ta->flags & TEXTAREA_READONLY)
return true;
 
c_len = ta->show->utf8_len;
 
if (caret != -1 && caret > (signed)c_len)
caret = c_len;
 
if (ta->flags & TEXTAREA_MULTILINE) {
/* Multiline textarea */
text_y_offset = ta->border_width + ta->pad_top;
} else {
/* Single line text area; text is vertically centered */
text_y_offset = ta->border_width;
text_y_offset += (ta->vis_height - ta->line_height + 1) / 2;
}
 
/* Delete the old caret */
if (ta->caret_pos.char_off != -1) {
x0 = ta->caret_x - ta->scroll_x;
y0 = ta->caret_y + text_y_offset - ta->scroll_y;
width = 2;
height = ta->line_height;
 
msg.ta = ta;
msg.type = TEXTAREA_MSG_REDRAW_REQUEST;
msg.data.redraw.x0 = x0;
msg.data.redraw.y0 = y0;
msg.data.redraw.x1 = x0 + width;
msg.data.redraw.y1 = y0 + height;
 
ta->callback(ta->data, &msg);
}
 
/* check if the caret has to be drawn at all */
if (caret != -1) {
/* Find byte offset of caret position */
for (b_off = 0; caret > 0; caret--)
b_off = utf8_next(ta->show->data, ta->show->len, b_off);
 
/* Now find line in which byte offset appears */
for (i = 0; i < ta->line_count - 1; i++)
if (ta->lines[i + 1].b_start > b_off)
break;
 
ta->caret_pos.line = i;
 
/* Now calculate the char. offset of the caret in this line */
for (c_len = 0, ta->caret_pos.char_off = 0;
c_len < b_off - ta->lines[i].b_start;
c_len = utf8_next(ta->show->data +
ta->lines[i].b_start,
ta->lines[i].b_length, c_len))
ta->caret_pos.char_off++;
 
/* Finally, redraw the caret */
index = textarea_get_caret(ta);
if (index == -1)
return false;
 
/* find byte offset of caret position */
for (b_off = 0; index-- > 0;
b_off = utf8_next(ta->show->data,
ta->show->len, b_off))
; /* do nothing */
 
nsfont.font_width(&ta->fstyle,
ta->show->data +
ta->lines[ta->caret_pos.line].b_start,
b_off - ta->lines[ta->caret_pos.line].b_start,
&x);
 
x += ta->border_width + ta->pad_left;
ta->caret_x = x;
y = ta->line_height * ta->caret_pos.line;
ta->caret_y = y;
 
if (!textarea_scroll_visible(ta)) {
/* No scroll, just caret moved, redraw it */
x -= ta->scroll_x;
y -= ta->scroll_y;
x0 = max(x - 1, ta->border_width);
y0 = max(y + text_y_offset, 0);
x1 = min(x + 1, ta->vis_width - ta->border_width);
y1 = min(y + ta->line_height + text_y_offset,
ta->vis_height);
 
width = x1 - x0;
height = y1 - y0;
 
if (width > 0 && height > 0) {
msg.ta = ta;
msg.type = TEXTAREA_MSG_REDRAW_REQUEST;
msg.data.redraw.x0 = x0;
msg.data.redraw.y0 = y0;
msg.data.redraw.x1 = x0 + width;
msg.data.redraw.y1 = y0 + height;
 
ta->callback(ta->data, &msg);
}
}
}
 
return true;
}
 
 
/* exported interface, documented in textarea.h */
int textarea_get_caret(struct textarea *ta)
{
unsigned int c_off = 0, b_off;
 
/* Ensure caret isn't hidden */
if (ta->caret_pos.char_off < 0)
textarea_set_caret(ta, 0);
 
/* if the text is a trailing NUL only */
if (ta->text.utf8_len == 0)
return 0;
 
/* Calculate character offset of this line's start */
for (b_off = 0; b_off < ta->lines[ta->caret_pos.line].b_start;
b_off = utf8_next(ta->text.data, ta->text.len, b_off))
c_off++;
 
return c_off + ta->caret_pos.char_off;
}
 
 
/* exported interface, documented in textarea.h */
void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
const struct rect *clip, const struct redraw_context *ctx)
{
struct textarea_msg msg;
const struct plotter_table *plot = ctx->plot;
int line0, line1, line, left, right;
int chars, text_y_offset, text_y_offset_baseline;
unsigned int c_pos, c_len, c_len_part, b_start, b_end, line_len;
unsigned int sel_start, sel_end;
char *line_text;
struct rect r, s;
bool selected = false;
plot_font_style_t *fstyle;
plot_style_t plot_style_fill_bg = {
.stroke_type = PLOT_OP_TYPE_NONE,
.stroke_width = 0,
.stroke_colour = NS_TRANSPARENT,
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = ta->border_col
};
 
r = *clip;
 
if (r.x1 < x || r.x0 > x + ta->vis_width || r.y1 < y ||
r.y0 > y + ta->vis_height)
/* Textarea outside the clipping rectangle */
return;
 
if (ta->lines == NULL)
/* Nothing to redraw */
return;
 
line0 = (r.y0 - y + ta->scroll_y) / ta->line_height - 1;
line1 = (r.y1 - y + ta->scroll_y) / ta->line_height + 1;
 
if (line0 < 0)
line0 = 0;
if (line1 < 0)
line1 = 0;
if (ta->line_count - 1 < line0)
line0 = ta->line_count - 1;
if (ta->line_count - 1 < line1)
line1 = ta->line_count - 1;
if (line1 < line0)
line1 = line0;
 
if (r.x0 < x)
r.x0 = x;
if (r.y0 < y)
r.y0 = y;
if (r.x1 > x + ta->vis_width)
r.x1 = x + ta->vis_width;
if (r.y1 > y + ta->vis_height)
r.y1 = y + ta->vis_height;
 
plot->clip(&r);
if (ta->border_col != NS_TRANSPARENT &&
ta->border_width > 0) {
/* Plot border */
plot->rectangle(x, y, x + ta->vis_width, y + ta->vis_height,
&plot_style_fill_bg);
}
if (ta->fstyle.background != NS_TRANSPARENT) {
/* Plot background */
plot_style_fill_bg.fill_colour = ta->fstyle.background;
plot->rectangle(x + ta->border_width, y + ta->border_width,
x + ta->vis_width - ta->border_width,
y + ta->vis_height - ta->border_width,
&plot_style_fill_bg);
}
 
if (r.x0 < x + ta->border_width)
r.x0 = x + ta->border_width;
if (r.x1 > x + ta->vis_width - ta->border_width)
r.x1 = x + ta->vis_width - ta->border_width;
if (r.y0 < y + ta->border_width)
r.y0 = y + ta->border_width;
if (r.y1 > y + ta->vis_height - ta->border_width -
(ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0))
r.y1 = y + ta->vis_height - ta->border_width -
(ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0);
 
if (line0 > 0)
c_pos = utf8_bounded_length(ta->show->data,
ta->lines[line0].b_start);
else
c_pos = 0;
 
text_y_offset = text_y_offset_baseline = ta->border_width;
if (ta->flags & TEXTAREA_MULTILINE) {
/* Multiline textarea */
text_y_offset += ta->pad_top;
text_y_offset_baseline += (ta->line_height * 3 + 2) / 4 +
ta->pad_top;
} else {
/* Single line text area; text is vertically centered */
int vis_height = ta->vis_height - 2 * ta->border_width;
text_y_offset += (vis_height - ta->line_height + 1) / 2;
text_y_offset_baseline += (vis_height * 3 + 2) / 4;
}
 
plot_style_fill_bg.fill_colour = ta->sel_fstyle.background;
 
for (line = line0; (line <= line1) &&
(y + line * ta->line_height <= r.y1 + ta->scroll_y);
line++) {
if (ta->lines[line].b_length == 0)
continue;
 
/* reset clip rectangle */
plot->clip(&r);
 
c_len = utf8_bounded_length(
&(ta->show->data[ta->lines[line].b_start]),
ta->lines[line].b_length);
 
b_end = 0;
right = x + ta->border_width + ta->pad_left - ta->scroll_x;
 
do {
sel_start = ta->sel_start;
sel_end = ta->sel_end;
/* get length of part of line */
if (ta->sel_end == -1 || ta->sel_end == ta->sel_start ||
sel_end <= c_pos ||
sel_start > c_pos + c_len) {
/* rest of line unselected */
selected = false;
c_len_part = c_len;
fstyle = &ta->fstyle;
 
} else if (sel_start <= c_pos &&
sel_end > c_pos + c_len) {
/* rest of line selected */
selected = true;
c_len_part = c_len;
fstyle = &ta->sel_fstyle;
 
} else if (sel_start > c_pos) {
/* next part of line unselected */
selected = false;
c_len_part = sel_start - c_pos;
fstyle = &ta->fstyle;
 
} else if (sel_end > c_pos) {
/* next part of line selected */
selected = true;
c_len_part = sel_end - c_pos;
fstyle = &ta->sel_fstyle;
 
} else {
assert(0);
}
 
line_text = &(ta->show->data[ta->lines[line].b_start]);
line_len = ta->lines[line].b_length;
 
/* find b_start and b_end for this part of the line */
b_start = b_end;
 
chars = c_len_part;
for (b_end = b_start; chars > 0; chars--)
b_end = utf8_next(line_text, line_len, b_end);
 
/* find clip left/right for this part of line */
left = right;
nsfont.font_width(&ta->fstyle, line_text,
b_end, &right);
right += x + ta->border_width + ta->pad_left -
ta->scroll_x;
 
/* set clip rectangle for line part */
s = r;
if (s.x0 < left)
s.x0 = left;
if (s.x1 > right)
s.x1 = right;
plot->clip(&s);
 
if (selected) {
/* draw selection fill */
plot->rectangle(s.x0,
y + line * ta->line_height + 1 -
ta->scroll_y + text_y_offset,
s.x1,
y + (line + 1) * ta->line_height + 1 -
ta->scroll_y + text_y_offset,
&plot_style_fill_bg);
}
 
/* draw text */
plot->text(x + ta->border_width + ta->pad_left -
ta->scroll_x,
y + line * ta->line_height +
text_y_offset_baseline - ta->scroll_y,
ta->show->data +
ta->lines[line].b_start,
ta->lines[line].b_length, fstyle);
 
c_pos += c_len_part;
c_len -= c_len_part;
 
} while (c_pos < c_pos + c_len);
 
/* if there is a newline between the lines, skip it */
if (line < ta->line_count - 1 &&
ta->lines[line + 1].b_start !=
ta->lines[line].b_start +
ta->lines[line].b_length)
c_pos++;
}
 
plot->clip(clip);
 
if ((ta->sel_end == -1 || ta->sel_start == ta->sel_end) &&
ta->caret_pos.char_off >= 0) {
/* There is no selection, and caret visible: show caret */
int caret_y = y - ta->scroll_y + ta->caret_y + text_y_offset;
 
if (ta->flags & TEXTAREA_INTERNAL_CARET) {
/* Render our own caret */
plot->line(x - ta->scroll_x + ta->caret_x, caret_y,
x - ta->scroll_x + ta->caret_x,
caret_y + ta->line_height,
&pstyle_stroke_caret);
} else {
/* Tell client where caret should be placed */
msg.ta = ta;
msg.type = TEXTAREA_MSG_MOVED_CARET;
msg.data.caret.hidden = false;
msg.data.caret.x = x - ta->scroll_x + ta->caret_x;
msg.data.caret.y = caret_y;
msg.data.caret.height = ta->line_height;
 
ta->callback(ta->data, &msg);
}
} else if (!(ta->flags & TEXTAREA_INTERNAL_CARET)) {
/* Caret hidden, and client is responsible: tell client */
msg.ta = ta;
msg.type = TEXTAREA_MSG_MOVED_CARET;
msg.data.caret.hidden = true;
 
ta->callback(ta->data, &msg);
}
 
if (ta->bar_x != NULL)
scrollbar_redraw(ta->bar_x,
x + ta->border_width,
y + ta->vis_height - ta->border_width -
SCROLLBAR_WIDTH,
clip, 1.0, ctx);
 
if (ta->bar_y != NULL)
scrollbar_redraw(ta->bar_y,
x + ta->vis_width - ta->border_width -
SCROLLBAR_WIDTH,
y + ta->border_width,
clip, 1.0, ctx);
}
 
 
/* exported interface, documented in textarea.h */
bool textarea_keypress(struct textarea *ta, uint32_t key)
{
struct textarea_msg msg;
char utf8[6];
unsigned int caret, caret_init, length, l_len, b_off, b_len;
int c_line, c_chars, line;
bool redraw = false;
bool readonly;
 
caret_init = caret = textarea_get_caret(ta);
line = ta->caret_pos.line;
readonly = (ta->flags & TEXTAREA_READONLY ? true : false);
 
if (!(key <= 0x001F || (0x007F <= key && key <= 0x009F))) {
/* normal character insertion */
length = utf8_from_ucs4(key, utf8);
utf8[length] = '\0';
 
if (ta->sel_start != -1) {
if (!textarea_replace_text(ta,
ta->sel_start,
ta->sel_end, utf8, length, false))
return false;
 
caret = ta->sel_start + 1;
ta->sel_start = ta->sel_end = -1;
redraw = true;
} else {
if (!textarea_replace_text(ta,
caret, caret,
utf8, length, false))
return false;
caret++;
redraw = true;
}
 
} else switch (key) {
case KEY_SELECT_ALL:
caret = ta->text.utf8_len;
 
ta->sel_start = 0;
ta->sel_end = ta->text.utf8_len;
redraw = true;
break;
case KEY_COPY_SELECTION:
if (ta->sel_start != -1) {
if (!textarea_replace_text(ta,
ta->sel_start,
ta->sel_end,
NULL, 0, true))
return false;
}
break;
case KEY_DELETE_LEFT:
if (readonly)
break;
if (ta->sel_start != -1) {
if (!textarea_replace_text(ta,
ta->sel_start,
ta->sel_end, "", 0, false))
return false;
 
caret = ta->sel_start;
ta->sel_start = ta->sel_end = -1;
redraw = true;
} else if (caret > 0) {
if (!textarea_replace_text(ta,
caret - 1,
caret, "", 0, false))
return false;
caret--;
redraw = true;
}
break;
case KEY_NL:
if (readonly)
break;
if(!textarea_insert_text(ta, caret, "\n", 1))
return false;
caret++;
ta->sel_start = ta->sel_end = -1;
redraw = true;
break;
case KEY_CUT_LINE:
break;
case KEY_PASTE:
{
char *clipboard;
size_t clipboard_length;
size_t clipboard_chars;
 
if (readonly)
break;
 
gui_get_clipboard(&clipboard, &clipboard_length);
if (clipboard == NULL)
return false;
clipboard_chars = utf8_bounded_length(clipboard,
clipboard_length);
 
if (ta->sel_start != -1) {
if (!textarea_replace_text(ta,
ta->sel_start, ta->sel_end,
clipboard, clipboard_length,
false))
return false;
 
caret = ta->sel_start + clipboard_chars;
ta->sel_start = ta->sel_end = -1;
redraw = true;
} else {
if (!textarea_replace_text(ta,
caret, caret,
clipboard, clipboard_length,
false))
return false;
caret += clipboard_chars;
redraw = true;
}
 
free(clipboard);
}
break;
case KEY_CUT_SELECTION:
if (readonly)
break;
if (ta->sel_start != -1) {
if (!textarea_replace_text(ta,
ta->sel_start,
ta->sel_end, "", 0, true))
return false;
 
caret = ta->sel_start;
ta->sel_start = ta->sel_end = -1;
redraw = true;
}
break;
case KEY_ESCAPE:
/* Fall through to KEY_CLEAR_SELECTION */
case KEY_CLEAR_SELECTION:
ta->sel_start = -1;
ta->sel_end = -1;
redraw = true;
break;
case KEY_LEFT:
if (readonly)
break;
if (caret > 0)
caret--;
if (ta->sel_start != -1) {
ta->sel_start = ta->sel_end = -1;
redraw = true;
}
break;
case KEY_RIGHT:
if (readonly)
break;
if (caret < ta->text.utf8_len)
caret++;
if (ta->sel_start != -1) {
ta->sel_start = ta->sel_end = -1;
redraw = true;
}
break;
case KEY_PAGE_UP:
if (readonly)
break;
if (ta->flags & TEXTAREA_MULTILINE) {
/* +1 because one line is subtracted in
KEY_UP */
line = ta->caret_pos.line - (ta->vis_height +
ta->line_height - 1) /
ta->line_height + 1;
}
/* fall through */
case KEY_UP:
if (readonly)
break;
if (ta->sel_start != -1) {
ta->sel_start = ta->sel_end = -1;
redraw = true;
}
if (ta->flags & TEXTAREA_MULTILINE) {
line--;
if (line < 0)
line = 0;
if (line == ta->caret_pos.line)
break;
 
b_off = ta->lines[line].b_start;
b_len = ta->lines[line].b_length;
 
c_line = ta->caret_pos.line;
c_chars = ta->caret_pos.char_off;
 
if (ta->text.data[b_off + b_len - 1] == ' '
&& line < ta->line_count - 1)
b_len--;
 
l_len = utf8_bounded_length(
&(ta->text.data[b_off]),
b_len);
 
 
ta->caret_pos.line = line;
ta->caret_pos.char_off = min(l_len,
(unsigned)
ta->caret_pos.char_off);
 
caret = textarea_get_caret(ta);
 
ta->caret_pos.line = c_line;
ta->caret_pos.char_off = c_chars;
}
break;
case KEY_PAGE_DOWN:
if (readonly)
break;
if (ta->flags & TEXTAREA_MULTILINE) {
/* -1 because one line is added in KEY_DOWN */
line = ta->caret_pos.line + (ta->vis_height +
ta->line_height - 1) /
ta->line_height
- 1;
}
/* fall through */
case KEY_DOWN:
if (readonly)
break;
if (ta->sel_start != -1) {
ta->sel_start = ta->sel_end = -1;
redraw = true;
}
if (ta->flags & TEXTAREA_MULTILINE) {
line++;
if (line > ta->line_count - 1)
line = ta->line_count - 1;
if (line == ta->caret_pos.line)
break;
 
b_off = ta->lines[line].b_start;
b_len = ta->lines[line].b_length;
 
c_line = ta->caret_pos.line;
c_chars = ta->caret_pos.char_off;
 
if (ta->text.data[b_off + b_len - 1] == ' '
&& line < ta->line_count - 1)
b_len--;
 
l_len = utf8_bounded_length(
&(ta->text.data[b_off]),
b_len);
 
 
ta->caret_pos.line = line;
ta->caret_pos.char_off = min(l_len,
(unsigned)
ta->caret_pos.char_off);
 
caret = textarea_get_caret(ta);
 
ta->caret_pos.line = c_line;
ta->caret_pos.char_off = c_chars;
}
break;
case KEY_DELETE_RIGHT:
if (readonly)
break;
if (ta->sel_start != -1) {
if (!textarea_replace_text(ta,
ta->sel_start,
ta->sel_end, "", 0, false))
return false;
 
caret = ta->sel_start;
ta->sel_start = ta->sel_end = -1;
redraw = true;
} else {
if (caret < ta->text.utf8_len) {
if (!textarea_replace_text(ta,
caret, caret + 1,
"", 0, false))
return false;
redraw = true;
}
}
break;
case KEY_LINE_START:
if (readonly)
break;
caret -= ta->caret_pos.char_off;
if (ta->sel_start != -1) {
ta->sel_start = ta->sel_end = -1;
redraw = true;
}
break;
case KEY_LINE_END:
if (readonly)
break;
 
caret = utf8_bounded_length(ta->text.data,
ta->lines[ta->caret_pos.line].b_start +
ta->lines[ta->caret_pos.line].b_length);
if (ta->text.data[ta->lines[ta->caret_pos.line].
b_start +
ta->lines[ta->caret_pos.line].b_length
- 1] == ' ')
caret--;
if (ta->sel_start != -1) {
ta->sel_start = ta->sel_end = -1;
redraw = true;
}
break;
case KEY_TEXT_START:
if (readonly)
break;
caret = 0;
if (ta->sel_start != -1) {
ta->sel_start = ta->sel_end = -1;
redraw = true;
}
break;
case KEY_TEXT_END:
if (readonly)
break;
caret = ta->text.utf8_len;
if (ta->sel_start != -1) {
ta->sel_start = ta->sel_end = -1;
redraw = true;
}
break;
case KEY_WORD_LEFT:
case KEY_WORD_RIGHT:
break;
case KEY_DELETE_LINE_END:
if (readonly)
break;
if (ta->sel_start != -1) {
if (!textarea_replace_text(ta,
ta->sel_start,
ta->sel_end, "", 0, false))
return false;
ta->sel_start = ta->sel_end = -1;
} else {
b_off = ta->lines[ta->caret_pos.line].b_start;
b_len = ta->lines[ta->caret_pos.line].b_length;
l_len = utf8_bounded_length(
&(ta->text.data[b_off]),
b_len);
if (!textarea_replace_text(ta, caret,
caret + l_len, "", 0, false))
return false;
}
redraw = true;
break;
case KEY_DELETE_LINE_START:
if (readonly)
break;
if (ta->sel_start != -1) {
if (!textarea_replace_text(ta,
ta->sel_start,
ta->sel_end, "", 0, false))
return false;
ta->sel_start = ta->sel_end = -1;
} else {
if (!textarea_replace_text(ta,
caret - ta->caret_pos.char_off,
caret, "", 0, false))
return false;
caret -= ta->caret_pos.char_off;
}
redraw = true;
break;
default:
return false;
}
 
 
if (caret != caret_init)
textarea_set_caret(ta, caret);
//TODO:redraw only the important part
if (redraw) {
msg.ta = ta;
msg.type = TEXTAREA_MSG_REDRAW_REQUEST;
msg.data.redraw.x0 = 0;
msg.data.redraw.y0 = 0;
msg.data.redraw.x1 = ta->vis_width;
msg.data.redraw.y1 = ta->vis_height;
 
ta->callback(ta->data, &msg);
}
 
return true;
}
 
 
/* exported interface, documented in textarea.h */
bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse,
int x, int y)
{
int c_start, c_end;
int sx, sy; /* xy coord offset for scrollbar */
int sl; /* scrollbar length */
unsigned int c_off;
struct textarea_msg msg;
 
if (ta->drag_info.type != TEXTAREA_DRAG_NONE &&
mouse == BROWSER_MOUSE_HOVER) {
/* There is a drag that we must end */
textarea_drag_end(ta, mouse, x, y);
}
 
if (ta->drag_info.type == TEXTAREA_DRAG_SCROLLBAR) {
/* Scrollbar drag in progress; pass input to scrollbar */
if (ta->drag_info.data.scrollbar == ta->bar_x) {
x -= ta->border_width;
y -= ta->vis_height - ta->border_width -
SCROLLBAR_WIDTH;
} else {
x -= ta->vis_width - ta->border_width -
SCROLLBAR_WIDTH;
y -= ta->border_width;
}
scrollbar_mouse_action(ta->drag_info.data.scrollbar,
mouse, x, y);
return true;
}
 
/* Horizontal scrollbar */
if (ta->bar_x != NULL && ta->drag_info.type == TEXTAREA_DRAG_NONE) {
/* No drag happening, but mouse input is over scrollbar;
* pass input to scrollbar */
sx = x - ta->border_width;
sy = y - (ta->vis_height - ta->border_width - SCROLLBAR_WIDTH);
sl = ta->vis_width - 2 * ta->border_width -
(ta->bar_y != NULL ? SCROLLBAR_WIDTH : 0);
 
if (sx >= 0 && sy >= 0 && sx < sl && sy < SCROLLBAR_WIDTH) {
scrollbar_mouse_action(ta->bar_x, mouse, sx, sy);
return true;
}
}
 
/* Vertical scrollbar */
if (ta->bar_y != NULL && ta->drag_info.type == TEXTAREA_DRAG_NONE) {
/* No drag happening, but mouse input is over scrollbar;
* pass input to scrollbar */
sx = x - (ta->vis_width - ta->border_width - SCROLLBAR_WIDTH);
sy = y - ta->border_width;
sl = ta->vis_height - 2 * ta->border_width;
 
if (sx >= 0 && sy >= 0 && sx < SCROLLBAR_WIDTH && sy < sl) {
scrollbar_mouse_action(ta->bar_y, mouse, sx, sy);
return true;
}
}
 
/* mouse button pressed above the text area, move caret */
if (mouse & BROWSER_MOUSE_PRESS_1) {
if (!(ta->flags & TEXTAREA_READONLY)) {
textarea_get_xy_offset(ta, x, y, &c_off);
ta->drag_start_char = c_off;
 
textarea_set_caret(ta, c_off);
}
if (ta->sel_start != -1) {
/* remove selection */
ta->sel_start = ta->sel_end = -1;
 
msg.ta = ta;
msg.type = TEXTAREA_MSG_REDRAW_REQUEST;
msg.data.redraw.x0 = 0;
msg.data.redraw.y0 = 0;
msg.data.redraw.x1 = ta->vis_width;
msg.data.redraw.y1 = ta->vis_height;
 
ta->callback(ta->data, &msg);
}
 
} else if (mouse & BROWSER_MOUSE_DOUBLE_CLICK) {
if (!(ta->flags & TEXTAREA_READONLY)) {
textarea_set_caret_xy(ta, x, y);
return textarea_select_fragment(ta);
}
 
} else if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_HOLDING_1)) {
textarea_get_xy_offset(ta, x, y, &c_off);
c_start = ta->drag_start_char;
c_end = c_off;
ta->drag_info.type = TEXTAREA_DRAG_SELECTION;
 
msg.ta = ta;
msg.type = TEXTAREA_MSG_DRAG_REPORT;
msg.data.drag = ta->drag_info.type;
 
ta->callback(ta->data, &msg);
 
return textarea_select(ta, c_start, c_end);
}
 
return true;
}
 
 
/* exported interface, documented in textarea.h */
void textarea_get_dimensions(struct textarea *ta, int *width, int *height)
{
if (width != NULL)
*width = ta->vis_width;
if (height != NULL)
*height = ta->vis_height;
}
 
 
/* exported interface, documented in textarea.h */
void textarea_set_dimensions(struct textarea *ta, int width, int height)
{
struct textarea_msg msg;
 
ta->vis_width = width;
ta->vis_height = height;
textarea_reflow(ta, 0);
 
msg.ta = ta;
msg.type = TEXTAREA_MSG_REDRAW_REQUEST;
msg.data.redraw.x0 = 0;
msg.data.redraw.y0 = 0;
msg.data.redraw.x1 = ta->vis_width;
msg.data.redraw.y1 = ta->vis_height;
 
ta->callback(ta->data, &msg);
}
/programs/network/netsurf/netsurf/desktop/textarea.h
0,0 → 1,207
/*
* Copyright 2006 John-Mark Bell <jmb@netsurf-browser.org>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Single/Multi-line UTF-8 text area (interface)
*/
 
#ifndef _NETSURF_DESKTOP_TEXTAREA_H_
#define _NETSURF_DESKTOP_TEXTAREA_H_
 
#include <stdint.h>
#include <stdbool.h>
#include "desktop/browser.h"
#include "desktop/plot_style.h"
 
 
struct textarea;
 
/* Text area flags */
typedef enum {
TEXTAREA_DEFAULT = (1 << 0), /**< Standard input */
TEXTAREA_MULTILINE = (1 << 1), /**< Multiline area */
TEXTAREA_READONLY = (1 << 2), /**< Non-editable */
TEXTAREA_INTERNAL_CARET = (1 << 3), /**< Render own caret */
TEXTAREA_PASSWORD = (1 << 4) /**< Obscured display */
} textarea_flags;
 
typedef enum {
TEXTAREA_DRAG_NONE,
TEXTAREA_DRAG_SCROLLBAR,
TEXTAREA_DRAG_SELECTION
} textarea_drag_type;
 
typedef enum {
TEXTAREA_MSG_DRAG_REPORT, /**< Textarea drag start/end report */
TEXTAREA_MSG_REDRAW_REQUEST, /**< Textarea redraw request */
TEXTAREA_MSG_MOVED_CARET /**< Textarea caret moved */
} textarea_msg_type;
 
struct textarea_msg {
struct textarea *ta;
 
textarea_msg_type type;
union {
textarea_drag_type drag;
struct rect redraw;
struct {
bool hidden;
int x;
int y;
int height;
} caret;
} data;
};
 
typedef struct textarea_setup {
textarea_flags flags; /**< Setup flags */
 
int width; /**< Textarea width */
int height; /**< Textarea height */
 
int pad_top; /**< Textarea top padding */
int pad_right; /**< Textarea right padding */
int pad_bottom; /**< Textarea bottom padding */
int pad_left; /**< Textarea left padding */
 
int border_width; /**< Textarea border width */
colour border_col; /**< Textarea border colour */
 
colour selected_text; /**< Textarea selected text colour */
colour selected_bg; /**< Textarea selection background colour */
plot_font_style_t text; /**< Textarea background colour and font */
 
} textarea_setup;
 
/**
* Client callback for the textarea
*
* \param data user data passed at textarea creation
* \param textarea_msg textarea message data
*/
typedef void(*textarea_client_callback)(void *data, struct textarea_msg *msg);
 
/**
* Create a text area
*
* \param setup textarea settings and style
* \param redraw_callback will be called when textarea wants to redraw
* \param data user specified data which will be passed to callbacks
* \return Opaque handle for textarea or 0 on error
*/
struct textarea *textarea_create(const textarea_setup *setup,
textarea_client_callback callback, void *data);
 
/**
* Destroy a text area
*
* \param ta Text area to destroy
*/
void textarea_destroy(struct textarea *ta);
 
/**
* Set the text in a text area, discarding any current text
*
* \param ta Text area
* \param text UTF-8 text to set text area's contents to
* \return true on success, false on memory exhaustion
*/
bool textarea_set_text(struct textarea *ta, const char *text);
 
/**
* Extract the text from a text area
*
* \param ta Text area
* \param buf Pointer to buffer to receive data, or NULL
* to read length required
* \param len Length (bytes) of buffer pointed to by buf, or 0 to read length
* \return Length (bytes) written/required or -1 on error
*/
int textarea_get_text(struct textarea *ta, char *buf, unsigned int len);
 
/**
* Set the caret's position
*
* \param ta Text area
* \param caret 0-based character index to place caret at, -1 removes
* the caret
* \return true on success false otherwise
*/
bool textarea_set_caret(struct textarea *ta, int caret);
 
/**
* Get the caret's position
*
* \param ta Text area
* \return 0-based character index of caret location, or -1 on error
*/
int textarea_get_caret(struct textarea *ta);
 
/**
* Handle redraw requests for text areas
*
* \param ta textarea to render
* \param x x coordinate of textarea top
* \param y y coordinate of textarea left
* \param bg background colour under textarea
* \param clip clip rectangle
* \param ctx current redraw context
*/
void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
const struct rect *clip, const struct redraw_context *ctx);
 
/**
* Key press handling for text areas.
*
* \param ta The text area which got the keypress
* \param key The ucs4 character codepoint
* \return true if the keypress is dealt with, false otherwise.
*/
bool textarea_keypress(struct textarea *ta, uint32_t key);
 
/**
* Handles all kinds of mouse action
*
* \param ta Text area
* \param mouse the mouse state at action moment
* \param x X coordinate
* \param y Y coordinate
* \return true if action was handled false otherwise
*/
bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse,
int x, int y);
 
/**
* Gets the dimensions of a textarea
*
* \param width if not NULL, gets updated to the width of the textarea
* \param height if not NULL, gets updated to the height of the textarea
*/
void textarea_get_dimensions(struct textarea *ta, int *width, int *height);
 
/**
* Set the dimensions of a textarea, causing a reflow and
* emitting a redraw request.
*
* \param width the new width of the textarea
* \param height the new height of the textarea
*/
void textarea_set_dimensions(struct textarea *ta, int width, int height);
#endif
 
/programs/network/netsurf/netsurf/desktop/textinput.c
0,0 → 1,188
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk>
* Copyright 2004 John Tytgat <joty@netsurf-browser.org>
* Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Textual input handling (implementation)
*/
 
#include <assert.h>
#include <ctype.h>
#include <string.h>
#include <dom/dom.h>
 
#include "desktop/browser_private.h"
#include "desktop/gui.h"
#include "desktop/mouse.h"
#include "desktop/scrollbar.h"
#include "desktop/selection.h"
#include "desktop/textinput.h"
#include "render/box.h"
#include "render/font.h"
#include "render/form.h"
#include "render/html_internal.h"
#include "render/layout.h"
#include "utils/log.h"
#include "utils/talloc.h"
#include "utils/utf8.h"
#include "utils/utils.h"
 
/* Define to enable textinput debug */
#undef TEXTINPUT_DEBUG
 
 
/**
* Position the caret and assign a callback for key presses.
*
* \param bw The browser window in which to place the caret
* \param x X coordinate of the caret
* \param y Y coordinate
* \param height Height of caret
* \param caret_cb Callback function for keypresses
* \param paste_cb Callback function for pasting text
* \param move_cb Callback function for caret movement
* \param p1 Callback private data pointer, passed to callback function
* \param p2 Callback private data pointer, passed to callback function
*/
void browser_window_place_caret(struct browser_window *bw,
int x, int y, int height,
browser_caret_callback caret_cb,
browser_paste_callback paste_cb,
browser_move_callback move_cb,
void *p1, void *p2)
{
struct browser_window *root_bw;
int pos_x = 0;
int pos_y = 0;
 
/* Find top level browser window */
root_bw = browser_window_get_root(bw);
browser_window_get_position(bw, true, &pos_x, &pos_y);
 
x = x * bw->scale + pos_x;
y = y * bw->scale + pos_y;
 
gui_window_place_caret(root_bw->window, x, y, height * bw->scale);
bw->caret_callback = caret_cb;
bw->paste_callback = paste_cb;
bw->move_callback = move_cb;
bw->caret_p1 = p1;
bw->caret_p2 = p2;
 
/* Set focus browser window */
root_bw->focus = bw;
}
 
 
/**
* Removes the caret and callback for key process.
*
* \param bw The browser window from which to remove caret
*/
void browser_window_remove_caret(struct browser_window *bw)
{
struct browser_window *root_bw;
 
root_bw = browser_window_get_root(bw);
 
if (root_bw && root_bw->window)
gui_window_remove_caret(root_bw->window);
 
bw->caret_callback = NULL;
bw->paste_callback = NULL;
bw->move_callback = NULL;
bw->caret_p1 = NULL;
bw->caret_p2 = NULL;
}
 
 
/**
* Handle key presses in a browser window.
*
* \param bw The root browser window
* \param key The UCS4 character codepoint
* \return true if key handled, false otherwise
*/
bool browser_window_key_press(struct browser_window *bw, uint32_t key)
{
struct browser_window *focus = bw->focus;
 
assert(bw->window != NULL);
 
/* safe keys that can be handled whether input claimed or not */
switch (key) {
case KEY_COPY_SELECTION:
selection_copy_to_clipboard(bw->cur_sel);
return true;
 
case KEY_CLEAR_SELECTION:
selection_clear(bw->cur_sel, true);
return true;
 
case KEY_ESCAPE:
if (bw->cur_sel && selection_defined(bw->cur_sel)) {
selection_clear(bw->cur_sel, true);
return true;
}
/* if there's no selection,
* leave Escape for the caller */
return false;
}
 
if (focus->caret_callback) {
/* Pass keypress onto anything that has claimed input focus */
return focus->caret_callback(focus, key,
focus->caret_p1, focus->caret_p2);
}
 
/* keys we can't handle here if cursor is in form */
switch (key) {
case KEY_SELECT_ALL:
selection_select_all(bw->cur_sel);
return true;
}
 
return false;
}
 
 
/**
* Paste a block of text into a browser window at the caret position.
*
* \param bw browser window
* \param utf8 pointer to block of text
* \param utf8_len length (bytes) of text block
* \param last true iff this is the last chunk (update screen too)
* \return true iff successful
*
* TODO: Remove this function.
*/
 
bool browser_window_paste_text(struct browser_window *bw, const char *utf8,
unsigned utf8_len, bool last)
{
if (!bw->focus || !bw->focus->paste_callback)
return false;
 
return bw->focus->paste_callback(bw->focus, utf8, utf8_len, last,
bw->focus->caret_p1, bw->focus->caret_p2);
}
 
/programs/network/netsurf/netsurf/desktop/textinput.h
0,0 → 1,69
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk>
* Copyright 2004 John Tytgat <joty@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Textual input handling (interface)
*/
 
#ifndef _NETSURF_DESKTOP_TEXTINPUT_H_
#define _NETSURF_DESKTOP_TEXTINPUT_H_
 
enum input_key {
 
KEY_SELECT_ALL = 1,
KEY_COPY_SELECTION = 3,
 
KEY_DELETE_LEFT = 8,
KEY_TAB = 9,
 
KEY_NL = 10,
KEY_SHIFT_TAB = 11,
KEY_CR = 13,
 
KEY_CUT_LINE = 21,
KEY_PASTE = 22,
KEY_CUT_SELECTION = 24,
KEY_CLEAR_SELECTION = 26,
 
KEY_ESCAPE = 27,
 
/* cursor movement keys */
KEY_LEFT = 28,
KEY_RIGHT,
KEY_UP,
KEY_DOWN,
 
KEY_DELETE_RIGHT = 127,
 
KEY_LINE_START = 128,
KEY_LINE_END,
KEY_TEXT_START,
KEY_TEXT_END,
KEY_WORD_LEFT,
KEY_WORD_RIGHT,
KEY_PAGE_UP,
KEY_PAGE_DOWN,
KEY_DELETE_LINE_END,
KEY_DELETE_LINE_START,
};
 
 
#endif
/programs/network/netsurf/netsurf/desktop/thumbnail.c
0,0 → 1,106
/*
* Copyright 2011 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Core thumbnail handling (implementation).
*/
 
#include <assert.h>
#include <stdbool.h>
 
#include "content/content.h"
#include "content/hlcache.h"
#include "desktop/browser.h"
#include "desktop/knockout.h"
#include "desktop/options.h"
#include "desktop/plotters.h"
#include "desktop/thumbnail.h"
#include "utils/log.h"
 
 
/**
* Get scale at which thumbnail will be rendered for a given content and
* thumbnail size.
*
* \param content The content to redraw for thumbnail
* \param width The thumbnail width
* \return scale thumbnail will be rendered at
*
* Units for width and height are pixels.
*/
static float thumbnail_get_redraw_scale(struct hlcache_handle *content,
int width)
{
assert(content);
 
if (content_get_width(content))
return (float)width / (float)content_get_width(content);
else
return 1.0;
}
 
 
/* exported interface, documented in thumbnail.h */
bool thumbnail_redraw(struct hlcache_handle *content,
int width, int height, const struct redraw_context *ctx)
{
struct redraw_context new_ctx = *ctx;
struct rect clip;
struct content_redraw_data data;
float scale;
bool plot_ok = true;
 
assert(content);
 
if (ctx->plot->option_knockout)
knockout_plot_start(ctx, &new_ctx);
 
/* Set clip rectangle to required thumbnail size */
clip.x0 = 0;
clip.y0 = 0;
clip.x1 = width;
clip.y1 = height;
 
new_ctx.plot->clip(&clip);
 
/* Plot white background */
plot_ok &= new_ctx.plot->rectangle(clip.x0, clip.y0, clip.x1, clip.y1,
plot_style_fill_white);
 
/* Find the scale we're using */
scale = thumbnail_get_redraw_scale(content, width);
 
/* Set up content redraw data */
data.x = 0;
data.y = 0;
data.width = width;
data.height = height;
 
data.background_colour = 0xFFFFFF;
data.scale = scale;
data.repeat_x = false;
data.repeat_y = false;
 
/* Render the content */
plot_ok &= content_redraw(content, &data, &clip, &new_ctx);
if (ctx->plot->option_knockout)
knockout_plot_end();
 
return plot_ok;
}
/programs/network/netsurf/netsurf/desktop/thumbnail.h
0,0 → 1,58
/*
* Copyright 2011 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Thumbail handling (interface).
*/
 
#ifndef _NETSURF_DESKTOP_THUMBNAIL_H_
#define _NETSURF_DESKTOP_THUMBNAIL_H_
 
#include <stdbool.h>
#include "utils/nsurl.h"
#include "utils/types.h"
 
struct hlcache_handle;
struct bitmap;
 
 
/**
* Redraw a content for thumbnailing
*
* Calls the redraw function for the content,
*
* \param content The content to redraw for thumbnail
* \param width The thumbnail width
* \param height The thumbnail height
* \param ctx current redraw context
* \return true if successful, false otherwise
*
* The thumbnail is guaranteed to be filled to its width/height extents, so
* there is no need to render a solid background first.
*
* Units for width and height are pixels.
*/
bool thumbnail_redraw(struct hlcache_handle *content,
int width, int height, const struct redraw_context *ctx);
 
 
/* In platform specific thumbnail.c. */
bool thumbnail_create(struct hlcache_handle *content, struct bitmap *bitmap,
nsurl *url);
 
#endif
/programs/network/netsurf/netsurf/desktop/tree.c
0,0 → 1,3087
/*
* Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Generic tree handling (implementation).
*/
 
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "content/content.h"
#include "content/hlcache.h"
#include "css/utils.h"
#include "desktop/browser.h"
#include "desktop/knockout.h"
#include "desktop/textarea.h"
#include "desktop/textinput.h"
#include "desktop/tree.h"
#include "desktop/options.h"
#include "desktop/plotters.h"
#include "render/font.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
#include "utils/url.h"
 
#undef TREE_NOISY_DEBUG
 
#define MAXIMUM_URL_LENGTH 1024
 
#define TREE_TEXT_SIZE_PT 11
#define TREE_ICON_SIZE 17
#define NODE_INSTEP 20
 
static int tree_text_size_px;
static int TREE_LINE_HEIGHT;
 
static char *tree_icons_dir = NULL;
 
static plot_font_style_t plot_fstyle = {
.family = PLOT_FONT_FAMILY_SANS_SERIF,
.size = TREE_TEXT_SIZE_PT * FONT_SIZE_SCALE,
.weight = 400,
.flags = FONTF_NONE
};
 
static plot_font_style_t plot_fstyle_def_folder = {
.family = PLOT_FONT_FAMILY_SANS_SERIF,
.size = TREE_TEXT_SIZE_PT * FONT_SIZE_SCALE,
.weight = 700,
.flags = FONTF_NONE
};
 
static plot_font_style_t plot_fstyle_selected = {
.family = PLOT_FONT_FAMILY_SANS_SERIF,
.size = TREE_TEXT_SIZE_PT * FONT_SIZE_SCALE,
.weight = 400,
.flags = FONTF_NONE
};
 
static plot_font_style_t plot_fstyle_selected_def_folder = {
.family = PLOT_FONT_FAMILY_SANS_SERIF,
.size = TREE_TEXT_SIZE_PT * FONT_SIZE_SCALE,
.weight = 700,
.flags = FONTF_NONE
};
 
/** plot style for treeview backgrounds. */
static plot_style_t plot_style_fill_tree_background = {
.fill_type = PLOT_OP_TYPE_SOLID
};
 
/** plot style for treeview backgrounds. */
static plot_style_t plot_style_fill_tree_selected = {
.fill_type = PLOT_OP_TYPE_SOLID
};
 
/** plot style for treeview furniture lines. */
static plot_style_t plot_style_stroke_tree_furniture = {
.stroke_type = PLOT_OP_TYPE_SOLID
};
 
/** plot style for treeview furniture fills. */
static plot_style_t plot_style_fill_tree_furniture = {
.fill_type = PLOT_OP_TYPE_SOLID
};
 
struct node;
struct tree;
 
struct node_element_box {
int x; /**< X offset from origin */
int y; /**< Y offset from origin */
int width; /**< Element width */
int height; /**< Element height */
};
 
struct node_element {
struct node *parent; /**< Parent node */
node_element_type type; /**< Element type */
struct node_element_box box; /**< Element bounding box */
const char *text; /**< Text for the element */
void *bitmap; /**< Bitmap for the element */
struct node_element *next; /**< Next node element */
unsigned int flag; /**< Client specified flag for data
being represented */
bool editable; /**< Whether the node text can be
* modified, editable text is deleted
* without noticing the tree user
*/
};
 
struct node {
bool selected; /**< Whether the node is selected */
bool expanded; /**< Whether the node is expanded */
bool folder; /**< Whether the node is a folder */
bool def_folder; /**< Whether the node is the default folder */
bool retain_in_memory; /**< Whether the node remains
in memory after deletion */
bool deleted; /**< Whether the node is currently
deleted */
bool processing; /**< Internal flag used when moving */
struct node_element_box box; /**< Bounding box of all elements */
struct node_element data; /**< Data to display */
struct node *parent; /**< Parent entry (NULL for root) */
struct node *child; /**< First child */
struct node *last_child; /**< Last child */
struct node *previous; /**< Previous child of the parent */
struct node *next; /**< Next child of the parent */
 
/** Sorting function for the node (for folder nodes only) */
int (*sort) (struct node *, struct node *);
/** Gets called for each deleted node_element and on node launch */
tree_node_user_callback user_callback;
/** User data to be passed to delete_callback */
void *callback_data;
};
 
struct tree {
struct node *root; /* Tree root element */
int width; /* Tree width */
int height; /* Tree height */
unsigned int flags; /* Tree flags */
struct textarea *textarea; /* Handle for UTF-8 textarea */
int ta_height; /* Textarea height */
struct node_element *editing; /* Node element being edited */
 
bool redraw; /* Flag indicating whether the tree
should be redrawn on layout
changes */
tree_drag_type drag;
const struct treeview_table *callbacks;
void *client_data; /* User assigned data for the
callbacks */
struct node *def_folder; /* Node to be used for additions by default */
};
 
void tree_set_icon_dir(char *icon_dir)
{
LOG(("Tree icon directory set to %s", icon_dir));
tree_icons_dir = icon_dir;
}
 
/**
* Set up colours for plot styles used in tree redraw.
*/
void tree_setup_colours(void)
{
/* Background colour */
plot_style_fill_tree_background.fill_colour =
gui_system_colour_char("Window");
 
/* Selection background colour */
plot_style_fill_tree_selected.fill_colour =
gui_system_colour_char("Highlight");
 
/* Furniture line colour */
plot_style_stroke_tree_furniture.stroke_colour = blend_colour(
gui_system_colour_char("Window"),
gui_system_colour_char("WindowText"));
 
/* Furniture fill colour */
plot_style_fill_tree_furniture.fill_colour =
gui_system_colour_char("Window");
 
/* Text colour */
plot_fstyle.foreground = gui_system_colour_char("WindowText");
plot_fstyle.background = gui_system_colour_char("Window");
plot_fstyle_def_folder.foreground =
gui_system_colour_char("InfoText");
plot_fstyle_def_folder.background =
gui_system_colour_char("Window");
 
/* Selected text colour */
plot_fstyle_selected.foreground =
gui_system_colour_char("HighlightText");
plot_fstyle_selected.background =
gui_system_colour_char("Highlight");
plot_fstyle_selected_def_folder.foreground =
gui_system_colour_char("HighlightText");
plot_fstyle_selected_def_folder.background =
gui_system_colour_char("Highlight");
}
 
 
/**
* Creates and initialises a new tree.
*
* \param flags Flag word for flags to create the new tree with
* \param callbacks Callback functions to support the tree in the frontend.
* \param client_data Data to be passed to start_redraw and end_redraw
* \return The newly created tree, or NULL on memory exhaustion
*/
struct tree *tree_create(unsigned int flags,
const struct treeview_table *callbacks, void *client_data)
{
struct tree *tree;
char *title;
 
tree = calloc(sizeof(struct tree), 1);
if (tree == NULL) {
LOG(("calloc failed"));
warn_user("NoMemory", 0);
return NULL;
}
 
title = strdup("Root");
if (title == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
free(tree);
return NULL;
}
tree->root = tree_create_folder_node(NULL, NULL, title,
false, false, false);
if (tree->root == NULL) {
free(title);
free(tree);
return NULL;
}
tree->root->expanded = true;
 
tree->width = 0;
tree->height = 0;
tree->flags = flags;
tree->textarea = NULL;
tree->editing = NULL;
tree->redraw = false;
tree->drag = TREE_NO_DRAG;
tree->callbacks = callbacks;
tree->client_data = client_data;
 
/* Set text height in pixels */
tree_text_size_px =
(TREE_TEXT_SIZE_PT * FIXTOINT(nscss_screen_dpi) + 36) /
72;
/* Set line height appropriate for this text height in pixels
* Using 4/3 text height */
TREE_LINE_HEIGHT = (tree_text_size_px * 8 + 3) / 6;
 
/* But if that's too small for the icons, base the line height on
* the icon height. */
if (TREE_LINE_HEIGHT < TREE_ICON_SIZE + 2)
TREE_LINE_HEIGHT = TREE_ICON_SIZE + 2;
 
tree_setup_colours();
 
return tree;
}
 
 
/**
* Recalculates the dimensions of a node element.
*
* \param tree the tree to which the element belongs, may be NULL
* \param element the element to recalculate
*/
static void tree_recalculate_node_element(struct tree *tree,
struct node_element *element)
{
struct bitmap *bitmap = NULL;
int width, height;
static char *cache_text = NULL;
static int cache_size = 0;
plot_font_style_t *fstyle;
static plot_font_style_t *cache_fstyle = NULL;
 
assert(element != NULL);
 
if (element->parent->def_folder)
fstyle = &plot_fstyle_def_folder;
else
fstyle = &plot_fstyle;
 
switch (element->type) {
case NODE_ELEMENT_TEXT_PLUS_ICON:
case NODE_ELEMENT_TEXT:
if(element->text == NULL)
break;
 
if (tree != NULL && element == tree->editing) {
textarea_get_dimensions(tree->textarea,
&element->box.width, NULL);
} else {
if ((cache_text != NULL) &&
(strcmp(cache_text, element->text) == 0) &&
(cache_fstyle == fstyle)) {
element->box.width = cache_size;
#ifdef TREE_NOISY_DEBUG
LOG(("Tree font width cache hit"));
#endif
} else {
if(cache_text != NULL) free(cache_text);
nsfont.font_width(fstyle,
element->text,
strlen(element->text),
&cache_size);
element->box.width = cache_size;
cache_text = strdup(element->text);
cache_fstyle = fstyle;
}
}
 
element->box.width += 8;
element->box.height = TREE_LINE_HEIGHT;
 
if (element->type == NODE_ELEMENT_TEXT_PLUS_ICON)
element->box.width += NODE_INSTEP;
 
break;
 
case NODE_ELEMENT_BITMAP:
bitmap = element->bitmap;
if (bitmap != NULL) {
width = bitmap_get_width(bitmap);
height = bitmap_get_height(bitmap);
element->box.width = width + 1;
element->box.height = height + 2;
} else {
element->box.width = 0;
element->box.height = 0;
}
break;
}
}
 
 
/**
* Calculates the height of a node including any children
*
* \param node the node to calculate the height of
* \return the total height of the node and children
*/
static int tree_get_node_height(struct node *node)
{
int y1;
 
assert(node != NULL);
 
if ((node->child == NULL) || (node->expanded == false)) {
return node->box.height;
}
 
y1 = node->box.y;
if (y1 < 0) {
y1 = 0;
}
node = node->child;
 
while ((node->next != NULL) ||
((node->child != NULL) && (node->expanded))) {
for (; node->next != NULL; node = node->next);
 
if ((node->child != NULL) && (node->expanded)) {
node = node->child;
}
}
return node->box.y + node->box.height - y1;
}
 
 
/**
* Calculates the width of a node including any children
*
* \param node the node to calculate the height of
* \return the total width of the node and children
*/
static int tree_get_node_width(struct node *node)
{
int width = 0;
int child_width;
 
assert(node != NULL);
 
for (; node != NULL; node = node->next) {
if (width < (node->box.x + node->box.width)) {
width = node->box.x + node->box.width;
}
 
if ((node->child != NULL) && (node->expanded)) {
child_width = tree_get_node_width(node->child);
if (width < child_width) {
width = child_width;
}
}
}
return width;
}
 
 
/**
* Recalculates the position of a node, its siblings and children.
*
* \param tree the tree to which 'root' belongs
* \param root the root node to update from
*/
static void tree_recalculate_node_positions(struct tree *tree,
struct node *root)
{
struct node *parent;
struct node *node;
struct node *child;
struct node_element *element;
int y;
bool has_icon;
 
for (node = root; node != NULL; node = node->next) {
 
parent = node->parent;
 
if (node->previous != NULL) {
node->box.x = node->previous->box.x;
node->box.y = node->previous->box.y +
tree_get_node_height(node->previous);
} else if (parent != NULL) {
node->box.x = parent->box.x + NODE_INSTEP;
node->box.y = parent->box.y +
parent->box.height;
for (child = parent->child; child != node;
child = child->next)
node->box.y += child->box.height;
} else {
node->box.x = tree->flags & TREE_NO_FURNITURE
? -NODE_INSTEP + 4 : 0;
node->box.y = -TREE_LINE_HEIGHT;
}
 
if (!node->expanded) {
node->data.box.x = node->box.x;
node->data.box.y = node->box.y;
continue;
}
 
if (node->folder) {
node->data.box.x = node->box.x;
node->data.box.y = node->box.y;
tree_recalculate_node_positions(tree, node->child);
} else {
y = node->box.y;
has_icon = false;
for (element = &node->data; element != NULL;
element = element->next)
if (element->type ==
NODE_ELEMENT_TEXT_PLUS_ICON) {
has_icon = true;
break;
}
 
for (element = &node->data; element != NULL;
element = element->next) {
element->box.x = node->box.x;
if (element->type !=
NODE_ELEMENT_TEXT_PLUS_ICON &&
has_icon)
element->box.x += NODE_INSTEP;
element->box.y = y;
y += element->box.height;
}
}
 
}
}
 
 
/**
* Recalculates the size of a node.
*
* \param tree the tree to which node belongs, may be NULL
* \param node the node to update
* \param recalculate_sizes whether the node elements have changed
*/
static void tree_recalculate_node_sizes(struct tree *tree, struct node *node,
bool recalculate_sizes)
{
struct node_element *element;
int height;
 
assert(node != NULL);
 
height = node->box.height;
node->box.width = 0;
node->box.height = 0;
if (node->expanded) {
for (element = &node->data; element != NULL;
element = element->next) {
if (recalculate_sizes) {
#ifdef TREE_NOISY_DEBUG
if(element->text) LOG(("%s", element->text));
#endif
tree_recalculate_node_element(tree, element);
}
node->box.width = (node->box.width > element->box.x +
element->box.width - node->box.x) ?
node->box.width :
element->box.width + element->box.x -
node->box.x;
node->box.height += element->box.height;
}
} else {
if (recalculate_sizes)
for (element = &node->data; element != NULL;
element = element->next) {
#ifdef TREE_NOISY_DEBUG
if(element->text) LOG(("%s", element->text));
#endif
tree_recalculate_node_element(tree, element);
}
 
node->box.width = node->data.box.width;
node->box.height = node->data.box.height;
}
 
if (tree != NULL && height != node->box.height)
tree_recalculate_node_positions(tree, tree->root);
}
 
 
/**
* Creates a folder node with the specified title, and optionally links it into
* the tree.
*
* \param tree the owner tree of 'parent', may be NULL
* \param parent the parent node, or NULL not to link
* \param title the node title (not copied, used directly)
* \param editable if true, the node title will be editable
* \param retain_in_memory if true, the node will stay in memory after deletion
* \param deleted if true, the node is created with the deleted flag
* \return the newly created node.
*/
struct node *tree_create_folder_node(struct tree *tree, struct node *parent,
const char *title, bool editable, bool retain_in_memory,
bool deleted)
{
struct node *node;
 
assert(title != NULL);
 
node = calloc(sizeof(struct node), 1);
if (node == NULL) {
LOG(("calloc failed"));
warn_user("NoMemory", 0);
return NULL;
}
node->folder = true;
node->retain_in_memory = retain_in_memory;
node->deleted = deleted;
node->data.parent = node;
node->data.type = NODE_ELEMENT_TEXT;
node->data.text = title;
node->data.flag = TREE_ELEMENT_TITLE;
node->data.editable = editable;
node->sort = NULL;
node->user_callback = NULL;
node->previous = NULL;
 
tree_recalculate_node_sizes(tree, node, true);
if (parent != NULL)
tree_link_node(tree, parent, node, false);
 
return node;
}
 
 
/**
* Creates a leaf node with the specified title, and optionally links it into
* the tree.
*
* \param tree the owner tree of 'parent', may be NULL
* \param parent the parent node, or NULL not to link
* \param title the node title (not copied, used directly)
* \param editable if true, the node title will be editable
* \param retain_in_memory if true, the node will stay in memory after deletion
* \param deleted if true, the node is created with the deleted flag
* \return the newly created node.
*/
struct node *tree_create_leaf_node(struct tree *tree, struct node *parent,
const char *title, bool editable, bool retain_in_memory,
bool deleted)
{
struct node *node;
 
assert(title != NULL);
 
node = calloc(sizeof(struct node), 1);
if (node == NULL) {
LOG(("calloc failed"));
warn_user("NoMemory", 0);
return NULL;
}
 
node->folder = false;
node->retain_in_memory = retain_in_memory;
node->deleted = deleted;
node->data.parent = node;
node->data.type = NODE_ELEMENT_TEXT;
node->data.text = title;
node->data.flag = TREE_ELEMENT_TITLE;
node->data.editable = editable;
node->sort = NULL;
node->user_callback = NULL;
node->previous = NULL;
 
tree_recalculate_node_sizes(tree, node, true);
if (parent != NULL)
tree_link_node(tree, parent, node, false);
 
return node;
}
 
 
/**
* Creates an empty text node element and links it to a node.
*
* \param parent the parent node
* \param type the required element type
* \param flag user assigned flag used for searches
* \return the newly created element.
*/
struct node_element *tree_create_node_element(struct node *parent,
node_element_type type, unsigned int flag, bool editable)
{
struct node_element *element;
 
element = calloc(sizeof(struct node_element), 1);
if (element == NULL)
return NULL;
 
element->parent = parent;
element->flag = flag;
element->type = type;
element->editable = editable;
element->next = parent->data.next;
parent->data.next = element;
 
return element;
}
 
 
/**
* Inserts a node into the correct place according to the parent's sort function
*
* \param parent the node whose child node 'node' becomes
* \param node the node to be inserted
*/
static void tree_sort_insert(struct node *parent, struct node *node)
{
struct node *after;
 
assert(node != NULL);
assert(parent != NULL);
assert(parent->sort != NULL);
 
after = parent->last_child;
while ((after != NULL) &&
(parent->sort(node, after) == -1))
after = after->previous;
 
if (after != NULL) {
if (after->next != NULL)
after->next->previous = node;
node->next = after->next;
node->previous = after;
after->next = node;
} else {
node->previous = NULL;
node->next = parent->child;
if (parent->child != NULL) {
parent->child->previous = node;
}
parent->child = node;
}
 
if (node->next == NULL)
parent->last_child = node;
 
node->parent = parent;
}
 
 
/**
* Recalculates the size of a tree.
*
* \param tree the tree to recalculate
*/
static void tree_recalculate_size(struct tree *tree)
{
int width, height;
 
assert(tree != NULL);
 
width = tree->width;
height = tree->height;
 
tree->width = tree_get_node_width(tree->root);
tree->height = tree_get_node_height(tree->root);
 
if ((width != tree->width) || (height != tree->height))
tree->callbacks->resized(tree, tree->width, tree->height,
tree->client_data);
}
 
/**
* Recalculate the node data and redraw the relevant section of the tree.
*
* \param tree the tree to redraw, may be NULL
* \param node the node to update
* \param recalculate_sizes whether the elements have changed
* \param expansion the request is the result of a node expansion
*/
static void tree_handle_node_changed(struct tree *tree, struct node *node,
bool recalculate_sizes, bool expansion)
{
int node_width, node_height, tree_width, tree_height;
 
assert(node != NULL);
assert(tree != NULL);
 
node_width = node->box.width;
node_height = node->box.height;
tree_width = tree->width;
tree_height = tree->height;
 
if ((recalculate_sizes) || (expansion)) {
tree_recalculate_node_sizes(tree, node, true);
}
 
if (tree != NULL) {
if ((node->box.height != node_height) || (expansion)) {
tree_recalculate_node_positions(tree, tree->root);
tree_recalculate_size(tree);
if (tree->width > tree_width)
tree_width = tree->width;
if (tree->height > tree_height)
tree_height = tree->height;
if (tree->redraw) {
tree->callbacks->redraw_request(0, node->box.y,
tree_width,
tree_height - node->box.y,
tree->client_data);
}
} else {
if (node->box.width > node_width)
node_width = node->box.width;
if (tree->redraw)
tree->callbacks->redraw_request(node->box.x,
node->box.y,
node_width, node->box.height,
tree->client_data);
if (recalculate_sizes) {
tree_recalculate_size(tree);
}
}
}
}
 
 
/**
* Links a node to another node.
*
* \param tree the tree in which the link takes place, may be NULL
* \param link the node to link before/as a child (folders)
* or before/after (link)
* \param node the node to link
* \param before whether to link siblings before or after the supplied node
*/
void tree_link_node(struct tree *tree, struct node *link, struct node *node,
bool before)
{
 
struct node *parent;
bool sort = false;
 
assert(link != NULL);
assert(node != NULL);
 
if ((link->folder == 0) || (before)) {
parent = node->parent = link->parent;
if (parent->sort) {
sort = true;
} else {
if (before) {
node->next = link;
node->previous = link->previous;
if (link->previous != NULL)
link->previous->next = node;
link->previous = node;
if ((parent != NULL) && (parent->child == link))
parent->child = node;
} else {
node->previous = link;
node->next = link->next;
if (link->next != NULL)
link->next->previous = node;
link->next = node;
if ((parent != NULL) &&
(parent->last_child == link))
parent->last_child = node;
}
}
} else {
parent = node->parent = link;
if (parent->sort != NULL) {
sort = true;
} else {
node->next = NULL;
if (link->child == NULL) {
link->child = link->last_child = node;
node->previous = NULL;
} else {
link->last_child->next = node;
node->previous = link->last_child;
link->last_child = node;
}
}
 
}
 
if (sort) {
tree_sort_insert(parent, node);
}
 
tree_handle_node_changed(tree, link, false, true);
 
node->deleted = false;
}
 
 
/**
* Recalculate the node element and redraw the relevant section of the tree.
* The tree size is not updated.
*
* \param tree the tree to redraw, may be NULL
* \param element the node element to update
*/
static void tree_handle_node_element_changed(struct tree *tree,
struct node_element *element, bool text_changed)
{
int width, height;
 
assert(element != NULL);
 
width = element->box.width;
height = element->box.height;
 
if(text_changed == true) {
#ifdef TREE_NOISY_DEBUG
if(element->text) LOG(("%s", element->text));
#endif
tree_recalculate_node_element(tree, element);
}
 
if (element->box.height != height) {
tree_recalculate_node_sizes(tree, element->parent, false);
if ((tree != NULL) && (tree->redraw)) {
tree->callbacks->redraw_request(0, element->box.y,
tree->width + element->box.width -
width,
tree->height - element->box.y +
element->box.height - height,
tree->client_data);
}
} else {
if (element->box.width != width) {
tree_recalculate_node_sizes(tree, element->parent,
false);
}
 
if (tree != NULL) {
width = (width > element->box.width) ? width :
element->box.width;
if (tree->redraw) {
tree->callbacks->redraw_request(element->box.x,
element->box.y,
width,
element->box.height,
tree->client_data);
}
}
}
}
 
 
/**
* Stops editing a node_element
*
* \param tree The tree to stop editing for
* \param keep_changes If true the changes made to the text will be kept,
* if false they will be dropped
*/
static void tree_stop_edit(struct tree *tree, bool keep_changes)
{
int text_len;
char *text = NULL;
struct node_element *element;
struct node_msg_data msg_data;
node_callback_resp response;
 
assert(tree != NULL);
 
if (tree->editing == NULL || tree->textarea == NULL)
return;
 
element = tree->editing;
 
if (keep_changes) {
text_len = textarea_get_text(tree->textarea, NULL, 0);
text = malloc(text_len * sizeof(char));
if (text == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
textarea_destroy(tree->textarea);
tree->textarea = NULL;
return;
}
textarea_get_text(tree->textarea, text, text_len);
}
 
 
if (keep_changes && element->parent->user_callback != NULL) {
msg_data.msg = NODE_ELEMENT_EDIT_FINISHING;
msg_data.flag = element->flag;
msg_data.node = element->parent;
msg_data.data.text = text;
response = element->parent->user_callback(
element->parent->callback_data,
&msg_data);
 
switch (response) {
case NODE_CALLBACK_REJECT:
free(text);
text = NULL;
break;
case NODE_CALLBACK_CONTINUE:
free(text);
text = NULL;
return;
case NODE_CALLBACK_HANDLED:
case NODE_CALLBACK_NOT_HANDLED:
text = msg_data.data.text;
break;
}
}
 
textarea_destroy(tree->textarea);
tree->textarea = NULL;
tree->editing = NULL;
 
if (text != NULL)
tree_update_node_element(tree, element, text, NULL);
else
tree_handle_node_element_changed(tree, element, true);
 
 
tree_recalculate_size(tree);
if (element->parent->user_callback != NULL) {
msg_data.msg = keep_changes ? NODE_ELEMENT_EDIT_FINISHED :
NODE_ELEMENT_EDIT_CANCELLED;
msg_data.flag = element->flag;
msg_data.node = element->parent;
element->parent->user_callback(element->parent->callback_data,
&msg_data);
}
}
 
 
/**
* Delinks a node from the tree structures.
*
* \param tree the tree in which the delink takes place, may be NULL
* \param node the node to delink
*/
void tree_delink_node(struct tree *tree, struct node *node)
{
struct node *parent;
 
assert(node != NULL);
 
/* do not remove the root */
if (tree != NULL && node == tree->root)
return;
if ((tree != NULL) && (tree->editing != NULL)) {
parent = tree->editing->parent;
while (parent != NULL) {
if (node == parent) {
tree_stop_edit(tree, false);
break;
}
parent = parent->parent;
}
}
 
if (node->parent->child == node)
node->parent->child = node->next;
if (node->parent->last_child == node)
node->parent->last_child = node->previous;
parent = node->parent;
node->parent = NULL;
 
if (node->previous != NULL)
node->previous->next = node->next;
if (node->next != NULL)
node->next->previous = node->previous;
node->previous = NULL;
node->next = NULL;
 
tree_handle_node_changed(tree, parent, false, true);
}
 
 
/**
* Deletes a node from the tree.
*
* \param tree the tree to delete from, may be NULL
* \param node the node to delete
* \param siblings whether to delete all siblings
*/
static void tree_delete_node_internal(struct tree *tree, struct node *node,
bool siblings)
{
struct node *next, *child, *parent;
struct node_element *e, *f;
node_callback_resp response;
struct node_msg_data msg_data;
 
assert(node != NULL);
 
if (tree != NULL && tree->root == node)
return;
 
next = node->next;
parent = node->parent;
if (tree != NULL && parent == tree->root)
parent = NULL;
if ((tree != NULL) && (tree->def_folder == node))
tree->def_folder = NULL;
tree_delink_node(tree, node);
child = node->child;
node->child = NULL;
 
node->deleted = true;
if (child != NULL)
tree_delete_node_internal(tree, child, true);
 
if (!node->retain_in_memory) {
node->retain_in_memory = true;
for (e = &node->data; e != NULL; e = f) {
if (e->text != NULL) {
response = NODE_CALLBACK_NOT_HANDLED;
if (!e->editable &&
node->user_callback != NULL) {
msg_data.msg = NODE_DELETE_ELEMENT_TXT;
msg_data.flag = e->flag;
msg_data.node = node;
msg_data.data.text = (void *)e->text;
response = node->user_callback(
node->callback_data,
&msg_data);
}
if (response != NODE_CALLBACK_HANDLED)
free((void *)e->text);
e->text = NULL;
}
if (e->bitmap != NULL) {
response = NODE_CALLBACK_NOT_HANDLED;
if (node->user_callback != NULL) {
msg_data.msg = NODE_DELETE_ELEMENT_IMG;
msg_data.flag = e->flag;
msg_data.node = node;
msg_data.data.bitmap =
(void *)e->bitmap;
response = node->user_callback(
node->callback_data,
&msg_data);
}
/* TODO the type of this field is platform
dependent */
if (response != NODE_CALLBACK_HANDLED)
free(e->bitmap);
e->bitmap = NULL;
}
f = e->next;
if (e != &node->data)
free(e);
}
free(node);
}
 
if (siblings && next)
tree_delete_node_internal(tree, next, true);
if ((tree->flags & TREE_DELETE_EMPTY_DIRS) && parent != NULL &&
parent->child == NULL && !parent->deleted)
tree_delete_node_internal(tree, parent, false);
}
 
 
/**
* Deletes all nodes of a tree and the tree itself.
*
* \param tree the tree to be deleted
*/
void tree_delete(struct tree *tree)
{
tree->redraw = false;
 
if (tree->root->child != NULL)
tree_delete_node_internal(tree, tree->root->child, true);
 
free((void *)tree->root->data.text);
free(tree->root);
free(tree);
}
 
 
/**
* Gets the redraw property of the given tree.
*
* \param tree the tree for which to retrieve the property
* \return the redraw property of the tree
*/
bool tree_get_redraw(struct tree *tree)
{
return tree->redraw;
}
 
 
/**
* Deletes a node from the tree.
*
* \param tree the tree to delete from, may be NULL
* \param node the node to delete
* \param siblings whether to delete all siblings
*/
void tree_delete_node(struct tree *tree, struct node *node, bool siblings)
{
int y = node->box.y;
int height = tree->height;
int width = tree->width;
bool redraw_setting = tree->redraw;
 
tree->redraw = false;
 
tree_delete_node_internal(tree, node, siblings);
tree_recalculate_node_positions(tree, tree->root);
 
tree->redraw = redraw_setting;
 
if (tree->redraw)
tree->callbacks->redraw_request(0, y,
width, height, tree->client_data);
tree_recalculate_size(tree);
}
 
 
/**
* Sets an icon for a node
*
* \param tree The tree to which node belongs, may be NULL
* \param node The node for which the icon is set
* \param icon the image to use
*/
void tree_set_node_icon(struct tree *tree, struct node *node,
hlcache_handle *icon)
{
node->data.type = NODE_ELEMENT_TEXT_PLUS_ICON;
tree_update_node_element(tree, &(node->data), NULL, icon);
}
 
 
/**
* Updates all siblings and descendants of a node to an expansion state.
* No update is performed for the tree changes.
*
* \param tree the tree to which 'node' belongs
* \param node the node to set all siblings and descendants of
* \param expanded the expansion state to set
*/
static void tree_set_node_expanded_all(struct tree *tree, struct node *node,
bool expanded)
{
for (; node != NULL; node = node->next) {
if (node->expanded != expanded) {
node->expanded = expanded;
tree_recalculate_node_sizes(tree, node, false);
}
if ((node->child != NULL) && (node->expanded))
tree_set_node_expanded_all(tree, node->child, expanded);
}
}
 
 
/**
* Updates [all siblings and descendants of] a node to an expansion state.
*
* \param tree the tree to update
* \param node the node to set [all siblings and descendants of]
* \param expanded the expansion state to set
* \param folder whether to update folders, if this together with leaf
* will be false only 'node' will be updated
* \param leaf whether to update leaves (check also description for folder)
* \return whether any changes were made
*/
static bool tree_set_node_expanded_internal(struct tree *tree,
struct node *node, bool expanded, bool folder, bool leaf)
{
bool redraw = false;
struct node *end = (folder == false && leaf == false) ?
node->next : NULL;
 
if (tree->editing != NULL && node == tree->editing->parent)
tree_stop_edit(tree, false);
 
for (; node != end; node = node->next) {
if ((node->expanded != expanded) && (node != tree->root) &&
((folder && (node->folder)) ||
(leaf && (!node->folder)) ||
(!folder && !leaf))) {
node->expanded = expanded;
if (node->child != NULL)
tree_set_node_expanded_all(tree,
node->child, false);
if ((node->data.next != NULL) &&
(node->data.next->box.height == 0))
tree_recalculate_node_sizes(tree, node, true);
else
tree_recalculate_node_sizes(tree, node, false);
redraw = true;
}
if ((folder || leaf) && (node->child != NULL) &&
(node->expanded))
redraw |= tree_set_node_expanded_internal(tree,
node->child, expanded, folder, leaf);
}
return redraw;
}
 
 
/**
* Updates [all siblings and descendants of] a node to an expansion state.
*
* \param tree the tree to update
* \param node the node to set [all siblings and descendants of]
* \param expanded the expansion state to set
* \param folder whether to update folders, if this together with leaf
* will be false only 'node' will be updated
* \param leaf whether to update leaves (check also description for folder)
*/
void tree_set_node_expanded(struct tree *tree, struct node *node, bool expanded,
bool folder, bool leaf)
{
if (tree_set_node_expanded_internal(tree, node, expanded, folder, leaf))
tree_handle_node_changed(tree, node, false, true);
}
 
 
/**
* Updates a node to an selected state. The required areas of the tree are
* redrawn.
*
* \param tree the tree to update nodes for, may be NULL
* \param node the node to set all siblings and descendants of
* \param all if true update node together with its siblings and
* descendants
* \param selected the selection state to set
*/
void tree_set_node_selected(struct tree *tree, struct node *node, bool all,
bool selected)
{
struct node *end;
 
if (tree != NULL && node == tree->root)
node = tree->root->child;
if (node == NULL)
return;
 
end = all ? NULL : node->next;
 
for (; node != end; node = node->next) {
if (node->selected != selected) {
node->selected = selected;
if (tree != NULL && tree->redraw)
tree->callbacks->redraw_request(
node->data.box.x,
node->data.box.y,
node->data.box.width,
node->data.box.height,
tree->client_data);
}
if (all && (node->child != NULL) && (node->expanded))
tree_set_node_selected(tree, node->child, all,
selected);
}
}
 
 
/**
* Sets the sort function for a node
*
* \param tree the tree to which 'node' belongs, may be NULL
* \param node the node to be inserted
* \param sort pointer to the sorting function
*/
void tree_set_node_sort_function(struct tree *tree, struct node *node,
int (*sort) (struct node *, struct node *))
{
struct node *child;
 
node->sort = sort;
 
if (tree != NULL && tree->editing != NULL)
tree_stop_edit(tree, false);
 
/* the node had already some children so they must get sorted */
if (node->child != NULL) {
 
child = node->child;
node->child = NULL;
 
while (child != NULL) {
tree_sort_insert(node, child);
child = child->next;
}
 
}
 
if (tree != NULL)
tree_recalculate_node_positions(tree, node->child);
}
 
 
/**
* Sets the delete callback for a node.
*
* \param node the node for which the callback is set
* \param callback the callback functions to be set
* \param data user data to be passed to callback
*/
void tree_set_node_user_callback(struct node *node,
tree_node_user_callback callback, void *data)
{
node->user_callback = callback;
node->callback_data = data;
}
 
 
/**
* Sets the redraw property to the given value. If redraw is true, the tree will
* be redrawn on layout/appearance changes.
*
* \param tree the tree for which the property is set
* \param redraw the value to set
*/
void tree_set_redraw(struct tree *tree, bool redraw)
{
/* the tree might have no graphical representation, do not set the
redraw flag in such case */
if (tree->callbacks == NULL)
return;
tree->redraw = redraw;
}
 
 
/**
* Checks whether a node, its siblings or any children are selected.
*
* \param node the root node to check from
* \return whether 'node', its siblings or any children are selected.
*/
bool tree_node_has_selection(struct node *node)
{
for (; node != NULL; node = node->next) {
if (node->selected)
return true;
if ((node->child != NULL) && (node->expanded) &&
(tree_node_has_selection(node->child)))
return true;
}
return false;
}
 
 
/**
* Returns the current value of the nodes deleted property.
*
* \param node the node to be checked
* \return the current value of the nodes deleted property
*/
bool tree_node_is_deleted(struct node *node)
{
return node->deleted;
}
 
 
/**
* Returns true if the node is a folder
*
* \param node the node to be checked
* \return true if the node is a folder, false otherwise
*/
bool tree_node_is_folder(struct node *node)
{
return node->folder;
}
 
 
/**
* Returns true if the node is the default folder for a tree
*
* \param node the node to be checked
* \return true if the node is a default folder, false otherwise
*/
bool tree_node_is_default(struct node *node)
{
return node->def_folder;
}
 
 
/**
* Update the text of a node element if it has changed.
*
* \param element The node element to update.
* \param text The text to update the element with. The ownership of
* this string is taken by this function and must not be
* referred to after the function exits.
*/
bool tree_update_element_text(struct tree *tree,
struct node_element *element, char *text)
{
const char *node_text; /* existing node text */
 
if (text == NULL)
return false;
 
if (element == NULL) {
free(text);
return false;
}
 
node_text = tree_node_element_get_text(element);
 
if ((node_text == NULL) || (strcmp(node_text, text) != 0)) {
tree_update_node_element(tree, element, text, NULL);
} else {
/* text does not need changing, free it */
free(text);
}
return true;
}
 
 
/**
* Updates the content of a node_element.
*
* \param tree the tree owning element, may be NULL
* \param element the element to be updated
* \param text new text to be set, may be NULL
* \param bitmap new bitmap to be set, may be NULL
*/
void tree_update_node_element(struct tree *tree, struct node_element *element,
const char *text, void *bitmap)
{
node_callback_resp response;
struct node_msg_data msg_data;
bool text_changed = false;
 
assert(element != NULL);
 
if (tree != NULL && element == tree->editing)
tree_stop_edit(tree, false);
 
if (text != NULL && (element->type == NODE_ELEMENT_TEXT ||
element->type == NODE_ELEMENT_TEXT_PLUS_ICON)) {
if (element->text != NULL) {
if(strcmp(element->text, text) == 0) text_changed = true;
 
response = NODE_CALLBACK_NOT_HANDLED;
if (!element->editable &&
element->parent->user_callback !=
NULL) {
msg_data.msg = NODE_DELETE_ELEMENT_TXT;
msg_data.flag = element->flag;
msg_data.node = element->parent;
msg_data.data.text = (void *)element->text;
response = element->parent->user_callback(
element->parent->callback_data,
&msg_data);
}
if (response != NODE_CALLBACK_HANDLED)
free((void *)element->text);
}
element->text = text;
}
 
if (bitmap != NULL && (element->type == NODE_ELEMENT_BITMAP ||
element->type == NODE_ELEMENT_TEXT_PLUS_ICON)) {
if (element->bitmap != NULL) {
response = NODE_CALLBACK_NOT_HANDLED;
if (element->parent->user_callback != NULL) {
msg_data.msg = NODE_DELETE_ELEMENT_IMG;
msg_data.flag = element->flag;
msg_data.node = element->parent;
msg_data.data.bitmap = (void *)element->bitmap;
response = element->parent->user_callback(
element->parent->callback_data,
&msg_data);
}
if (response != NODE_CALLBACK_HANDLED)
free(element->bitmap);
}
else {
/* Increase the box width to accomodate the new icon */
element->box.width += NODE_INSTEP;
}
 
element->bitmap = bitmap;
}
 
tree_handle_node_element_changed(tree, element, text_changed);
}
 
 
/**
* Returns the node element's text
*
* \return the node element's text
*/
const char *tree_node_element_get_text(struct node_element *element)
{
return element->text;
}
 
 
/**
* Get the root node of a tree
*
* \param tree the tree to get the root of
* \return the root of the tree
*/
struct node *tree_get_root(struct tree *tree)
{
return tree->root;
}
 
 
/**
* Returns whether the current tree is being edited at this time
*
* \param tree the tree to be checked
* \return true if the tree is currently being edited
*/
bool tree_is_edited(struct tree *tree)
{
return tree->editing == NULL ? false : true;
}
 
 
/**
* Get the drag state of a tree
*
* \param tree the tree to get the state of
* \return drag type (defined in desktop/tree.h)
*/
tree_drag_type tree_drag_status(struct tree *tree)
{
return tree->drag;
}
 
 
/**
* Get the default node of a tree for additions
*
* \param tree the tree to get the default node of
* \return the default node
*/
struct node *tree_get_default_folder_node(struct tree *tree)
{
if (tree->def_folder != NULL) {
return tree->def_folder;
} else {
return tree_get_root(tree);
}
}
 
 
/**
* Set the default node of a tree to the selected node
*
* \param tree the tree to set the default node of
* \param node the node to set as default (NULL for selected node)
* \return success
*/
bool tree_set_default_folder_node(struct tree *tree, struct node *node)
{
struct node *sel_node;
 
if (node == NULL) {
sel_node = tree_get_selected_node(tree->root);
} else {
sel_node = node;
}
 
if((sel_node == NULL) ||
(tree_node_is_folder(sel_node) == false)) {
return false;
}
 
tree_clear_default_folder_node(tree);
 
tree->def_folder = sel_node;
sel_node->def_folder = true;
tree_handle_node_changed(tree, sel_node, true, false);
 
return true;
}
 
 
/**
* Clear the default node of a tree
*
* \param tree the tree to clear the default node of
*/
void tree_clear_default_folder_node(struct tree *tree)
{
struct node *def_node = NULL;
def_node = tree_get_default_folder_node(tree);
 
if (def_node != NULL) {
tree->def_folder = NULL;
def_node->def_folder = false;
tree_handle_node_changed(tree, def_node, true, false);
}
}
 
 
/**
* Returns the parent of a node
*
* \param node the node to get the parent of
* \return the node's parent
*/
struct node *tree_node_get_parent(struct node *node)
{
return node->parent;
}
 
 
/**
* Returns the first child of a node
*
* \param node the node to get the child of
* \return the nodes first child
*/
struct node *tree_node_get_child(struct node *node)
{
return node->child;
}
 
 
/**
* Returns the closest sibling a node
*
* \param node the node to get the sibling of
* \return the nodes sibling
*/
struct node *tree_node_get_next(struct node *node)
{
return node->next;
}
 
 
/**
* Draws an element's expansion icon
*
* \param tree the tree to draw the expansion for
* \param element the element to draw the expansion for
* \param tree_x X coordinate of the tree
* \param tree_y Y coordinate of the tree
* \param ctx current redraw context
*/
static void tree_draw_node_expansion_toggle(struct tree *tree,
struct node *node, int tree_x, int tree_y,
const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
int x, y;
 
assert(tree != NULL);
assert(node != NULL);
 
if ((node->child != NULL) || (node->data.next != NULL)) {
x = tree_x + node->box.x - (NODE_INSTEP / 2) - 4;
y = tree_y + node->box.y + (TREE_LINE_HEIGHT - 9) / 2;
plot->rectangle(x, y, x + 9, y + 9,
&plot_style_fill_tree_furniture);
plot->rectangle(x , y, x + 8, y + 8,
&plot_style_stroke_tree_furniture);
plot->line(x + 2, y + 4, x + 7, y + 4,
&plot_style_stroke_tree_furniture);
if (!node->expanded)
plot->line(x + 4, y + 2, x + 4, y + 7,
&plot_style_stroke_tree_furniture);
 
}
 
}
 
 
/**
* Draws an element, including any expansion icons
*
* \param tree the tree to draw an element for
* \param element the element to draw
* \param tree_x X coordinate to draw the tree at (wrt plot origin)
* \param tree_y Y coordinate to draw the tree at (wrt plot origin)
* \param clip clipping rectangle (wrt plot origin)
* \param ctx current redraw context
*/
static void tree_draw_node_element(struct tree *tree,
struct node_element *element, int tree_x, int tree_y,
const struct rect *clip, const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
struct bitmap *bitmap = NULL;
int x, y, width;
bool selected = false;
bool def_folder = false;
hlcache_handle *icon;
plot_font_style_t *fstyle;
const int icon_inset = (TREE_LINE_HEIGHT - TREE_ICON_SIZE) / 2;
 
assert(tree != NULL);
assert(element != NULL);
assert(element->parent != NULL);
 
x = tree_x + element->box.x;
y = tree_y + element->box.y;
width = element->box.width;
if (&element->parent->data == element) {
if (element->parent->selected)
selected = true;
if (element->parent->def_folder)
def_folder = true;
}
 
switch (element->type) {
case NODE_ELEMENT_TEXT_PLUS_ICON:
icon = element->bitmap;
if (icon != NULL && (content_get_status(icon) ==
CONTENT_STATUS_READY ||
content_get_status(icon) ==
CONTENT_STATUS_DONE) &&
x + TREE_ICON_SIZE > clip->x0 &&
x < clip->x1) {
struct rect c;
/* Clip to image area */
c.x0 = x;
c.y0 = y + icon_inset;
c.x1 = x + TREE_ICON_SIZE;
c.y1 = y + icon_inset + TREE_ICON_SIZE;
if (c.x0 < clip->x0) c.x0 = clip->x0;
if (c.y0 < clip->y0) c.y0 = clip->y0;
if (c.x1 > clip->x1) c.x1 = clip->x1;
if (c.y1 > clip->y1) c.y1 = clip->y1;
 
if (c.x1 > c.x0 && c.y1 > c.y0) {
/* Valid clip rectangles only */
struct content_redraw_data data;
 
plot->clip(&c);
 
data.x = x;
data.y = y + icon_inset;
data.width = TREE_ICON_SIZE;
data.height = TREE_ICON_SIZE;
 
data.background_colour = 0xFFFFFF;
data.scale = 1;
data.repeat_x = false;
data.repeat_y = false;
 
content_redraw(icon, &data, &c, ctx);
 
/* Restore previous clipping area */
plot->clip(clip);
}
}
 
x += NODE_INSTEP;
width -= NODE_INSTEP;
 
/* fall through */
case NODE_ELEMENT_TEXT:
if (element->text == NULL || clip->x1 < x)
break;
 
if (element == tree->editing)
return;
 
if (selected) {
if (def_folder == true)
fstyle = &plot_fstyle_selected_def_folder;
else
fstyle = &plot_fstyle_selected;
 
plot->rectangle(x, y, x + width,
y + element->box.height,
&plot_style_fill_tree_selected);
} else {
if (def_folder == true)
fstyle = &plot_fstyle_def_folder;
else
fstyle = &plot_fstyle;
}
 
plot->text(x + 4, y + (TREE_LINE_HEIGHT * 3 + 2) / 4,
element->text, strlen(element->text),
fstyle);
break;
case NODE_ELEMENT_BITMAP:
bitmap = element->bitmap;
if (bitmap == NULL)
break;
plot->bitmap(x, y, element->box.width - 1,
element->box.height - 2,
bitmap, 0xFFFFFF, BITMAPF_NONE);
if (!(tree->flags & TREE_NO_FURNITURE))
plot->rectangle(x, y, x + element->box.width - 1,
y + element->box.height - 3,
&plot_style_stroke_tree_furniture);
 
break;
}
 
}
 
 
/**
* Redraws a node.
*
* \param tree the tree to draw
* \param node the node to draw children and siblings of
* \param tree_x X coordinate to draw the tree at (wrt plot origin)
* \param tree_y Y coordinate to draw the tree at (wrt plot origin)
* \param clip clipping rectangle (wrt plot origin)
* \param ctx current redraw context
*/
static void tree_draw_node(struct tree *tree, struct node *node,
int tree_x, int tree_y, struct rect clip,
const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
struct node_element *element;
struct node *parent;
int x0, y0, x1, y1;
struct rect node_extents;
 
assert(tree != NULL);
assert(node != NULL);
 
/* Find node's extents, including children's area */
node_extents.x0 = tree_x + node->box.x - NODE_INSTEP;
node_extents.y0 = tree_y + node->box.y;
node_extents.x1 = tree_x + node->box.x + node->box.width + NODE_INSTEP;
if (node->next != NULL)
node_extents.y1 = tree_y + node->next->box.y;
else
node_extents.y1 = tree_y + node->box.y + node->box.height;
 
/* Nothing to draw, if node is outside clip region */
if ((node_extents.x1 < clip.x0) && (node_extents.y1 < clip.y0) &&
(node_extents.x0 > clip.x1) &&
(node_extents.y0 > clip.y1)) {
return;
}
 
/* Intersect clip region with node's extents */
if (clip.x0 < node_extents.x0) clip.x0 = node_extents.x0;
if (clip.y0 < node_extents.y0) clip.y0 = node_extents.y0;
if (clip.x1 > node_extents.x1) clip.x1 = node_extents.x1;
if (clip.y1 > node_extents.y1) clip.y1 = node_extents.y1;
 
if (clip.x0 >= clip.x1 || clip.y0 >= clip.y1) {
/* Invalid clip rectangle */
return;
}
 
/* Set up the clipping area */
plot->clip(&clip);
 
/* Draw node's furniture */
if (!(tree->flags & TREE_NO_FURNITURE)) {
/* Display furniture */
if (node->previous != NULL) {
/* There is a node above this
* Display furniture; line connecting up to previous */
x0 = x1 = tree_x + node->box.x - (NODE_INSTEP / 2);
y0 = tree_y + node->previous->box.y;
y1 = tree_y + node->box.y + (TREE_LINE_HEIGHT / 2);
plot->line(x0, y0, x1, y1,
&plot_style_stroke_tree_furniture);
}
if (node->next != NULL) {
/* There is a node below this
* Display furniture; line connecting down to next */
x0 = x1 = tree_x + node->box.x - (NODE_INSTEP / 2);
y0 = tree_y + node->box.y + (TREE_LINE_HEIGHT / 2);
y1 = tree_y + node->next->box.y;
plot->line(x0, y0, x1, y1,
&plot_style_stroke_tree_furniture);
}
 
parent = node->parent;
if ((parent != NULL) && (parent != tree->root) &&
(parent->child == node)) {
/* Node is first child */
x0 = x1 = tree_x + parent->box.x + (NODE_INSTEP / 2);
y0 = tree_y + parent->data.box.y +
parent->data.box.height;
y1 = y0 + (TREE_LINE_HEIGHT / 2);
plot->line(x0, y0, x1, y1,
&plot_style_stroke_tree_furniture);
}
/* Line from expansion toggle to icon */
x0 = tree_x + node->box.x - (NODE_INSTEP / 2);
x1 = x0 + (NODE_INSTEP / 2) - 2;
y0 = y1 = tree_y + node->data.box.y + node->data.box.height -
(TREE_LINE_HEIGHT / 2);
plot->line(x0, y0, x1, y1, &plot_style_stroke_tree_furniture);
 
tree_draw_node_expansion_toggle(tree, node,
tree_x, tree_y, ctx);
}
 
/* Draw node's element(s)
* NOTE: node's children are handled later in tree_draw_tree() */
if (node->expanded) {
for (element = &node->data; element != NULL;
element = element->next) {
/* Draw each element of expanded node */
tree_draw_node_element(tree, element, tree_x, tree_y,
&clip, ctx);
}
} else {
/* Draw main title element of node */
tree_draw_node_element(tree, &node->data, tree_x, tree_y,
&clip, ctx);
}
}
 
 
/**
* Redraws a node's descendants.
*
* \param tree the tree to draw
* \param node the node to draw children and siblings of
* \param tree_x X coordinate to draw the tree at (wrt plot origin)
* \param tree_y Y coordinate to draw the tree at (wrt plot origin)
* \param clip clipping rectangle (wrt plot origin)
* \param ctx current redraw context
*/
static void tree_draw_tree(struct tree *tree, struct node *node,
int tree_x, int tree_y, struct rect clip,
const struct redraw_context *ctx)
{
struct node *child;
 
assert(tree != NULL);
assert(node != NULL);
 
for (child = node->child; child != NULL; child = child->next) {
/* Draw children that are inside the clip region */
 
if (child->next != NULL &&
(child->next->box.y + tree_y < clip.y0))
/* Child is above clip region */
continue;
if (child->box.y + tree_y > clip.y1)
/* Child is below clip region
* further siblings will be too */
return;
 
/* Draw current child */
tree_draw_node(tree, child, tree_x, tree_y, clip, ctx);
/* And its children */
if ((child->child != NULL) && (child->expanded)) {
/* Child has children and they are visible */
tree_draw_tree(tree, child, tree_x, tree_y, clip, ctx);
}
}
}
 
 
/**
* Redraws a tree.
*
* \param tree the tree to draw
* \param x X coordinate to draw the tree at (wrt plot origin)
* \param y Y coordinate to draw the tree at (wrt plot origin)
* \param clip_x minimum x of the clipping rectangle (wrt tree origin)
* \param clip_y minimum y of the clipping rectangle (wrt tree origin)
* \param clip_width width of the clipping rectangle
* \param clip_height height of the clipping rectangle
* \param ctx current redraw context
*/
void tree_draw(struct tree *tree, int x, int y,
int clip_x, int clip_y, int clip_width, int clip_height,
const struct redraw_context *ctx)
{
struct redraw_context new_ctx = *ctx;
struct rect clip;
 
assert(tree != NULL);
assert(tree->root != NULL);
 
/* Start knockout rendering if it's available for this plotter */
if (ctx->plot->option_knockout)
knockout_plot_start(ctx, &new_ctx);
 
/* Set up clip rectangle */
clip.x0 = x + clip_x;
clip.y0 = y + clip_y;
clip.x1 = clip.x0 + clip_width;
clip.y1 = clip.y0 + clip_height;
new_ctx.plot->clip(&clip);
 
/* Flat fill extents of clipping area */
new_ctx.plot->rectangle(clip.x0, clip.y0, clip.x1, clip.y1,
&plot_style_fill_tree_background);
 
/* don't draw empty trees or trees with redraw flag set to false */
if (tree->root->child != NULL && tree->redraw) {
 
/* Draw the tree */
tree_draw_tree(tree, tree->root, x, y, clip, &new_ctx);
 
/* Draw textarea, if present */
if (tree->editing != NULL) {
x = x + tree->editing->box.x;
y = y + tree->editing->box.y;
if (tree->editing->type == NODE_ELEMENT_TEXT_PLUS_ICON)
x += NODE_INSTEP;
textarea_redraw(tree->textarea, x, y,
plot_style_fill_tree_background.
fill_colour,
&clip, &new_ctx);
}
}
 
/* Rendering complete */
if (ctx->plot->option_knockout)
knockout_plot_end();
}
 
 
/**
* Finds a node element from a node with a specific user_type
*
* \param node the node to examine
* \param flag user assinged flag used is searches
* \param after if this is not NULL the search will start after the given
* node_element
* \return the corresponding element
*/
struct node_element *tree_node_find_element(struct node *node,
unsigned int flag, struct node_element *after)
{
struct node_element *element;
 
if (after == NULL)
element = &node->data;
else {
assert(after->parent == node);
element = after->next;
}
 
for (; element != NULL; element = element->next)
if (element->flag == flag) return element;
 
return NULL;
}
 
 
/**
* Deletes all selected nodes from the tree.
*
* \param tree the tree to delete from
* \param node the node to delete
*/
void tree_delete_selected_nodes(struct tree *tree, struct node *node)
{
struct node *next;
int y = node->box.y;
int height = tree->height;
int width = tree->width;
bool redraw_setting = tree->redraw;
 
tree->redraw = false;
 
if (node == tree->root) {
if (node->child != NULL)
tree_delete_selected_nodes(tree, node->child);
 
tree->redraw = redraw_setting;
 
if (tree->redraw)
tree->callbacks->redraw_request(0, y,
width, height,
tree->client_data);
return;
}
 
while (node != NULL) {
next = node->next;
if (node->selected)
tree_delete_node(tree, node, false);
else if (node->child != NULL)
tree_delete_selected_nodes(tree, node->child);
node = next;
}
 
tree->redraw = redraw_setting;
 
if (tree->redraw)
tree->callbacks->redraw_request(0, y,
width, height,
tree->client_data);
}
 
 
/**
* Returns the selected node, or NULL if multiple nodes are selected.
*
* \param node the node to search sibling and children
* \return the selected node, or NULL if multiple nodes are selected
*/
struct node *tree_get_selected_node(struct node *node)
{
struct node *result = NULL;
struct node *temp;
 
for (; node != NULL; node = node->next) {
if (node->selected) {
if (result != NULL)
return NULL;
result = node;
}
if ((node->child != NULL) && (node->expanded)) {
temp = tree_get_selected_node(node->child);
if (temp != NULL) {
if (result != NULL)
return NULL;
else
result = temp;
}
}
}
return result;
}
 
 
/**
* Finds a node element at a specific location.
*
* \param node the root node to check from
* \param x the x co-ordinate
* \param y the y co-ordinate
* \param expansion_toggle whether the coordinate was in an expansion toggle
* \return the node at the specified position, or NULL for none
*/
static struct node_element *tree_get_node_element_at(struct node *node,
int x, int y, bool *expansion_toggle)
{
struct node_element *element;
int x0, x1, y0, y1;
 
*expansion_toggle = false;
for (; node != NULL; node = node->next) {
if (node->box.y > y) return NULL;
if ((node->box.x - NODE_INSTEP < x) && (node->box.y < y) &&
(node->box.x + node->box.width >= x) &&
(node->box.y + node->box.height >= y)) {
if (node->expanded) {
for (element = &node->data; element != NULL;
element = element->next) {
x0 = element->box.x;
y0 = element->box.y;
x1 = element->box.x +
element->box.width;
y1 = element->box.y +
element->box.height;
if ((x0 < x) && (y0 < y) && (x1 >= x)
&& (y1 >= y))
return element;
}
} else {
x0 = node->data.box.x;
y0 = node->data.box.y;
x1 = node->data.box.x + node->data.box.width;
y1 = node->data.box.y + node->data.box.height;
if ((x0 < x) && (y0 < y) && (x1 >= x) &&
(y1>= y))
return &node->data;
}
if (((node->child != NULL) ||
(node->data.next != NULL)) &&
(node->data.box.x - NODE_INSTEP + 4 < x)
&& (node->data.box.y + 4 < y) &&
(node->data.box.x > x) &&
(node->data.box.y + TREE_LINE_HEIGHT > y)) {
/* Node either has node children, or node
* has more than one element.
* Coordinate is over node expansion toggle area
*/
*expansion_toggle = true;
return &node->data;
}
}
 
element = tree_get_node_element_at(node->child, x, y,
expansion_toggle);
if ((node->child != NULL) && (node->expanded) &&
(element != NULL))
return element;
}
return NULL;
}
 
 
/**
* Finds a node at a specific location.
*
* \param root the root node to check from
* \param x the x co-ordinate
* \param y the y co-ordinate
* \param expansion_toggle whether the coordinate was in an expansion toggle
* \return the node at the specified position, or NULL for none
*/
static struct node *tree_get_node_at(struct node *root, int x, int y,
bool *expansion_toggle)
{
struct node_element *result;
 
if ((result = tree_get_node_element_at(root, x, y, expansion_toggle)))
return result->parent;
return NULL;
}
 
 
/**
* Gets link characteristics to insert a node at a specified position.
*
* \param tree the tree to find link information for
* \param x the x co-ordinate
* \param y the y co-ordinate
* \param before set to whether the node should be linked before on exit
* \return the node to link with
*/
struct node *tree_get_link_details(struct tree *tree, int x, int y,
bool *before)
{
struct node *node = NULL;
bool expansion_toggle;
 
assert(tree != NULL);
assert(tree->root != NULL);
 
*before = false;
if (tree->root->child != NULL)
node = tree_get_node_at(tree->root->child, x, y,
&expansion_toggle);
if ((node == NULL) || (expansion_toggle))
return tree->root;
 
if (y < (node->box.y + (node->box.height / 2))) {
*before = true;
} else if ((node->folder) && (node->expanded) &&
(node->child != NULL)) {
node = node->child;
*before = true;
}
return node;
}
 
 
/**
* Launches all the selected nodes of the tree
*
* \param tree the tree for which all nodes will be launched
* \param node the node which will be checked together with its children
* \param tabs launch node in a new tab instead of a new window
*/
static void tree_launch_selected_internal(struct tree *tree, struct node *node,
bool tabs)
{
struct node_msg_data msg_data;
 
msg_data.data.bw = NULL;
 
for (; node != NULL; node = node->next) {
if (node->selected && node->user_callback != NULL) {
msg_data.msg = NODE_LAUNCH;
if (tabs == true) {
msg_data.flag = TREE_ELEMENT_LAUNCH_IN_TABS;
} else {
msg_data.flag = TREE_ELEMENT_TITLE;
}
 
msg_data.node = node;
node->user_callback(node->callback_data, &msg_data);
}
if (node->child != NULL)
tree_launch_selected_internal(tree, node->child, tabs);
}
}
 
 
/**
* Launches all the selected nodes of the tree
*
* \param tree the tree for which all nodes will be launched
* \param tabs launch nodes in new tabs instead of new windows
*/
void tree_launch_selected(struct tree *tree, bool tabs)
{
if (tree->root->child != NULL)
tree_launch_selected_internal(tree, tree->root->child, tabs);
}
 
 
/**
* Updates the node at position x,y to a selected state.
* The required areas of the tree are redrawn.
*
* \param tree the tree to update nodes for, may be NULL
* \param x x position in tree
* \param y y position in tree
* \param selected the selection state to set
*/
void tree_set_node_selected_at(struct tree *tree, int x, int y, bool selected)
{
bool expansion_toggle;
struct node *node;
 
node = tree_get_node_at(tree->root, x, y, &expansion_toggle);
 
if ((node == NULL) || (expansion_toggle == true))
return;
 
tree_set_node_selected(tree, node, false, selected);
}
 
 
/**
* Handles a mouse action for a tree
*
* \param tree the tree to handle a click for
* \param mouse the mouse state
* \param x X coordinate of mouse action
* \param y Y coordinate of mouse action
* \return whether the click was handled
*/
bool tree_mouse_action(struct tree *tree, browser_mouse_state mouse, int x,
int y)
{
bool expansion_toggle;
struct node *node;
struct node *last;
struct node_element *element;
struct node_msg_data msg_data;
 
bool double_click_1 = mouse & BROWSER_MOUSE_DOUBLE_CLICK &&
mouse & BROWSER_MOUSE_CLICK_1;
bool double_click_2 = mouse & BROWSER_MOUSE_DOUBLE_CLICK &&
mouse & BROWSER_MOUSE_CLICK_2;
 
assert(tree != NULL);
assert(tree->root != NULL);
 
if (tree->root->child == NULL)
return true;
 
element = tree_get_node_element_at(tree->root->child, x, y,
&expansion_toggle);
 
/* pass in-textarea mouse action and drags which started in it
to the textarea */
if (tree->editing != NULL) {
int x0, x1, y0, y1;
x0 = tree->editing->box.x;
if (tree->editing->type == NODE_ELEMENT_TEXT_PLUS_ICON)
x0 += NODE_INSTEP;
x1 = tree->editing->box.x + tree->editing->box.width;
y0 = tree->editing->box.y;
y1 = tree->editing->box.y + tree->ta_height;
 
if (tree->drag == TREE_TEXTAREA_DRAG &&
(mouse & (BROWSER_MOUSE_HOLDING_1 |
BROWSER_MOUSE_HOLDING_2))) {
/* Track the drag path */
textarea_mouse_action(tree->textarea, mouse,
x - x0, y - y0);
return true;
}
 
if ((x >= x0) && (x < x1) && (y >= y0) && (y < y1)) {
textarea_mouse_action(tree->textarea, mouse,
x - x0, y - y0);
return true;
 
}
}
 
/* we are not interested in the drag path, return */
if (mouse & (BROWSER_MOUSE_HOLDING_1 | BROWSER_MOUSE_HOLDING_2))
return true;
 
/* cancel edit */
if (tree->editing != NULL)
tree_stop_edit(tree, false);
 
/* no item either means cancel selection on (select) click or a drag */
if (element == NULL) {
if (tree->flags & TREE_SINGLE_SELECT) {
tree_set_node_selected(tree, tree->root->child, true,
false);
return true;
}
if (mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_DRAG_1))
tree_set_node_selected(tree, tree->root->child, true,
false);
if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) {
 
/** @todo the tree window has to scroll the tree when
* mouse reaches border while dragging this isn't
* solved for the browser window too.
*/
tree->drag = TREE_SELECT_DRAG;
}
return true;
}
 
node = element->parent;
 
/* A click on expansion toggle or double click on folder toggles node
* expansion */
if (((expansion_toggle) && (mouse & (BROWSER_MOUSE_CLICK_1 |
BROWSER_MOUSE_CLICK_2))) ||
(((!expansion_toggle) && (node->child != NULL)) &&
(double_click_1 || double_click_2))) {
 
/* clear any selection */
tree_set_node_selected(tree, tree->root->child, true, false);
 
/* expand / contract node and redraw */
tree_set_node_expanded(tree, node, !node->expanded,
false, false);
 
/* find the last child node if expanded */
last = node;
if ((last->child != NULL) && (last->expanded)) {
last = last->child;
while ((last->next != NULL) ||
((last->child != NULL) &&
(last->expanded))) {
if (last->next != NULL)
last = last->next;
else
last = last->child;
}
}
/* scroll to the bottom element then back to the top */
element = &last->data;
if (last->expanded)
for (; element->next != NULL; element = element->next);
tree->callbacks->scroll_visible(element->box.y,
element->box.height,
tree->client_data);
tree->callbacks->scroll_visible(node->data.box.y,
node->data.box.height,
tree->client_data);
return true;
}
 
/* no use for any other expansion toggle click */
if (expansion_toggle)
return true;
 
/* single/double ctrl+click or alt+click starts editing */
if ((element->editable) && (!tree->editing) &&
((element->type == NODE_ELEMENT_TEXT) ||
(element->type == NODE_ELEMENT_TEXT_PLUS_ICON)) &&
(mouse & BROWSER_MOUSE_CLICK_1 || double_click_1) &&
(mouse & BROWSER_MOUSE_MOD_2 ||
mouse & BROWSER_MOUSE_MOD_3)) {
tree_set_node_selected(tree, tree->root->child, true, false);
tree_start_edit(tree, element);
return true;
}
 
/* double click launches the leaf */
if (double_click_1 || double_click_2) {
if (node->user_callback == NULL)
return false;
msg_data.msg = NODE_LAUNCH;
msg_data.flag = TREE_ELEMENT_TITLE;
msg_data.node = node;
if (node->user_callback(node->callback_data, &msg_data) !=
NODE_CALLBACK_HANDLED)
return false;
 
return true;
}
 
/* single click (select) cancels current selection and selects item */
if (mouse & BROWSER_MOUSE_CLICK_1 || (mouse & BROWSER_MOUSE_CLICK_2 &&
tree->flags & TREE_SINGLE_SELECT)) {
if (tree->flags & TREE_NO_SELECT)
return true;
if (!node->selected) {
tree_set_node_selected(tree, tree->root->child, true,
false);
node->selected = true;
tree_handle_node_element_changed(tree, &node->data, false);
}
return true;
}
 
/* single click (adjust) toggles item selection */
if (mouse & BROWSER_MOUSE_CLICK_2) {
if (tree->flags & TREE_NO_SELECT)
return true;
node->selected = !node->selected;
tree_handle_node_element_changed(tree, &node->data, false);
return true;
}
 
/* drag starts a drag operation */
if ((!tree->editing) && (mouse & (BROWSER_MOUSE_DRAG_1 |
BROWSER_MOUSE_DRAG_2))) {
if (tree->flags & TREE_NO_DRAGS)
return true;
 
if (!node->selected) {
tree_set_node_selected(tree, tree->root->child, true,
false);
node->selected = true;
tree_handle_node_element_changed(tree, &node->data, false);
}
 
if (tree->flags & TREE_MOVABLE)
tree->drag = TREE_MOVE_DRAG;
else tree->drag = TREE_UNKNOWN_DRAG;
 
return true;
}
 
 
return false;
}
 
 
/**
* Updates the selected state for a region of nodes.
*
* \param tree the tree to update
* \param node the node to update children and siblings of
* \param y the minimum y of the selection rectangle
* \param height the height of the selection rectangle
* \param invert whether to invert the selected state
*/
static void tree_handle_selection_area_node(struct tree *tree,
struct node *node, int y, int height, bool invert)
{
struct node_element *element;
struct node *update;
int y_max;
int y0, y1;
 
assert(tree != NULL);
assert(node != NULL);
 
y_max = y + height;
 
for (; node != NULL; node = node->next) {
if (node->box.y > y_max) return;
y0 = node->box.y;
y1 = node->box.y + node->box.height;
if ((y0 < y_max) && (y1 >= y)) {
update = NULL;
if (node->expanded) {
for (element = &node->data; element != NULL;
element = element->next) {
y0 = element->box.y;
y1 = element->box.y +
element->box.height;
if ((y0 < y_max) && (y1 >= y)) {
update = element->parent;
break;
}
}
} else {
y0 = node->data.box.y;
y1 = node->data.box.y + node->data.box.height;
if ((y0 < y_max) && (y1 >= y))
update = node->data.parent;
}
if ((update) && (node != tree->root)) {
if (invert) {
node->selected = !node->selected;
tree_handle_node_element_changed(tree,
&node->data, false);
} else if (!node->selected) {
node->selected = true;
tree_handle_node_element_changed(tree,
&node->data, false);
}
}
}
if ((node->child != NULL) && (node->expanded))
tree_handle_selection_area_node(tree, node->child, y,
height, invert);
}
}
 
 
/**
* Updates the selected state for a region of nodes.
*
* \param tree the tree to update
* \param y the minimum y of the selection rectangle
* \param height the height of the selection rectangle
* \param invert whether to invert the selected state
*/
static void tree_handle_selection_area(struct tree *tree, int y, int height,
bool invert)
{
assert(tree != NULL);
assert(tree->root != NULL);
 
if (tree->root->child == NULL)
return;
 
if (height < 0) {
y += height;
height = -height;
}
tree_handle_selection_area_node(tree, tree->root->child, y, height,
invert);
}
 
 
/**
* Clears the processing flag.
*
* \param node the node to process siblings and children of
*/
static void tree_clear_processing(struct node *node)
{
for (; node != NULL; node = node->next) {
node->processing = false;
if (node->child != NULL)
tree_clear_processing(node->child);
}
}
 
 
/**
* Sets the processing flag to the selection state.
*
* \param node the node to process siblings and children of
*/
static void tree_selected_to_processing(struct node *node)
{
for (; node != NULL; node = node->next) {
node->processing = node->selected;
if ((node->child != NULL) && (node->expanded))
tree_selected_to_processing(node->child);
}
}
 
 
/**
* Moves the first node in a tree with the processing flag set.
*
* \param tree the tree in which the move takes place
* \param node the node to move siblings/children of
* \param link the node to link before/as a child (folders) or before/after
* (link)
* \param before whether to link siblings before or after the supplied node
* \param first whether to always link after the supplied node (ie not
* inside of folders)
* \return the node moved
*/
static struct node *tree_move_processing_node(struct tree *tree,
struct node *node, struct node *link, bool before, bool first)
{
struct node *result;
 
bool folder = link->folder;
for (; node != NULL; node = node->next) {
if (node->processing) {
node->processing = false;
tree_delink_node(tree, node);
if (!first)
link->folder = false;
tree_link_node(tree, link, node, before);
if (!first)
link->folder = folder;
return node;
}
if (node->child != NULL) {
result = tree_move_processing_node(tree, node->child,
link, before, first);
if (result != NULL)
return result;
}
}
return NULL;
}
 
 
/**
* Moves nodes within a tree.
*
* \param tree the tree to process
* \param destination the node to link before/as a child (folders)
* or before/after (link)
* \param before whether to link siblings before or after the supplied
* node
*/
static void tree_move_selected_nodes(struct tree *tree,
struct node *destination, bool before)
{
struct node *link;
struct node *test;
bool error;
 
tree_clear_processing(tree->root);
tree_selected_to_processing(tree->root);
 
/* the destination node cannot be a child of any node with
the processing flag set */
error = destination->processing;
for (test = destination; test != NULL; test = test->parent)
error |= test->processing;
if (error) {
tree_clear_processing(tree->root);
return;
}
if ((destination->folder) && (!destination->expanded) && (!before)) {
tree_set_node_expanded(tree, destination, true, false, false);
}
link = tree_move_processing_node(tree, tree->root, destination, before,
true);
while (link != NULL)
link = tree_move_processing_node(tree, tree->root, link, false,
false);
 
tree_clear_processing(tree->root);
tree_recalculate_node_positions(tree, tree->root);
if (tree->redraw)
tree->callbacks->redraw_request(0, 0, tree->width, tree->height,
tree->client_data);
}
 
 
/**
* Handle the end of a drag operation
*
* \param tree the tree on which the drag was performed
* \param mouse mouse state during drag end
* \param x0 x coordinate of drag start
* \param y0 y coordinate of drag start
* \param x1 x coordinate of drag end
* \param y1 y coordinate of drag end
*/
void tree_drag_end(struct tree *tree, browser_mouse_state mouse, int x0, int y0,
int x1, int y1)
{
 
bool before;
struct node *node;
int x, y;
 
switch (tree->drag) {
case TREE_NO_DRAG:
case TREE_UNKNOWN_DRAG:
break;
 
case TREE_TEXTAREA_DRAG:
x = tree->editing->box.x;
y = tree->editing->box.y;
if (tree->editing->type == NODE_ELEMENT_TEXT_PLUS_ICON)
x += NODE_INSTEP;
textarea_mouse_action(tree->textarea, BROWSER_MOUSE_HOVER,
x1 - x, y1 - y);
break;
 
case TREE_SELECT_DRAG:
tree_handle_selection_area(tree, y0, y1 - y0,
(mouse | BROWSER_MOUSE_HOLDING_2));
break;
 
case TREE_MOVE_DRAG:
if (!(tree->flags & TREE_MOVABLE))
return;
node = tree_get_link_details(tree, x1, y1, &before);
tree_move_selected_nodes(tree, node, before);
break;
}
 
tree->drag = TREE_NO_DRAG;
}
 
 
/**
* Key press handling for a tree.
*
* \param tree The tree which got the keypress
* \param key The ucs4 character codepoint
* \return true if the keypress is dealt with, false otherwise.
*/
bool tree_keypress(struct tree *tree, uint32_t key)
{
if (tree->editing != NULL)
switch (key) {
case KEY_ESCAPE:
tree_stop_edit(tree, false);
return true;
case KEY_NL:
case KEY_CR:
tree_stop_edit(tree, true);
return true;
default:
return textarea_keypress(tree->textarea, key);
}
 
return false;
}
 
 
/**
* Alphabetical comparison function for nodes
*
* \param n1 first node to compare
* \param n2 first node to compare
* \return 0 if equal, greater then zero if n1 > n2,
* less then zero if n2 < n1
*/
int tree_alphabetical_sort(struct node *n1, struct node *n2)
{
return strcmp(n1->data.text, n2->data.text);
}
 
 
/**
* Redraw requests from the textarea are piped through this because we have to
* check the redraw flag of the tree before requesting a redraw and change the
* position to tree origin relative.
*/
 
static void tree_textarea_callback(void *data, struct textarea_msg *msg)
{
struct tree *tree = data;
int x, y;
 
switch (msg->type) {
case TEXTAREA_MSG_DRAG_REPORT:
if (msg->data.drag == TEXTAREA_DRAG_NONE) {
/* Textarea drag finished */
tree->drag = TREE_NO_DRAG;
} else {
/* Textarea drag started */
tree->drag = TREE_TEXTAREA_DRAG;
}
break;
 
case TEXTAREA_MSG_REDRAW_REQUEST:
x = msg->data.redraw.x0 + tree->editing->box.x;
y = msg->data.redraw.y0 + tree->editing->box.y;
 
if (tree->editing->type == NODE_ELEMENT_TEXT_PLUS_ICON)
x += NODE_INSTEP;
 
/* Redraw the textarea */
if (tree->redraw)
tree->callbacks->redraw_request(x, y,
msg->data.redraw.x1 -
msg->data.redraw.x0,
msg->data.redraw.y1 -
msg->data.redraw.y0,
tree->client_data);
break;
 
default:
break;
}
}
 
 
/**
* Starts editing a node_element
*
* \param tree The tree to which element belongs
* \param element The element to start being edited
*/
void tree_start_edit(struct tree *tree, struct node_element *element)
{
struct node *parent;
int width, height;
textarea_setup ta_setup;
 
assert(tree != NULL);
assert(element != NULL);
 
if (tree->editing != NULL)
tree_stop_edit(tree, true);
 
parent = element->parent;
if (&parent->data == element)
parent = parent->parent;
for (; parent != NULL; parent = parent->parent) {
if (!parent->expanded) {
tree_set_node_expanded(tree, parent, true,
false, false);
}
}
 
tree->editing = element;
tree->callbacks->get_window_dimensions(&width, NULL, tree->client_data);
width -= element->box.x;
height = element->box.height;
if (element->type == NODE_ELEMENT_TEXT_PLUS_ICON)
width -= NODE_INSTEP;
 
tree->ta_height = height;
 
ta_setup.flags = TEXTAREA_INTERNAL_CARET;
ta_setup.width = width;
ta_setup.height = tree->ta_height;
ta_setup.pad_top = 0;
ta_setup.pad_right = 4;
ta_setup.pad_bottom = 0;
ta_setup.pad_left = 4;
ta_setup.border_width = 1;
ta_setup.border_col = 0x000000;
ta_setup.selected_text = 0xffffff;
ta_setup.selected_bg = 0x000000;
ta_setup.text = plot_fstyle;
ta_setup.text.foreground = 0x000000;
ta_setup.text.background = 0xffffff;
 
tree->textarea = textarea_create(&ta_setup,
tree_textarea_callback, tree);
if (tree->textarea == NULL) {
tree_stop_edit(tree, false);
return;
}
textarea_set_text(tree->textarea, element->text);
 
tree_handle_node_element_changed(tree, element, true);
tree_recalculate_size(tree);
tree->callbacks->scroll_visible(element->box.y, element->box.height,
tree->client_data);
}
 
 
/**
* Callback for fetchcache(). Should be removed once bitmaps get loaded directly
* from disc
*/
static nserror tree_icon_callback(hlcache_handle *handle,
const hlcache_event *event, void *pw)
{
return NSERROR_OK;
}
 
 
/**
* Tree utility function. Placed here so that this code doesn't have to be
* copied by each user.
*
* \param name the name of the loaded icon, if it's not a full path the icon is
* looked for in the directory specified by tree_icons_dir
* \return the icon in form of a content or NULL on failure
*/
hlcache_handle *tree_load_icon(const char *name)
{
char *url = NULL;
const char *icon_url = NULL;
int len;
hlcache_handle *c;
nserror err;
nsurl *icon_nsurl;
 
/** @todo something like bitmap_from_disc is needed here */
 
if (!strncmp(name, "file://", 7)) {
icon_url = name;
} else {
char *native_path;
 
if (tree_icons_dir == NULL)
return NULL;
 
/* path + separator + leafname + '\0' */
len = strlen(tree_icons_dir) + 1 + strlen(name) + 1;
native_path = malloc(len);
if (native_path == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
return NULL;
}
 
/* Build native path */
memcpy(native_path, tree_icons_dir,
strlen(tree_icons_dir) + 1);
path_add_part(native_path, len, name);
 
/* Convert native path to URL */
url = path_to_url(native_path);
 
free(native_path);
icon_url = url;
}
 
err = nsurl_create(icon_url, &icon_nsurl);
if (err != NSERROR_OK) {
if (url != NULL)
free(url);
return NULL;
}
 
/* Fetch the icon */
err = hlcache_handle_retrieve(icon_nsurl, 0, 0, 0,
tree_icon_callback, 0, 0,
CONTENT_IMAGE, &c);
 
nsurl_unref(icon_nsurl);
 
/* If we built the URL here, free it */
if (url != NULL)
free(url);
 
if (err != NSERROR_OK) {
return NULL;
}
 
return c;
}
/programs/network/netsurf/netsurf/desktop/tree.h
0,0 → 1,211
/*
* Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Generic tree handling (interface).
*/
 
#ifndef _NETSURF_DESKTOP_TREE_H_
#define _NETSURF_DESKTOP_TREE_H_
 
#include <stdbool.h>
#include <stdint.h>
 
#include "desktop/browser.h"
#include "image/bitmap.h"
 
struct hlcache_handle;
 
/* Tree flags */
enum tree_flags {
TREE_NO_FLAGS = 0,
TREE_NO_DRAGS = 1,
TREE_NO_FURNITURE = 2,
TREE_SINGLE_SELECT = 4,
TREE_NO_SELECT = 8,
TREE_MOVABLE = 16,
TREE_DELETE_EMPTY_DIRS = 32, /**< if the last child of a
* directory is deleted the
* directory will be deleted
* too.
*/
};
 
/** A "flag" value to indicate the element data contains title
* text. This value should be the first node_element in every
* node. All other values should be different than this one. The term
* flag is misused as it is actually a value used by the API consumer
* to indicate teh type of data a node element contains.
*/
#define TREE_ELEMENT_TITLE 0x00
#define TREE_ELEMENT_LAUNCH_IN_TABS 0x05 /* Launch in tabs instead of windows */
 
struct tree;
struct node;
struct node_element;
 
typedef enum {
TREE_NO_DRAG = 0,
TREE_SELECT_DRAG,
TREE_MOVE_DRAG,
TREE_TEXTAREA_DRAG, /** < A drag that is passed to a textarea */
TREE_UNKNOWN_DRAG /** < A drag the tree itself won't handle */
} tree_drag_type;
 
typedef enum {
NODE_ELEMENT_TEXT, /**< Text only */
NODE_ELEMENT_TEXT_PLUS_ICON, /**< Text and icon */
NODE_ELEMENT_BITMAP /**< Bitmap only */
} node_element_type;
 
typedef enum {
NODE_DELETE_ELEMENT_TXT, /**< The text of an element of the
* node is being deleted */
NODE_DELETE_ELEMENT_IMG, /**< The bitmap or icon of a node is
* being deleted */
NODE_LAUNCH, /**< The node has been launched */
NODE_ELEMENT_EDIT_CANCELLED, /**< Editing opperation cancelled. */
NODE_ELEMENT_EDIT_FINISHING, /**< New text has to be accepted
* or rejected. */
NODE_ELEMENT_EDIT_FINISHED /**< Editing of a node_element has
* been finished. */
} node_msg;
 
typedef enum {
NODE_CALLBACK_HANDLED,
NODE_CALLBACK_NOT_HANDLED,
NODE_CALLBACK_REJECT, /**< reject new text for node element
* and leave editing mode. */
NODE_CALLBACK_CONTINUE /**< don't leave editig mode. */
} node_callback_resp;
 
/** Internal node message. */
struct node_msg_data {
node_msg msg; /**< The type of message. */
unsigned int flag; /**< message flags. */
struct node *node; /**< tree node messsage concerns. */
union {
char *text; /**< textural data. */
void *bitmap; /**< bitmap data. */
struct browser_window *bw; /**< clone browser_window. */
} data; /**< The message data. */
};
 
/** callbacks to perform necessary operations on treeview. */
struct treeview_table {
void (*redraw_request)(int x, int y, int width, int height,
void *data); /**< request a redraw. */
void (*resized)(struct tree *tree, int width, int height,
void *data); /**< resize treeview area. */
void (*scroll_visible)(int y, int height, void *data); /**< scroll visible treeview area. */
void (*get_window_dimensions)(int *width, int *height, void *data); /**< get dimensions of window */
};
 
/**
* Informs the client about any events requiring his action
*
* \param user_data the user data which was passed at tree creation
* \param msg_data structure containing all the message information
* \return the appropriate node_callback_resp response
*/
typedef node_callback_resp (*tree_node_user_callback)(void *user_data,
struct node_msg_data *msg_data);
 
/* Non-platform specific code */
 
void tree_set_icon_dir(char *icon_dir);
void tree_setup_colours(void);
 
/* Functions for creating/deleting tree primitives and for tree structure
manipulation */
struct tree *tree_create(unsigned int flags,
const struct treeview_table *callbacks,
void *client_data);
struct node *tree_create_folder_node(struct tree *tree, struct node *parent,
const char *title, bool editable, bool retain_in_memory,
bool deleted);
struct node *tree_create_leaf_node(struct tree *tree, struct node *parent,
const char *title, bool editable, bool retain_in_memory,
bool deleted);
struct node_element *tree_create_node_element(struct node *parent,
node_element_type type, unsigned int flag, bool editable);
void tree_link_node(struct tree *tree, struct node *link, struct node *node,
bool before);
void tree_delink_node(struct tree *tree, struct node *node);
void tree_delete(struct tree *tree);
void tree_delete_node(struct tree *tree, struct node *node, bool siblings);
 
/* setters and getters for properties and data */
void tree_set_node_icon(struct tree *tree, struct node *node,
struct hlcache_handle *icon);
void tree_set_node_expanded(struct tree *tree, struct node *node, bool expanded,
bool folder, bool leaf);
void tree_set_node_selected(struct tree *tree, struct node *node, bool all,
bool selected);
void tree_set_node_selected_at(struct tree *tree, int x, int y, bool selected);
void tree_set_node_sort_function(struct tree *tree, struct node *node,
int (*sort) (struct node *, struct node *));
void tree_set_node_user_callback(struct node *node,
tree_node_user_callback callback, void *data);
void tree_set_redraw(struct tree *tree, bool redraw);
bool tree_get_redraw(struct tree *tree);
bool tree_node_has_selection(struct node *node);
bool tree_node_is_deleted(struct node *node);
bool tree_node_is_folder(struct node *node);
bool tree_node_is_default(struct node *node);
void tree_update_node_element(struct tree *tree, struct node_element *element,
const char *text, void *bitmap);
bool tree_update_element_text(struct tree *tree, struct node_element *element, char *text);
const char *tree_node_element_get_text(struct node_element *element);
struct node *tree_get_root(struct tree *tree);
bool tree_is_edited(struct tree *tree);
tree_drag_type tree_drag_status(struct tree *tree);
 
struct node *tree_get_default_folder_node(struct tree *tree);
bool tree_set_default_folder_node(struct tree *tree, struct node *node);
void tree_clear_default_folder_node(struct tree *tree);
 
/* functions for traversing the tree */
struct node *tree_node_get_parent(struct node *node);
struct node *tree_node_get_child(struct node *node);
struct node *tree_node_get_next(struct node *node);
 
void tree_draw(struct tree *tree, int x, int y,
int clip_x, int clip_y, int clip_width, int clip_height,
const struct redraw_context *ctx);
 
struct node_element *tree_node_find_element(struct node *node,
unsigned int flag, struct node_element *after);
void tree_delete_selected_nodes(struct tree *tree, struct node *node);
struct node *tree_get_selected_node(struct node *node);
struct node *tree_get_link_details(struct tree *tree, int x, int y,
bool *before);
void tree_launch_selected(struct tree *tree, bool tabs);
 
bool tree_mouse_action(struct tree *tree, browser_mouse_state mouse,
int x, int y);
void tree_drag_end(struct tree *tree, browser_mouse_state mouse, int x0, int y0,
int x1, int y1);
bool tree_keypress(struct tree *tree, uint32_t key);
 
int tree_alphabetical_sort(struct node *, struct node *);
void tree_start_edit(struct tree *tree, struct node_element *element);
struct hlcache_handle *tree_load_icon(const char *name);
 
#endif
/programs/network/netsurf/netsurf/desktop/tree_url_node.c
0,0 → 1,936
/*
* Copyright 2005 Richard Wilson <info@tinct.net>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Creation of URL nodes with use of trees (implementation)
*/
 
 
#include <assert.h>
#include <ctype.h>
 
#include <dom/dom.h>
#include <dom/bindings/hubbub/parser.h>
 
#include "content/content.h"
#include "content/hlcache.h"
#include "content/urldb.h"
#include "desktop/browser.h"
#include "desktop/options.h"
#include "desktop/tree_url_node.h"
#include "utils/corestrings.h"
#include "utils/libdom.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/utf8.h"
#include "utils/utils.h"
 
/** Flags for each type of url tree node. */
enum tree_element_url {
TREE_ELEMENT_URL = 0x01,
TREE_ELEMENT_LAST_VISIT = 0x02,
TREE_ELEMENT_VISITS = 0x03,
TREE_ELEMENT_THUMBNAIL = 0x04,
};
 
#define MAX_ICON_NAME_LEN 256
 
static bool initialised = false;
 
static hlcache_handle *folder_icon;
 
struct icon_entry {
content_type type;
hlcache_handle *icon;
};
 
struct icon_entry icon_table[] = {
{CONTENT_HTML, NULL},
{CONTENT_TEXTPLAIN, NULL},
{CONTENT_CSS, NULL},
{CONTENT_IMAGE, NULL},
{CONTENT_NONE, NULL},
 
/* this serves as a sentinel */
{CONTENT_HTML, NULL}
};
 
static uint32_t tun_users = 0;
 
void tree_url_node_init(const char *folder_icon_name)
{
struct icon_entry *entry;
char icon_name[MAX_ICON_NAME_LEN];
tun_users++;
if (initialised)
return;
initialised = true;
 
folder_icon = tree_load_icon(folder_icon_name);
 
entry = icon_table;
do {
 
tree_icon_name_from_content_type(icon_name, entry->type);
entry->icon = tree_load_icon(icon_name);
 
++entry;
} while (entry->type != CONTENT_HTML);
}
 
 
void tree_url_node_cleanup()
{
struct icon_entry *entry;
tun_users--;
if (tun_users > 0)
return;
if (!initialised)
return;
initialised = false;
hlcache_handle_release(folder_icon);
entry = icon_table;
do {
hlcache_handle_release(entry->icon);
++entry;
} while (entry->type != CONTENT_HTML);
}
 
/**
* Creates a tree entry for a URL, and links it into the tree
*
* \param parent the node to link to
* \param url the URL (copied)
* \param data the URL data to use
* \param title the custom title to use
* \return the node created, or NULL for failure
*/
struct node *tree_create_URL_node(struct tree *tree, struct node *parent,
nsurl *url, const char *title,
tree_node_user_callback user_callback, void *callback_data)
{
struct node *node;
struct node_element *element;
char *text_cp, *squashed;
 
squashed = squash_whitespace(title ? title : nsurl_access(url));
text_cp = strdup(squashed);
if (text_cp == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
return NULL;
}
free(squashed);
node = tree_create_leaf_node(tree, parent, text_cp, true, false,
false);
if (node == NULL) {
free(text_cp);
return NULL;
}
 
if (user_callback != NULL)
tree_set_node_user_callback(node, user_callback,
callback_data);
 
tree_create_node_element(node, NODE_ELEMENT_BITMAP,
TREE_ELEMENT_THUMBNAIL, false);
tree_create_node_element(node, NODE_ELEMENT_TEXT, TREE_ELEMENT_VISITS,
false);
tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_LAST_VISIT, false);
element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_URL, true);
if (element != NULL) {
text_cp = strdup(nsurl_access(url));
if (text_cp == NULL) {
tree_delete_node(tree, node, false);
LOG(("malloc failed"));
warn_user("NoMemory", 0);
return NULL;
}
tree_update_node_element(tree, element, text_cp, NULL);
}
 
return node;
}
 
 
/**
* Creates a read only tree entry for a URL, and links it into the tree.
*
* \param parent the node to link to
* \param url the URL
* \param data the URL data to use
* \return the node created, or NULL for failure
*/
struct node *tree_create_URL_node_readonly(struct tree *tree,
struct node *parent, nsurl *url,
const struct url_data *data,
tree_node_user_callback user_callback, void *callback_data)
{
struct node *node;
struct node_element *element;
char *title;
 
assert(url && data);
 
if (data->title != NULL) {
title = strdup(data->title);
} else {
title = strdup(nsurl_access(url));
}
 
if (title == NULL)
return NULL;
 
node = tree_create_leaf_node(tree, parent, title, false, false, false);
if (node == NULL) {
free(title);
return NULL;
}
 
if (user_callback != NULL) {
tree_set_node_user_callback(node, user_callback,
callback_data);
}
 
tree_create_node_element(node, NODE_ELEMENT_BITMAP,
TREE_ELEMENT_THUMBNAIL, false);
tree_create_node_element(node, NODE_ELEMENT_TEXT, TREE_ELEMENT_VISITS,
false);
tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_LAST_VISIT, false);
element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_URL, false);
if (element != NULL) {
tree_update_node_element(tree, element, nsurl_access(url),
NULL);
}
 
tree_update_URL_node(tree, node, url, data);
 
return node;
}
 
 
/**
* Updates the node details for a URL node.
*
* \param node the node to update
*/
void tree_update_URL_node(struct tree *tree, struct node *node,
nsurl *url, const struct url_data *data)
{
struct node_element *element;
struct bitmap *bitmap = NULL;
struct icon_entry *entry;
char *text_cp;
 
assert(node != NULL);
 
element = tree_node_find_element(node, TREE_ELEMENT_URL, NULL);
if (element == NULL)
return;
 
if (data != NULL) {
if (data->title == NULL)
urldb_set_url_title(url, nsurl_access(url));
 
if (data->title == NULL)
return;
 
element = tree_node_find_element(node, TREE_ELEMENT_TITLE,
NULL);
text_cp = strdup(data->title);
if (text_cp == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
return;
}
tree_update_node_element(tree, element, text_cp, NULL);
} else {
data = urldb_get_url_data(url);
if (data == NULL)
return;
}
 
entry = icon_table;
do {
if (entry->type == data->type) {
if (entry->icon != NULL)
tree_set_node_icon(tree, node, entry->icon);
break;
}
++entry;
} while (entry->type != CONTENT_HTML);
 
/* update last visit text */
element = tree_node_find_element(node, TREE_ELEMENT_LAST_VISIT, element);
tree_update_element_text(tree,
element,
messages_get_buff("TreeLast",
(data->last_visit > 0) ?
ctime((time_t *)&data->last_visit) :
messages_get("TreeUnknown")));
 
 
/* update number of visits text */
element = tree_node_find_element(node, TREE_ELEMENT_VISITS, element);
tree_update_element_text(tree,
element,
messages_get_buff("TreeVisits", data->visits));
 
 
/* update thumbnail */
element = tree_node_find_element(node, TREE_ELEMENT_THUMBNAIL, element);
if (element != NULL) {
bitmap = urldb_get_thumbnail(url);
 
if (bitmap != NULL) {
tree_update_node_element(tree, element, NULL, bitmap);
}
}
}
 
 
const char *tree_url_node_get_title(struct node *node)
{
struct node_element *element;
element = tree_node_find_element(node, TREE_ELEMENT_TITLE, NULL);
if (element == NULL)
return NULL;
return tree_node_element_get_text(element);
}
 
 
const char *tree_url_node_get_url(struct node *node)
{
struct node_element *element;
element = tree_node_find_element(node, TREE_ELEMENT_URL, NULL);
if (element == NULL)
return NULL;
return tree_node_element_get_text(element);
}
 
void tree_url_node_edit_title(struct tree *tree, struct node *node)
{
struct node_element *element;
element = tree_node_find_element(node, TREE_ELEMENT_TITLE, NULL);
tree_start_edit(tree, element);
}
 
void tree_url_node_edit_url(struct tree *tree, struct node *node)
{
struct node_element *element;
element = tree_node_find_element(node, TREE_ELEMENT_URL, NULL);
tree_start_edit(tree, element);
}
 
node_callback_resp tree_url_node_callback(void *user_data,
struct node_msg_data *msg_data)
{
struct tree *tree;
struct node_element *element;
nsurl *nsurl;
nserror error;
const char *text;
char *norm_text;
const struct url_data *data;
 
/** @todo memory leaks on non-shared folder deletion. */
switch (msg_data->msg) {
case NODE_DELETE_ELEMENT_TXT:
switch (msg_data->flag) {
/* only history is using non-editable url
* elements so only history deletion will run
* this code
*/
case TREE_ELEMENT_URL:
/* reset URL characteristics */
error = nsurl_create(msg_data->data.text, &nsurl);
if (error != NSERROR_OK) {
warn_user("NoMemory", 0);
return NODE_CALLBACK_REJECT;
}
urldb_reset_url_visit_data(nsurl);
nsurl_unref(nsurl);
return NODE_CALLBACK_HANDLED;
case TREE_ELEMENT_TITLE:
return NODE_CALLBACK_HANDLED;
}
break;
case NODE_DELETE_ELEMENT_IMG:
if (msg_data->flag == TREE_ELEMENT_THUMBNAIL ||
msg_data->flag == TREE_ELEMENT_TITLE)
return NODE_CALLBACK_HANDLED;
break;
case NODE_LAUNCH:
element = tree_node_find_element(msg_data->node,
TREE_ELEMENT_URL, NULL);
if (element != NULL) {
text = tree_node_element_get_text(element);
if (msg_data->flag == TREE_ELEMENT_LAUNCH_IN_TABS) {
msg_data->data.bw = browser_window_create(text,
msg_data->data.bw, 0, true, true);
} else {
browser_window_create(text, NULL, 0,
true, false);
}
return NODE_CALLBACK_HANDLED;
}
break;
case NODE_ELEMENT_EDIT_FINISHING:
 
text = msg_data->data.text;
 
if (msg_data->flag == TREE_ELEMENT_URL) {
size_t len;
error = nsurl_create(text, &nsurl);
if (error != NSERROR_OK) {
warn_user("NoMemory", 0);
return NODE_CALLBACK_REJECT;
}
error = nsurl_get(nsurl, NSURL_WITH_FRAGMENT,
&norm_text, &len);
if (error != NSERROR_OK) {
warn_user("NoMemory", 0);
return NODE_CALLBACK_REJECT;
}
 
msg_data->data.text = norm_text;
 
data = urldb_get_url_data(nsurl);
if (data == NULL) {
urldb_add_url(nsurl);
urldb_set_url_persistence(nsurl, true);
data = urldb_get_url_data(nsurl);
if (data == NULL) {
nsurl_unref(nsurl);
return NODE_CALLBACK_REJECT;
}
}
tree = user_data;
tree_update_URL_node(tree, msg_data->node,
nsurl, NULL);
nsurl_unref(nsurl);
}
else if (msg_data->flag == TREE_ELEMENT_TITLE) {
while (isspace(*text))
text++;
norm_text = strdup(text);
if (norm_text == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
return NODE_CALLBACK_REJECT;
}
/* don't allow zero length entry text, return
false */
if (norm_text[0] == '\0') {
warn_user("NoNameError", 0);
msg_data->data.text = NULL;
return NODE_CALLBACK_CONTINUE;
}
msg_data->data.text = norm_text;
}
 
return NODE_CALLBACK_HANDLED;
default:
break;
}
return NODE_CALLBACK_NOT_HANDLED;
}
 
typedef struct {
struct tree *tree;
struct node *directory;
tree_node_user_callback callback;
void *callback_data;
bool last_was_h4;
dom_string *title;
} tree_url_load_ctx;
 
static void tree_url_load_directory(dom_node *ul, tree_url_load_ctx *ctx);
 
/**
* Parse an entry represented as a li.
*
* \param li DOM node for parsed li
* \param directory directory to add this entry to
*/
static void tree_url_load_entry(dom_node *li, tree_url_load_ctx *ctx)
{
dom_node *a;
dom_string *title1;
dom_string *url1;
char *title, *url2;
nsurl *url;
const struct url_data *data;
struct node *entry;
dom_exception derror;
nserror error;
 
/* The li must contain an "a" element */
a = libdom_find_first_element(li, corestring_lwc_a);
if (a == NULL) {
warn_user("TreeLoadError", "(Missing <a> in <li>)");
return;
}
 
derror = dom_node_get_text_content(a, &title1);
if (derror != DOM_NO_ERR) {
warn_user("TreeLoadError", "(No title)");
dom_node_unref(a);
return;
}
 
derror = dom_element_get_attribute(a, corestring_dom_href, &url1);
if (derror != DOM_NO_ERR || url1 == NULL) {
warn_user("TreeLoadError", "(No URL)");
dom_string_unref(title1);
dom_node_unref(a);
return;
}
 
if (title1 != NULL) {
title = strndup(dom_string_data(title1),
dom_string_byte_length(title1));
dom_string_unref(title1);
} else {
title = strdup("");
}
if (title == NULL) {
warn_user("NoMemory", NULL);
dom_string_unref(url1);
dom_node_unref(a);
return;
}
 
/* We're loading external input.
* This may be garbage, so attempt to normalise via nsurl
*/
url2 = strndup(dom_string_data(url1), dom_string_byte_length(url1));
if (url2 == NULL) {
warn_user("NoMemory", NULL);
free(title);
dom_string_unref(url1);
dom_node_unref(a);
return;
}
 
dom_string_unref(url1);
 
error = nsurl_create(url2, &url);
 
free(url2);
 
if (error != NSERROR_OK) {
LOG(("Failed normalising '%s'", url2));
 
warn_user("NoMemory", NULL);
 
free(title);
dom_node_unref(a);
 
return;
}
 
data = urldb_get_url_data(url);
if (data == NULL) {
/* No entry in database, so add one */
urldb_add_url(url);
/* now attempt to get url data */
data = urldb_get_url_data(url);
}
if (data == NULL) {
nsurl_unref(url);
free(title);
dom_node_unref(a);
 
return;
}
 
/* Make this URL persistent */
urldb_set_url_persistence(url, true);
 
/* Force the title in the hotlist */
urldb_set_url_title(url, title);
 
entry = tree_create_URL_node(ctx->tree, ctx->directory, url, title,
ctx->callback, ctx->callback_data);
 
if (entry == NULL) {
/** \todo why isn't this fatal? */
warn_user("NoMemory", 0);
} else {
tree_update_URL_node(ctx->tree, entry, url, data);
}
 
nsurl_unref(url);
free(title);
dom_node_unref(a);
}
 
static bool tree_url_load_directory_cb(dom_node *node, void *ctx)
{
tree_url_load_ctx *tctx = ctx;
dom_string *name;
dom_exception error;
 
/* The ul may contain entries as a li, or directories as
* an h4 followed by a ul. Non-element nodes may be present
* (eg. text, comments), and are ignored. */
 
error = dom_node_get_node_name(node, &name);
if (error != DOM_NO_ERR || name == NULL)
return false;
 
if (dom_string_caseless_lwc_isequal(name, corestring_lwc_li)) {
/* entry */
tree_url_load_entry(node, tctx);
tctx->last_was_h4 = false;
} else if (dom_string_caseless_lwc_isequal(name, corestring_lwc_h4)) {
/* directory (a) */
dom_string *title;
 
error = dom_node_get_text_content(node, &title);
if (error != DOM_NO_ERR || title == NULL) {
warn_user("TreeLoadError", "(Empty <h4> "
"or memory exhausted.)");
dom_string_unref(name);
return false;
}
 
if (tctx->title != NULL)
dom_string_unref(tctx->title);
tctx->title = title;
tctx->last_was_h4 = true;
} else if (tctx->last_was_h4 && dom_string_caseless_lwc_isequal(name,
corestring_lwc_ul)) {
/* directory (b) */
dom_string *id;
bool dir_is_default;
struct node *dir;
char *title;
tree_url_load_ctx new_ctx;
 
error = dom_element_get_attribute(node, corestring_dom_id, &id);
if (error != DOM_NO_ERR) {
dom_string_unref(name);
return false;
}
 
if (id != NULL) {
dir_is_default = dom_string_caseless_lwc_isequal(id,
corestring_lwc_default);
 
dom_string_unref(id);
} else {
dir_is_default = false;
}
 
title = strndup(dom_string_data(tctx->title),
dom_string_byte_length(tctx->title));
if (title == NULL) {
dom_string_unref(name);
return false;
}
 
dir = tree_create_folder_node(tctx->tree, tctx->directory,
title, true, false, false);
if (dir == NULL) {
dom_string_unref(name);
return false;
}
 
if (dir_is_default)
tree_set_default_folder_node(tctx->tree, dir);
 
if (tctx->callback != NULL)
tree_set_node_user_callback(dir, tctx->callback,
tctx->callback_data);
 
if (folder_icon != NULL)
tree_set_node_icon(tctx->tree, dir, folder_icon);
 
new_ctx.tree = tctx->tree;
new_ctx.directory = dir;
new_ctx.callback = tctx->callback;
new_ctx.callback_data = tctx->callback_data;
new_ctx.last_was_h4 = false;
new_ctx.title = NULL;
 
tree_url_load_directory(node, &new_ctx);
 
if (new_ctx.title != NULL) {
dom_string_unref(new_ctx.title);
new_ctx.title = NULL;
}
tctx->last_was_h4 = false;
} else {
tctx->last_was_h4 = false;
}
 
dom_string_unref(name);
 
return true;
}
 
/**
* Parse a directory represented as a ul.
*
* \param ul DOM node for parsed ul
* \param directory directory to add this directory to
*/
static void tree_url_load_directory(dom_node *ul, tree_url_load_ctx *ctx)
{
assert(ul != NULL);
assert(ctx != NULL);
assert(ctx->directory != NULL);
 
libdom_iterate_child_elements(ul, tree_url_load_directory_cb, ctx);
}
 
/**
* Loads an url tree from a specified file.
*
* \param filename name of file to read
* \param tree empty tree which data will be read into
* \return the file represented as a tree, or NULL on failure
*/
bool tree_urlfile_load(const char *filename, struct tree *tree,
tree_node_user_callback callback, void *callback_data)
{
dom_document *document;
dom_node *html, *body, *ul;
struct node *root;
nserror error;
tree_url_load_ctx ctx;
 
if (filename == NULL) {
return false;
}
 
error = libdom_parse_file(filename, "iso-8859-1", &document);
if (error != NSERROR_OK) {
if (error != NSERROR_NOT_FOUND) {
warn_user("TreeLoadError", messages_get("ParsingFail"));
}
return false;
}
 
html = libdom_find_first_element((dom_node *) document,
corestring_lwc_html);
if (html == NULL) {
dom_node_unref(document);
warn_user("TreeLoadError", "(<html> not found)");
return false;
}
 
body = libdom_find_first_element(html, corestring_lwc_body);
if (body == NULL) {
dom_node_unref(html);
dom_node_unref(document);
warn_user("TreeLoadError", "(<html>...<body> not found)");
return false;
}
 
ul = libdom_find_first_element(body, corestring_lwc_ul);
if (ul == NULL) {
dom_node_unref(body);
dom_node_unref(html);
dom_node_unref(document);
warn_user("TreeLoadError",
"(<html>...<body>...<ul> not found.)");
return false;
}
 
root = tree_get_root(tree);
 
ctx.tree = tree;
ctx.directory = root;
ctx.callback = callback;
ctx.callback_data = callback_data;
ctx.last_was_h4 = false;
ctx.title = NULL;
 
tree_url_load_directory(ul, &ctx);
tree_set_node_expanded(tree, root, true, false, false);
 
if (ctx.title != NULL) {
dom_string_unref(ctx.title);
ctx.title = NULL;
}
 
dom_node_unref(ul);
dom_node_unref(body);
dom_node_unref(html);
dom_node_unref(document);
 
return true;
}
 
/**
* Add an entry to the HTML tree for saving.
*
* The node must contain a sequence of node_elements in the following order:
*
* \param entry hotlist entry to add
* \param fp File to write to
* \return true on success, false on memory exhaustion
*/
static bool tree_url_save_entry(struct node *entry, FILE *fp)
{
const char *href, *text;
char *latin1_href, *latin1_text;
utf8_convert_ret ret;
 
text = tree_url_node_get_title(entry);
if (text == NULL)
return false;
 
href = tree_url_node_get_url(entry);
if (href == NULL)
return false;
 
ret = utf8_to_html(text, "iso-8859-1", strlen(text), &latin1_text);
if (ret != UTF8_CONVERT_OK)
return false;
 
ret = utf8_to_html(href, "iso-8859-1", strlen(href), &latin1_href);
if (ret != UTF8_CONVERT_OK) {
free(latin1_text);
return false;
}
 
fprintf(fp, "<li><a href=\"%s\">%s</a></li>",
latin1_href, latin1_text);
 
free(latin1_href);
free(latin1_text);
 
return true;
}
 
/**
* Add a directory to the HTML tree for saving.
*
* \param directory hotlist directory to add
* \param fp File to write to
* \return true on success, false on memory exhaustion
*/
static bool tree_url_save_directory(struct node *directory, FILE *fp)
{
struct node *child;
 
fputs("<ul", fp);
if (tree_node_is_default(directory))
fputs(" id=\"default\"", fp);
fputc('>', fp);
 
if (tree_node_get_child(directory) != NULL)
fputc('\n', fp);
 
for (child = tree_node_get_child(directory); child != NULL;
child = tree_node_get_next(child)) {
if (tree_node_is_folder(child) == false) {
/* entry */
if (tree_url_save_entry(child, fp) == false)
return false;
} else {
/* directory */
/* invalid HTML */
const char *text;
char *latin1_text;
utf8_convert_ret ret;
 
text = tree_url_node_get_title(child);
if (text == NULL)
return false;
 
ret = utf8_to_html(text, "iso-8859-1",
strlen(text), &latin1_text);
if (ret != UTF8_CONVERT_OK)
return false;
 
fprintf(fp, "<h4>%s</h4>\n", latin1_text);
 
free(latin1_text);
 
if (tree_url_save_directory(child, fp) == false)
return false;
}
 
fputc('\n', fp);
}
 
fputs("</ul>", fp);
 
return true;
}
 
 
/**
* Perform a save to a specified file in the form of a html page
*
* \param filename the file to save to
* \param page_title title of the page
*/
bool tree_urlfile_save(struct tree *tree, const char *filename,
const char *page_title)
{
FILE *fp;
 
fp = fopen(filename, "w");
if (fp == NULL)
return NULL;
 
/* Unfortunately the Browse Hotlist format is invalid HTML,
* so this is a lie.
*/
fputs("<!DOCTYPE html "
"PUBLIC \"//W3C/DTD HTML 4.01//EN\" "
"\"http://www.w3.org/TR/html4/strict.dtd\">\n", fp);
fputs("<html>\n<head>\n", fp);
fputs("<meta http-equiv=\"Content-Type\" "
"content=\"text/html; charset=iso-8859-1\">\n", fp);
fprintf(fp, "<title>%s</title>\n", page_title);
fputs("</head>\n<body>", fp);
 
if (tree_url_save_directory(tree_get_root(tree), fp) == false) {
warn_user("HotlistSaveError", 0);
fclose(fp);
return false;
}
 
fputs("</body>\n</html>\n", fp);
 
fclose(fp);
 
return true;
}
 
/programs/network/netsurf/netsurf/desktop/tree_url_node.h
0,0 → 1,60
/*
* Copyright 2005 Richard Wilson <info@tinct.net>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Creation of URL nodes with use of trees public API
*/
#ifndef _NETSURF_DESKTOP_TREE_URL_NODE_H_
#define _NETSURF_DESKTOP_TREE_URL_NODE_H_
 
 
#include "desktop/tree.h"
#include "utils/nsurl.h"
 
struct url_data;
 
void tree_url_node_init(const char *folder_icon_name);
void tree_url_node_cleanup(void);
struct node *tree_create_URL_node(struct tree *tree,
struct node *parent, nsurl *url, const char *title,
tree_node_user_callback, void *callback_data);
struct node *tree_create_URL_node_readonly(struct tree *tree,
struct node *parent, nsurl *url,
const struct url_data *data,
tree_node_user_callback, void *callback_data);
void tree_update_URL_node(struct tree *tree, struct node *node,
nsurl *url, const struct url_data *data);
const char *tree_url_node_get_title(struct node *node);
const char *tree_url_node_get_url(struct node *node);
void tree_url_node_edit_title(struct tree *tree, struct node *node);
void tree_url_node_edit_url(struct tree *tree, struct node *node);
 
node_callback_resp tree_url_node_callback(void *user_data,
struct node_msg_data *msg_data);
 
bool tree_urlfile_load(const char *filename, struct tree *tree,
tree_node_user_callback, void *callback_data);
bool tree_urlfile_save(struct tree *tree, const char *filename,
const char *page_title);
 
/* front end specific */
void tree_icon_name_from_content_type(char *buffer, content_type type);
 
#endif
/programs/network/netsurf/netsurf/desktop/version.c
0,0 → 1,10
#include "utils/testament.h"
 
const char * const netsurf_version = "3.0 (Dev"
#if defined(CI_BUILD)
" CI #" CI_BUILD
#endif
")"
;
const int netsurf_version_major = 3;
const int netsurf_version_minor = 0;
/programs/network/netsurf/netsurf/framebuffer/bitmap.c
0,0 → 1,256
/*
* Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <inttypes.h>
#include <sys/types.h>
#include <stdbool.h>
#include <assert.h>
 
#include <libnsfb.h>
 
#include "image/bitmap.h"
#include "utils/log.h"
 
/**
* Create a bitmap.
*
* \param width width of image in pixels
* \param height width of image in pixels
* \param state a flag word indicating the initial state
* \return an opaque struct bitmap, or NULL on memory exhaustion
*/
 
void *bitmap_create(int width, int height, unsigned int state)
{
nsfb_t *bm;
 
LOG(("width %d, height %d, state %u",width,height,state));
 
bm = nsfb_new(NSFB_SURFACE_RAM);
if (bm == NULL) {
return NULL;
}
 
if ((state & BITMAP_OPAQUE) == 0) {
nsfb_set_geometry(bm, width, height, NSFB_FMT_ABGR8888);
} else {
nsfb_set_geometry(bm, width, height, NSFB_FMT_XBGR8888);
}
 
if (nsfb_init(bm) == -1) {
nsfb_free(bm);
return NULL;
}
 
LOG(("bitmap %p", bm));
 
return bm;
}
 
 
/**
* Return a pointer to the pixel data in a bitmap.
*
* \param bitmap a bitmap, as returned by bitmap_create()
* \return pointer to the pixel buffer
*
* The pixel data is packed as BITMAP_FORMAT, possibly with padding at the end
* of rows. The width of a row in bytes is given by bitmap_get_rowstride().
*/
 
unsigned char *bitmap_get_buffer(void *bitmap)
{
nsfb_t *bm = bitmap;
unsigned char *bmpptr;
 
assert(bm != NULL);
 
nsfb_get_buffer(bm, &bmpptr, NULL);
 
return bmpptr;
}
 
 
/**
* Find the width of a pixel row in bytes.
*
* \param bitmap a bitmap, as returned by bitmap_create()
* \return width of a pixel row in the bitmap
*/
 
size_t bitmap_get_rowstride(void *bitmap)
{
nsfb_t *bm = bitmap;
int bmpstride;
 
assert(bm != NULL);
 
nsfb_get_buffer(bm, NULL, &bmpstride);
 
return bmpstride;
}
 
 
/**
* Free a bitmap.
*
* \param bitmap a bitmap, as returned by bitmap_create()
*/
 
void bitmap_destroy(void *bitmap)
{
nsfb_t *bm = bitmap;
 
assert(bm != NULL);
 
nsfb_free(bm);
}
 
 
/**
* Save a bitmap in the platform's native format.
*
* \param bitmap a bitmap, as returned by bitmap_create()
* \param path pathname for file
* \return true on success, false on error and error reported
*/
 
bool bitmap_save(void *bitmap, const char *path, unsigned flags)
{
return true;
}
 
 
/**
* The bitmap image has changed, so flush any persistant cache.
*
* \param bitmap a bitmap, as returned by bitmap_create()
*/
void bitmap_modified(void *bitmap) {
}
 
/**
* Sets wether a bitmap should be plotted opaque
*
* \param bitmap a bitmap, as returned by bitmap_create()
* \param opaque whether the bitmap should be plotted opaque
*/
void bitmap_set_opaque(void *bitmap, bool opaque)
{
nsfb_t *bm = bitmap;
 
assert(bm != NULL);
 
LOG(("setting bitmap %p to %s", bm, opaque?"opaque":"transparent"));
 
if (opaque) {
nsfb_set_geometry(bm, 0, 0, NSFB_FMT_XBGR8888);
} else {
nsfb_set_geometry(bm, 0, 0, NSFB_FMT_ABGR8888);
}
}
 
 
/**
* Tests whether a bitmap has an opaque alpha channel
*
* \param bitmap a bitmap, as returned by bitmap_create()
* \return whether the bitmap is opaque
*/
bool bitmap_test_opaque(void *bitmap)
{
int tst;
nsfb_t *bm = bitmap;
unsigned char *bmpptr;
int width;
int height;
 
assert(bm != NULL);
 
nsfb_get_buffer(bm, &bmpptr, NULL);
 
nsfb_get_geometry(bm, &width, &height, NULL);
 
tst = width * height;
 
while (tst-- > 0) {
if (bmpptr[(tst << 2) + 3] != 0xff) {
LOG(("bitmap %p has transparency",bm));
return false;
}
}
LOG(("bitmap %p is opaque", bm));
return true;
}
 
 
/**
* Gets weather a bitmap should be plotted opaque
*
* \param bitmap a bitmap, as returned by bitmap_create()
*/
bool bitmap_get_opaque(void *bitmap)
{
nsfb_t *bm = bitmap;
enum nsfb_format_e format;
 
assert(bm != NULL);
 
nsfb_get_geometry(bm, NULL, NULL, &format);
 
if (format == NSFB_FMT_ABGR8888)
return false;
 
return true;
}
 
int bitmap_get_width(void *bitmap)
{
nsfb_t *bm = bitmap;
int width;
 
assert(bm != NULL);
 
nsfb_get_geometry(bm, &width, NULL, NULL);
 
return(width);
}
 
int bitmap_get_height(void *bitmap)
{
nsfb_t *bm = bitmap;
int height;
 
assert(bm != NULL);
 
nsfb_get_geometry(bm, NULL, &height, NULL);
 
return(height);
}
 
/* get bytes per pixel */
size_t bitmap_get_bpp(void *bitmap)
{
return 4;
}
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/clipboard.c
0,0 → 1,98
/*
* Copyright 2012 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* nsfb internal clipboard handling
*/
 
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "desktop/browser.h"
#include "desktop/gui.h"
#include "desktop/selection.h"
#include "framebuffer/gui.h"
#include "utils/log.h"
 
 
static struct gui_clipboard {
char *buffer;
size_t buffer_len;
size_t length;
} gui_clipboard;
 
 
 
 
/**
* Core asks front end for clipboard contents.
*
* \param buffer UTF-8 text, allocated by front end, ownership yeilded to core
* \param length Byte length of UTF-8 text in buffer
*/
void gui_get_clipboard(char **buffer, size_t *length)
{
*buffer = NULL;
*length = 0;
 
if (gui_clipboard.length > 0) {
assert(gui_clipboard.buffer != NULL);
LOG(("Pasting %i bytes: \"%s\"\n", gui_clipboard.length,
gui_clipboard.buffer));
 
*buffer = malloc(gui_clipboard.length);
 
if (*buffer != NULL) {
memcpy(*buffer, gui_clipboard.buffer,
gui_clipboard.length);
*length = gui_clipboard.length;
}
}
}
 
 
/**
* Core tells front end to put given text in clipboard
*
* \param buffer UTF-8 text, owned by core
* \param length Byte length of UTF-8 text in buffer
* \param styles Array of styles given to text runs, owned by core, or NULL
* \param n_styles Number of text run styles in array
*/
void gui_set_clipboard(const char *buffer, size_t length,
nsclipboard_styles styles[], int n_styles)
{
if (gui_clipboard.buffer_len < length + 1) {
/* Make buffer big enough */
char *new_buff;
 
new_buff = realloc(gui_clipboard.buffer, length + 1);
if (new_buff == NULL)
return;
 
gui_clipboard.buffer = new_buff;
gui_clipboard.buffer_len = length + 1;
}
 
gui_clipboard.length = 0;
 
memcpy(gui_clipboard.buffer, buffer, length);
gui_clipboard.length = length;
gui_clipboard.buffer[gui_clipboard.length] = '\0';
}
 
/programs/network/netsurf/netsurf/framebuffer/convert_image.c
0,0 → 1,314
/*
* Copyright 2009 Daniel Silverstone <dsilvers@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdbool.h>
#include <errno.h>
#include <stdio.h>
#include <png.h>
#include <stdlib.h>
 
#if PNG_LIBPNG_VER < 10209
#define png_set_expand_gray_1_2_4_to_8(png) png_set_gray_1_2_4_to_8(png)
#endif
 
static png_structp png;
static png_infop info;
static int interlace;
static size_t rowbytes;
static int raw_width, raw_height;
static int rowstride;
static unsigned char *bitmap_data;
static bool is_cursor = true;
static int raw_hot_x, raw_hot_y;
 
#define WIDTH (is_cursor?raw_width-1:raw_width)
#define HEIGHT (is_cursor?raw_height-1:raw_height)
 
#define HOT_X (is_cursor?raw_hot_x-1:0)
#define HOT_Y (is_cursor?raw_hot_y-1:0)
 
#define REAL(v) (is_cursor?v+1:v)
 
#define PPIX_AT(x,y) ((bitmap_data + (rowstride * y)) + (x * 4))
 
#define R_OFF 2
#define G_OFF 1
#define B_OFF 0
#define A_OFF 3
 
#define R_AT(x,y) *(PPIX_AT(x,y) + R_OFF)
#define G_AT(x,y) *(PPIX_AT(x,y) + G_OFF)
#define B_AT(x,y) *(PPIX_AT(x,y) + B_OFF)
#define A_AT(x,y) *(PPIX_AT(x,y) + A_OFF)
 
static void info_callback(png_structp png, png_infop info);
static void row_callback(png_structp png, png_bytep new_row,
png_uint_32 row_num, int pass);
static void end_callback(png_structp png, png_infop info);
 
 
 
static void
usage(void)
{
fprintf(stderr, "usage: fb_convert_image input.png output.inc varname\n");
}
 
static void info_callback(png_structp png, png_infop info);
static void row_callback(png_structp png, png_bytep new_row,
png_uint_32 row_num, int pass);
static void end_callback(png_structp png, png_infop info);
 
 
static void
detect_hotspot(void)
{
int i;
int greenpixels = 0;
for (i = 0; i < raw_width; ++i) {
if (A_AT(i, 0) == 255) {
if (G_AT(i, 0) == 255) {
greenpixels++;
raw_hot_x = i;
}
if ((B_AT(i, 0) != 0) || (R_AT(i, 0) != 0)) {
is_cursor = false;
return;
}
} else if (A_AT(i, 0) != 0) {
is_cursor = false;
return;
}
}
if (greenpixels != 1) {
is_cursor = false;
return;
}
 
for (i = 0; i < raw_height; ++i) {
if (A_AT(0, i) == 255) {
if (G_AT(0, i) == 255) {
greenpixels++;
raw_hot_y = i;
}
if ((B_AT(0, i) != 0) || (R_AT(0, i) != 0)) {
is_cursor = false;
return;
}
} else if (A_AT(0, i) != 0) {
is_cursor = false;
return;
}
}
if (greenpixels != 2) {
is_cursor = false;
return;
}
printf(" Pointer detected. Adjusted hotspot at %d, %d (0-based)\n",
raw_hot_x - 1, raw_hot_y - 1);
}
 
int
main(int argc, char **argv)
{
FILE *f;
unsigned char buffer[1024];
int br;
int x, y, c;
if (argc != 4) {
usage();
return 1;
}
printf(" CONVERT: %s (%s)\n", argv[1], argv[3]);
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
info = png_create_info_struct(png);
png_set_progressive_read_fn(png, NULL, info_callback, row_callback, end_callback);
f = fopen(argv[1], "rb");
if (f == NULL) {
printf(" Unable to open %s\n", argv[1]);
return 1;
}
do {
br = fread(buffer, 1, 1024, f);
if (br > 0) {
png_process_data(png, info, buffer, br);
}
} while (br > 0);
if (br < 0) {
printf("Error reading input: %s\n", strerror(errno));
return 1;
}
fclose(f);
detect_hotspot();
f = fopen(argv[2], "w");
if (f == NULL) {
printf(" Unable to open %s\n", argv[2]);
return 2;
}
fprintf(f, "/* This file is auto-generated from %s\n", argv[1]);
fprintf(f, " *\n * Do not edit this file directly.\n */\n\n");
fprintf(f, "#include <sys/types.h>\n\n");
fprintf(f, "#include <stdint.h>\n\n");
fprintf(f, "#include <stdbool.h>\n\n");
fprintf(f, "#include <libnsfb.h>\n\n");
fprintf(f, "#include \"desktop/plot_style.h\"\n");
fprintf(f, "#include \"framebuffer/gui.h\"\n");
fprintf(f, "#include \"framebuffer/fbtk.h\"\n\n");
fprintf(f, "static uint8_t %s_pixdata[] = {\n", argv[3]);
for (y = 0; y < HEIGHT; ++y) {
unsigned char *rowptr = bitmap_data + (rowstride * y);
if (is_cursor) {
/* If it's a cursor, skip one row and one column */
rowptr += rowstride + 4;
}
fprintf(f, "\t");
for (x = 0; x < WIDTH; ++x) {
for (c = 0; c < 4; ++c) {
unsigned char b = *rowptr++;
fprintf(f, "0x%02x, ", b);
}
}
fprintf(f, "\n");
}
fprintf(f, "};\n\n");
fprintf(f, "struct fbtk_bitmap %s = {\n", argv[3]);
fprintf(f, "\t.width\t\t= %d,\n", WIDTH);
fprintf(f, "\t.height\t\t= %d,\n", HEIGHT);
fprintf(f, "\t.hot_x\t\t= %d,\n", HOT_X);
fprintf(f, "\t.hot_y\t\t= %d,\n", HOT_Y);
fprintf(f, "\t.pixdata\t= %s_pixdata,\n", argv[3]);
fprintf(f, "};\n\n");
fclose(f);
return 0;
}
 
static void
info_callback(png_structp png, png_infop info)
{
int bit_depth, color_type, interlace, intent;
double gamma;
unsigned long width, height;
/* Read the PNG details */
png_get_IHDR(png, info, &width, &height, &bit_depth,
&color_type, &interlace, 0, 0);
/* Set up our transformations */
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png);
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(png);
if (png_get_valid(png, info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png);
if (bit_depth == 16)
png_set_strip_16(png);
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);
if (!(color_type & PNG_COLOR_MASK_ALPHA))
png_set_filler(png, 0xff, PNG_FILLER_AFTER);
/* gamma correction - we use 2.2 as our screen gamma
* this appears to be correct (at least in respect to !Browse)
* see http://www.w3.org/Graphics/PNG/all_seven.html for a test case
*/
if (png_get_sRGB(png, info, &intent))
png_set_gamma(png, 2.2, 0.45455);
else {
if (png_get_gAMA(png, info, &gamma))
png_set_gamma(png, 2.2, gamma);
else
png_set_gamma(png, 2.2, 0.45455);
}
 
 
png_read_update_info(png, info);
 
rowbytes = png_get_rowbytes(png, info);
interlace = (interlace == PNG_INTERLACE_ADAM7);
raw_width = width;
raw_height = height;
rowstride = raw_width * 4;
bitmap_data = malloc(rowstride * raw_height);
}
 
static unsigned int interlace_start[8] = {0, 16, 0, 8, 0, 4, 0};
static unsigned int interlace_step[8] = {28, 28, 12, 12, 4, 4, 0};
static unsigned int interlace_row_start[8] = {0, 0, 4, 0, 2, 0, 1};
static unsigned int interlace_row_step[8] = {8, 8, 8, 4, 4, 2, 2};
 
static void
row_callback(png_structp png, png_bytep new_row,
png_uint_32 row_num, int pass)
{
unsigned long i, j;
unsigned int start, step;
unsigned char *row = bitmap_data + (rowstride * row_num);
if (new_row == 0)
return;
if (interlace) {
start = interlace_start[pass];
step = interlace_step[pass];
row_num = interlace_row_start[pass] +
interlace_row_step[pass] * row_num;
 
/* Copy the data to our current row taking interlacing
* into consideration */
row = bitmap_data + (rowstride * row_num);
for (j = 0, i = start; i < rowbytes; i += step) {
row[i++] = new_row[j++];
row[i++] = new_row[j++];
row[i++] = new_row[j++];
row[i++] = new_row[j++];
}
} else {
memcpy(row, new_row, rowbytes);
}
}
 
static void
end_callback(png_structp png, png_infop info)
{
}
 
 
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
 
/programs/network/netsurf/netsurf/framebuffer/fb_search.c
0,0 → 1,74
/*
* Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdbool.h>
#include <string.h>
 
#include "utils/log.h"
 
/* callback functions for search implementation */
static void gui_search_set_status(bool found, void *p);
static void gui_search_set_hourglass(bool active, void *p);
static void gui_search_add_recent(const char *string, void *p);
static void gui_search_set_forward_state(bool active, void *p);
static void gui_search_set_back_state(bool active, void *p);
 
/**
* Change the displayed search status.
* \param found search pattern matched in text
* \param p the pointer sent to search_verify_new() / search_create_context()
*/
void gui_search_set_status(bool found, void *p)
{
}
 
/**
* display hourglass while searching
* \param active start/stop indicator
* \param p the pointer sent to search_verify_new() / search_create_context()
*/
void gui_search_set_hourglass(bool active, void *p)
{
}
 
/**
* add search string to recent searches list
* \param string search pattern
* \param p the pointer sent to search_verify_new() / search_create_context()
*/
void gui_search_add_recent(const char *string, void *p)
{
}
 
/**
* activate search forwards button in gui
* \param active activate/inactivate
* \param p the pointer sent to search_verify_new() / search_create_context()
*/
void gui_search_set_forward_state(bool active, void *p)
{
}
 
/**
* activate search forwards button in gui
* \param active activate/inactivate
* \param p the pointer sent to search_verify_new() / search_create_context()
*/
void gui_search_set_back_state(bool active, void *p)
{
}
/programs/network/netsurf/netsurf/framebuffer/fbtk/bitmap.c
0,0 → 1,198
/*
* Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
*
* Framebuffer windowing toolkit bitmaped image widget
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdbool.h>
#include <stdlib.h>
 
#include <libnsfb.h>
#include <libnsfb_plot.h>
 
#include "desktop/browser.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
#include "framebuffer/image_data.h"
 
#include "utils/log.h"
#include <menuet/os.h>
 
#include "widget.h"
 
static int
fb_redraw_bitmap(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
LOG(("REDRAW BITMAP"));
//__menuet__debug_out("REDRAW BITMAP");
nsfb_bbox_t bbox;
nsfb_bbox_t rect;
nsfb_t *nsfb;
 
LOG(("REDRAW BITMAP 1 "));
//__menuet__debug_out("REDRAW BITMAP 1");
 
 
nsfb = fbtk_get_nsfb(widget);
 
LOG(("REDRAW BITMAP 2"));
//__menuet__debug_out("REDRAW BITMAP 2");
 
 
fbtk_get_bbox(widget, &bbox);
 
rect = bbox;
 
LOG(("REDRAW BITMAP 3 "));
//__menuet__debug_out("REDRAW BITMAP 3");
 
 
nsfb_claim(nsfb, &bbox);
 
LOG(("REDRAW BITMAP 4"));
//__menuet__debug_out("REDRAW BITMAP 4");
 
/* clear background */
if ((widget->bg & 0xFF000000) != 0) {
/* transparent polygon filling isnt working so fake it */
LOG(("REDRAW BITMAP 5"));
//__menuet__debug_out("REDRAW BITMAP 5");
 
nsfb_plot_rectangle_fill(nsfb, &bbox, widget->bg);
}
 
LOG(("REDRAW BITMAP 6"));
//__menuet__debug_out("REDRAW BITMAP 6\n");
 
/* plot the image */
LOG(("STUB: DON'T REAL DRAW"));
//__menuet__debug_out("STUB: DON'T REAL DRAW\n");
LOG(("pixdata is %x", (nsfb_colour_t *)widget->u.bitmap.bitmap->pixdata));
LOG(("pixdata is w:%d h:%d",widget->u.bitmap.bitmap->width,
widget->u.bitmap.bitmap->height));
//hmm
//int zap;
//if (widget->u.bitmap.bitmap->width % 4 != 0) {
// zap = widget->u.bitmap.bitmap->width + 2; }
//nsfb_plot_rectangle_fill(nsfb, &rect, 0xFFFFFF);
nsfb_plot_bitmap(nsfb,
&rect,
(nsfb_colour_t *)widget->u.bitmap.bitmap->pixdata,
//0, 0, 0,
widget->u.bitmap.bitmap->width,
widget->u.bitmap.bitmap->height,
widget->u.bitmap.bitmap->width,
!widget->u.bitmap.bitmap->opaque);
LOG(("REDRAW BITMAP 7"));
//__menuet__debug_out("REDRAW BITMAP 7\n");
 
nsfb_update(nsfb, &bbox);
 
LOG(("REDRAW BITMAP OK\n"));
//__menuet__debug_out("REDRAW BITMAP OK\n");
 
return 0;
}
 
/* exported function documented in fbtk.h */
void
fbtk_set_bitmap(fbtk_widget_t *widget, struct fbtk_bitmap *image)
{
LOG(("SET BITMAP"));
//__menuet__debug_out("set BITMAP");
if ((widget == NULL) || (widget->type != FB_WIDGET_TYPE_BITMAP))
return;
 
widget->u.bitmap.bitmap = image;
 
fbtk_request_redraw(widget);
}
 
/* exported function documented in fbtk.h */
fbtk_widget_t *
fbtk_create_bitmap(fbtk_widget_t *parent,
int x,
int y,
int width,
int height,
colour c,
struct fbtk_bitmap *image)
{
LOG(("CREATE BITMAP"));
//__menuet__debug_out("cr BITMAP");
fbtk_widget_t *neww;
 
neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_BITMAP, x, y, width, height);
 
neww->bg = c;
neww->mapped = true;
neww->u.bitmap.bitmap = image;
 
fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_bitmap, NULL);
 
return neww;
}
 
/* exported function documented in fbtk.h */
fbtk_widget_t *
fbtk_create_button(fbtk_widget_t *parent,
int x,
int y,
int width,
int height,
colour c,
struct fbtk_bitmap *image,
fbtk_callback click,
void *pw)
{
fbtk_widget_t *neww;
 
LOG(("CREATE BUTTON BITMAP"));
//__menuet__debug_out("cr bb BITMAP");
neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_BITMAP, x, y, width, height);
 
neww->bg = c;
neww->mapped = true;
neww->u.bitmap.bitmap = image;
 
fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_bitmap, NULL);
fbtk_set_handler(neww, FBTK_CBT_CLICK, click, pw);
fbtk_set_handler(neww, FBTK_CBT_POINTERENTER, fbtk_set_ptr, &hand_image);
 
return neww;
}
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/fbtk/event.c
0,0 → 1,344
/*
* Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
*
* Framebuffer windowing toolkit event processing.
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
 
#include <libnsfb.h>
#include <libnsfb_plot.h>
#include <libnsfb_plot_util.h>
#include <libnsfb_event.h>
#include <libnsfb_cursor.h>
 
#include "utils/utils.h"
#include "utils/log.h"
#include "css/css.h"
#include "desktop/browser.h"
#include "desktop/plotters.h"
#include "desktop/textinput.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
#include "framebuffer/image_data.h"
 
#include "widget.h"
 
/* exported function documented in fbtk.h */
void
fbtk_input(fbtk_widget_t *root, nsfb_event_t *event)
{
fbtk_widget_t *input;
 
root = fbtk_get_root_widget(root);
 
/* obtain widget with input focus */
input = root->u.root.input;
if (input == NULL) {
LOG(("No widget has input focus."));
return; /* no widget with input */
}
 
fbtk_post_callback(input, FBTK_CBT_INPUT, event);
}
 
/* exported function documented in fbtk.h */
void
fbtk_click(fbtk_widget_t *widget, nsfb_event_t *event)
{
fbtk_widget_t *root;
fbtk_widget_t *clicked;
nsfb_bbox_t cloc;
int x, y;
 
/* ensure we have the root widget */
root = fbtk_get_root_widget(widget);
 
nsfb_cursor_loc_get(root->u.root.fb, &cloc);
 
clicked = fbtk_get_widget_at(root, cloc.x0, cloc.y0);
 
if (clicked == NULL)
return;
 
if (fbtk_get_handler(clicked, FBTK_CBT_INPUT) != NULL) {
fbtk_set_focus(clicked);
}
 
x = fbtk_get_absx(clicked);
y = fbtk_get_absy(clicked);
 
LOG(("clicked %p at %d,%d", clicked, x, y));
 
/* post the click */
fbtk_post_callback(clicked, FBTK_CBT_CLICK, event, cloc.x0 - x, cloc.y0 - y);
}
 
/* exported function documented in fbtk.h */
bool
fbtk_tgrab_pointer(fbtk_widget_t *widget)
{
fbtk_widget_t *root;
 
/* ensure we have the root widget */
root = fbtk_get_root_widget(widget);
 
if (root->u.root.grabbed == widget) {
/* release pointer grab */
root->u.root.grabbed = NULL;
return true;
} else if (root->u.root.grabbed == NULL) {
/* set pointer grab */
root->u.root.grabbed = widget;
return true;
}
/* pointer was already grabbed */
return false;
}
 
/* exported function documented in fbtk.h */
void
fbtk_warp_pointer(fbtk_widget_t *widget, int x, int y, bool relative)
{
fbtk_widget_t *root;
fbtk_widget_t *moved;
nsfb_bbox_t cloc;
 
/* ensure we have the root widget */
root = fbtk_get_root_widget(widget);
 
if (relative) {
nsfb_cursor_loc_get(root->u.root.fb, &cloc);
cloc.x0 += x;
cloc.y0 += y;
} else {
cloc.x0 = x;
cloc.y0 = y;
}
 
/* ensure cursor location lies within the root widget */
if (cloc.x0 < root->x)
cloc.x0 = root->x;
if (cloc.x0 >= (root->x + root->width))
cloc.x0 = (root->x + root->width) - 1;
if (cloc.y0 < root->y)
cloc.y0 = root->y;
if (cloc.y0 >= (root->y + root->height))
cloc.y0 = (root->y + root->height) - 1;
 
if (root->u.root.grabbed == NULL) {
/* update the pointer cursor */
nsfb_cursor_loc_set(root->u.root.fb, &cloc);
 
moved = fbtk_get_widget_at(root, cloc.x0, cloc.y0);
 
x = fbtk_get_absx(moved);
y = fbtk_get_absy(moved);
 
/* post enter and leaving messages */
if (moved != root->u.root.prev) {
fbtk_post_callback(root->u.root.prev, FBTK_CBT_POINTERLEAVE);
root->u.root.prev = moved;
fbtk_post_callback(root->u.root.prev, FBTK_CBT_POINTERENTER);
}
} else {
/* pointer movement has been grabbed by a widget */
moved = root->u.root.grabbed;
 
/* ensure pointer remains within widget boundary */
x = fbtk_get_absx(moved);
y = fbtk_get_absy(moved);
 
if (cloc.x0 < x)
cloc.x0 = x;
if (cloc.y0 < y)
cloc.y0 = y;
if (cloc.x0 > (x + moved->width))
cloc.x0 = (x + moved->width);
if (cloc.y0 > (y + moved->height))
cloc.y0 = (y + moved->height);
 
/* update the pointer cursor */
nsfb_cursor_loc_set(root->u.root.fb, &cloc);
}
 
/* post the movement */
fbtk_post_callback(moved, FBTK_CBT_POINTERMOVE, cloc.x0 - x, cloc.y0 - y);
 
}
 
/* exported function documented in fbtk.h */
bool
fbtk_event(fbtk_widget_t *root, nsfb_event_t *event, int timeout)
{
nsfb_bbox_t cloc;
bool unused = false; /* is the event available */
bool move_pointer = false; /* whether pointer move events occured */
 
/* ensure we have the root widget */
root = fbtk_get_root_widget(root);
 
do {
if (nsfb_event(root->u.root.fb, event, timeout) == false) {
if (move_pointer)
fbtk_warp_pointer(root, cloc.x0, cloc.y0,
false);
return false;
}
 
if (move_pointer && event->type != NSFB_EVENT_MOVE_RELATIVE &&
event->type != NSFB_EVENT_MOVE_ABSOLUTE) {
/* Flush the movements */
fbtk_warp_pointer(root, cloc.x0, cloc.y0, false);
 
} else if (!move_pointer &&
event->type == NSFB_EVENT_MOVE_RELATIVE) {
/* Get current pointer coords */
nsfb_cursor_loc_get(root->u.root.fb, &cloc);
}
 
switch (event->type) {
case NSFB_EVENT_KEY_DOWN:
case NSFB_EVENT_KEY_UP:
if ((event->value.keycode >= NSFB_KEY_MOUSE_1) &&
(event->value.keycode <= NSFB_KEY_MOUSE_5)) {
fbtk_click(root, event);
} else {
fbtk_input(root, event);
}
break;
 
case NSFB_EVENT_CONTROL:
unused = true;
break;
 
case NSFB_EVENT_MOVE_RELATIVE:
/* Consecutive move events are consolidated into a
* single pointer warp */
move_pointer = true;
cloc.x0 += event->value.vector.x;
cloc.y0 += event->value.vector.y;
timeout = 0;
break;
 
case NSFB_EVENT_MOVE_ABSOLUTE:
/* Consecutive move events are consolidated into a
* single pointer warp */
move_pointer = true;
cloc.x0 = event->value.vector.x;
cloc.y0 = event->value.vector.y;
timeout = 0;
break;
 
default:
break;
}
} while (event->type == NSFB_EVENT_MOVE_RELATIVE ||
event->type == NSFB_EVENT_MOVE_ABSOLUTE);
return unused;
}
 
static int keymap[] = {
/* 0 1 2 3 4 5 6 7 8 9 */
-1, -1, -1, -1, -1, -1, -1, -1, 8, 9, /* 0 - 9 */
-1, -1, -1, 13, -1, -1, -1, -1, -1, -1, /* 10 - 19 */
-1, -1, -1, -1, -1, -1, -1, 27, -1, -1, /* 20 - 29 */
-1, -1, ' ', '!', '"', '#', '$', -1, '&','\'', /* 30 - 39 */
'(', ')', '*', '+', ',', '-', '.', '/', '0', '1', /* 40 - 49 */
'2', '3', '4', '5', '6', '7', '8', '9', ':', ';', /* 50 - 59 */
'<', '=', '>', '?', '@', -1, -1, -1, -1, -1, /* 60 - 69 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 70 - 79 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 - 89 */
-1, '[','\\', ']', '~', '_', '`', 'a', 'b', 'c', /* 90 - 99 */
'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', /* 100 - 109 */
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 110 - 119 */
'x', 'y', 'z', -1, -1, -1, -1, -1, -1, -1, /* 120 - 129 */
};
 
static int sh_keymap[] = {
/* 0 1 2 3 4 5 6 7 8 9 */
-1, -1, -1, -1, -1, -1, -1, -1, 8, 9, /* 0 - 9 */
-1, -1, -1, 13, -1, -1, -1, -1, -1, -1, /* 10 - 19 */
-1, -1, -1, -1, -1, -1, -1, 27, -1, -1, /* 20 - 29 */
-1, -1, ' ', '!', '"', '~', '$', -1, '&', '@', /* 30 - 39 */
'(', ')', '*', '+', '<', '_', '>', '?', ')', '!', /* 40 - 49 */
'"', 243, '$', '%', '^', '&', '*', '(', ';', ':', /* 50 - 59 */
'<', '+', '>', '?', '@', -1, -1, -1, -1, -1, /* 60 - 69 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 70 - 79 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 - 89 */
-1, '{', '|', '}', '~', '_', 254, 'A', 'B', 'C', /* 90 - 99 */
'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', /* 100 - 109 */
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 110 - 119 */
'X', 'Y', 'Z', -1, -1, -1, -1, -1, -1, -1, /* 120 - 129 */
};
 
 
/* exported function documented in fbtk.h */
int
fbtk_keycode_to_ucs4(int code, fbtk_modifier_type mods)
{
int ucs4 = -1;
 
if (mods & FBTK_MOD_LSHIFT || mods & FBTK_MOD_RSHIFT) {
if ((code >= 0) && (code < (int) NOF_ELEMENTS(sh_keymap)))
ucs4 = sh_keymap[code];
 
} else if (mods == FBTK_MOD_CLEAR) {
if ((code >= 0) && (code < (int) NOF_ELEMENTS(keymap)))
ucs4 = keymap[code];
 
} else if (mods & FBTK_MOD_LCTRL || mods & FBTK_MOD_RCTRL) {
switch (code) {
case NSFB_KEY_a:
ucs4 = KEY_SELECT_ALL;
break;
 
case NSFB_KEY_c:
ucs4 = KEY_COPY_SELECTION;
break;
 
case NSFB_KEY_u:
ucs4 = KEY_CUT_LINE;
break;
 
case NSFB_KEY_v:
ucs4 = KEY_PASTE;
break;
 
case NSFB_KEY_x:
ucs4 = KEY_CUT_SELECTION;
break;
 
case NSFB_KEY_z:
ucs4 = KEY_CLEAR_SELECTION;
break;
default:
break;
}
}
return ucs4;
}
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/fbtk/fbtk.c
0,0 → 1,878
/*
* Copyright 2008,2010 Vincent Sanders <vince@simtec.co.uk>
*
* Framebuffer windowing toolkit core.
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <sys/types.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdarg.h>
 
#include <libnsfb.h>
#include <libnsfb_plot.h>
#include <libnsfb_plot_util.h>
#include <libnsfb_event.h>
#include <libnsfb_cursor.h>
 
#include "utils/utils.h"
#include "utils/log.h"
#include "css/css.h"
#include "desktop/browser.h"
#include "desktop/plotters.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
#include "framebuffer/image_data.h"
 
#include "widget.h"
 
#ifdef FBTK_LOGGING
 
/* tree dump debug, also example of depth first tree walk */
static void
dump_tk_tree(fbtk_widget_t *widget)
{
widget = fbtk_get_root_widget(widget);
int indent = 0;
 
while (widget != NULL) {
LOG(("%*s%p", indent, "", widget));
if (widget->first_child != NULL) {
widget = widget->first_child;
indent += 6;
} else if (widget->next != NULL) {
widget = widget->next;
} else {
while ((widget->parent != NULL) &&
(widget->parent->next == NULL)) {
widget = widget->parent;
indent -= 6;
}
if (widget->parent != NULL) {
indent -= 6;
widget = widget->parent->next;
} else {
widget = NULL;
}
}
}
}
 
#endif
 
/* exported function documented in fbtk.h */
void
fbtk_request_redraw(fbtk_widget_t *widget)
{
fbtk_widget_t *cwidget;
fbtk_widget_t *pwidget;
 
assert(widget != NULL);
 
/* if widget not mapped do not try to redraw it */
pwidget = widget;
while (pwidget != NULL) {
if (pwidget->mapped == false)
return;
pwidget = pwidget->parent;
}
 
widget->redraw.needed = true;
widget->redraw.x = 0;
widget->redraw.y = 0;
widget->redraw.width = widget->width;
widget->redraw.height = widget->height;
 
LOG(("redrawing %p %d,%d %d,%d",
widget,
widget->redraw.x,
widget->redraw.y,
widget->redraw.width,
widget->redraw.height));
 
cwidget = widget->last_child;
while (cwidget != NULL) {
fbtk_request_redraw(cwidget);
cwidget = cwidget->prev;
}
 
while (widget->parent != NULL) {
widget = widget->parent;
widget->redraw.child = true;
}
}
 
 
 
/* exported function documented in fbtk.h */
int
fbtk_set_mapping(fbtk_widget_t *widget, bool map)
{
LOG(("setting mapping on %p to %d", widget, map));
widget->mapped = map;
if (map) {
fbtk_request_redraw(widget);
} else {
fbtk_request_redraw(widget->parent);
}
return 0;
}
 
/** swap the widget given with the next sibling.
*
* Swap a sibling widget with the next deepest in the hierachy
*/
static void
swap_siblings(fbtk_widget_t *lw)
{
fbtk_widget_t *rw; /* the widget to swap lw with */
fbtk_widget_t *before;
fbtk_widget_t *after;
 
rw = lw->next;
LOG(("Swapping %p with %p", lw, rw));
before = lw->prev;
after = rw->next;
 
if (before == NULL) {
/* left widget is currently the first child */
lw->parent->first_child = rw;
} else {
before->next = rw;
}
rw->prev = before;
rw->next = lw;
 
if (after == NULL) {
/* right widget is currently the last child */
rw->parent->last_child = lw;
} else {
after->prev = lw;
}
lw->next = after;
lw->prev = rw;
}
 
 
 
/* exported function documented in fbtk.h */
int
fbtk_set_zorder(fbtk_widget_t *widget, int z)
{
while (z != 0) {
if (z < 0) {
if (widget->prev == NULL)
break; /* cannot go any shallower */
 
/* swap with previous entry */
swap_siblings(widget->prev);
 
z++;
} else {
if (widget->next == NULL)
break; /* cannot go any deeper */
 
/* swap with subsequent entry */
swap_siblings(widget);
 
z--;
}
}
 
return z;
}
 
 
/* exported function documented in fbtk.h */
bool
fbtk_set_pos_and_size(fbtk_widget_t *widget,
int x, int y,
int width, int height)
{
if ((widget->x != x) ||
(widget->y != y) ||
(widget->width != width) ||
(widget->height != height)) {
widget->x = x;
widget->y = y;
widget->width = width;
widget->height = height;
/* @todo This should limit the redrawn area to the sum
* of the old and new widget dimensions, not redraw the lot.
*/
fbtk_request_redraw(widget->parent);
return true;
}
return false;
}
 
 
/* exported function docuemnted in fbtk.h */
void
fbtk_set_caret(fbtk_widget_t *widget, bool set,
int x, int y, int height,
void (*remove_caret)(fbtk_widget_t *widget))
{
fbtk_widget_t *root;
 
assert(widget != NULL);
root = fbtk_get_root_widget(widget);
 
if (root->u.root.caret.owner != NULL &&
root->u.root.caret.remove_cb != NULL)
root->u.root.caret.remove_cb(widget);
 
if (set) {
assert(remove_caret != NULL);
 
root->u.root.caret.owner = widget;
root->u.root.caret.x = x;
root->u.root.caret.y = y;
root->u.root.caret.height = height;
root->u.root.caret.remove_cb = remove_caret;
 
} else {
root->u.root.caret.owner = NULL;
root->u.root.caret.remove_cb = NULL;
}
}
 
/* exported function documented in fbtk.h */
int
fbtk_destroy_widget(fbtk_widget_t *widget)
{
fbtk_widget_t *parent;
int ret = 0;
 
ret = fbtk_post_callback(widget, FBTK_CBT_DESTROY);
 
while (widget->first_child != NULL) {
fbtk_destroy_widget(widget->first_child);
}
 
parent = widget->parent;
if (parent != NULL) {
 
/* unlink from siblings */
if (widget->prev != NULL) {
widget->prev->next = widget->next;
} else {
/* must be the first widget, unlink from parent */
parent->first_child = widget->next;
}
if (widget->next != NULL) {
widget->next->prev = widget->prev;
} else {
/* must be the last widget, unlink from parent */
parent->last_child = widget->prev;
}
 
free(widget);
}
 
return ret;
}
 
/* region coverage flags. */
enum {
POINT_LEFTOF_REGION = 1,
POINT_RIGHTOF_REGION = 2,
POINT_ABOVE_REGION = 4,
POINT_BELOW_REGION = 8,
};
 
/* Computes where a point lies in respect to an area. */
#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) )
 
/* swap two integers */
#define SWAP(a, b) do { int t; t=(a); (a)=(b); (b)=t; } while(0)
 
/* exported function documented in fbtk.h */
bool
fbtk_clip_rect(const bbox_t * clip, bbox_t * box)
{
uint8_t region1;
uint8_t region2;
 
/* ensure co-ordinates are in ascending order */
if (box->x1 < box->x0)
SWAP(box->x0, box->x1);
if (box->y1 < box->y0)
SWAP(box->y0, box->y1);
 
region1 = REGION(box->x0, box->y0, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
region2 = REGION(box->x1, box->y1, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
 
/* area lies entirely outside the clipping rectangle */
if ((region1 | region2) && (region1 & region2))
return false;
 
if (box->x0 < clip->x0)
box->x0 = clip->x0;
if (box->x0 > clip->x1)
box->x0 = clip->x1;
 
if (box->x1 < clip->x0)
box->x1 = clip->x0;
if (box->x1 > clip->x1)
box->x1 = clip->x1;
 
if (box->y0 < clip->y0)
box->y0 = clip->y0;
if (box->y0 > clip->y1)
box->y0 = clip->y1;
 
if (box->y1 < clip->y0)
box->y1 = clip->y0;
if (box->y1 > clip->y1)
box->y1 = clip->y1;
 
return true;
}
 
/* exported function documented in fbtk.h */
bool
fbtk_clip_to_widget(fbtk_widget_t *widget, bbox_t * box)
{
bbox_t wbox;
wbox.x0 = 0;
wbox.y0 = 0;
wbox.x1 = widget->width;
wbox.y1 = widget->height;
return fbtk_clip_rect(&wbox, box);
}
 
 
 
/* internally exported function documented in widget.h */
int
fbtk_set_ptr(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
fbtk_widget_t *root = fbtk_get_root_widget(widget);
struct fbtk_bitmap *bm = cbi->context;
 
nsfb_cursor_set(root->u.root.fb,
(nsfb_colour_t *)bm->pixdata,
bm->width,
bm->height,
bm->width,
bm->hot_x,
bm->hot_y);
 
return 0;
}
 
 
 
/* internally exported function documented in widget.h */
fbtk_widget_t *
fbtk_get_root_widget(fbtk_widget_t *widget)
{
while (widget->parent != NULL)
widget = widget->parent;
 
/* check root widget was found */
if (widget->type != FB_WIDGET_TYPE_ROOT) {
LOG(("Widget with null parent that is not the root widget!"));
return NULL;
}
 
return widget;
}
 
 
/* exported function documented in fbtk.h */
int
fbtk_get_absx(fbtk_widget_t *widget)
{
int x = widget->x;
 
while (widget->parent != NULL) {
widget = widget->parent;
x += widget->x;
}
 
return x;
}
 
/* exported function documented in fbtk.h */
int
fbtk_get_absy(fbtk_widget_t *widget)
{
int y = widget->y;
 
while (widget->parent != NULL) {
widget = widget->parent;
y += widget->y;
}
 
return y;
}
 
/* exported function documented in fbtk.h */
int
fbtk_get_height(fbtk_widget_t *widget)
{
return widget->height;
}
 
/* exported function documented in fbtk.h */
int
fbtk_get_width(fbtk_widget_t *widget)
{
return widget->width;
}
 
/* exported function documented in fbtk.h */
bool
fbtk_get_bbox(fbtk_widget_t *widget, nsfb_bbox_t *bbox)
{
bbox->x0 = widget->x;
bbox->y0 = widget->y;
bbox->x1 = widget->x + widget->width;
bbox->y1 = widget->y + widget->height;
 
widget = widget->parent;
while (widget != NULL) {
bbox->x0 += widget->x;
bbox->y0 += widget->y;
bbox->x1 += widget->x;
bbox->y1 += widget->y;
widget = widget->parent;
}
 
return true;
}
 
bool
fbtk_get_caret(fbtk_widget_t *widget, int *x, int *y, int *height)
{
fbtk_widget_t *root = fbtk_get_root_widget(widget);
 
if (root->u.root.caret.owner == widget) {
*x = root->u.root.caret.x;
*y = root->u.root.caret.y;
*height = root->u.root.caret.height;
 
return true;
 
} else {
*x = 0;
*y = 0;
*height = 0;
 
return false;
}
}
 
/* exported function documented in fbtk.h */
fbtk_widget_t *
fbtk_get_widget_at(fbtk_widget_t *nwid, int x, int y)
{
fbtk_widget_t *widget = NULL; /* found widget */
 
/* require the root widget to start */
nwid = fbtk_get_root_widget(nwid);
 
while (nwid != NULL) {
if ((nwid->mapped) &&
(x >= nwid->x) &&
(y >= nwid->y) &&
(x < (nwid->x + nwid->width)) &&
(y < (nwid->y + nwid->height))) {
widget = nwid;
x -= nwid->x;
y -= nwid->y;
nwid = nwid->first_child;
} else {
nwid = nwid->next;
}
}
 
return widget;
}
 
 
 
 
/* internally exported function documented in widget.h */
fbtk_widget_t *
fbtk_widget_new(fbtk_widget_t *parent,
enum fbtk_widgettype_e type,
int x,
int y,
int width,
int height)
{
LOG(("New widget..."));
 
fbtk_widget_t *neww; /* new widget */
 
if (parent == NULL)
{LOG(("parent null..."));
return NULL;}
 
LOG(("calloc..."));
neww = calloc(1, sizeof(fbtk_widget_t));
if (neww == NULL)
return NULL;
 
LOG(("super!..."));
LOG(("creating %p %d,%d %d,%d", neww, x, y, width, height));
 
/* make new window fit inside parent */
if (width == 0) {
width = parent->width - x;
} else if (width < 0) {
width = parent->width + width - x;
}
if ((width + x) > parent->width) {
width = parent->width - x;
}
 
if (height == 0) {
height = parent->height - y;
} else if (height < 0) {
height = parent->height + height - y;
}
if ((height + y) > parent->height) {
height = parent->height - y;
}
 
 
LOG(("using %p %d,%d %d,%d", neww, x, y, width, height));
/* set values */
neww->type = type;
neww->x = x;
neww->y = y;
neww->width = width;
neww->height = height;
 
/* insert into widget heiarchy */
 
LOG(("into hierarchy..."));
neww->parent = parent;
 
if (parent->first_child == NULL) {
/* no child widgets yet */
LOG(("no childs yet..."));
parent->last_child = neww;
} else {
/* add new widget to front of sibling chain */
neww->next = parent->first_child;
neww->next->prev = neww;
LOG(("n front of sibling..."));
}
parent->first_child = neww;
 
 
LOG(("Widget OK..."));
return neww;
}
 
/* exported function documented in fbtk.h */
bool
fbtk_get_redraw_pending(fbtk_widget_t *widget)
{
fbtk_widget_t *root;
 
/* ensure we have the root widget */
root = fbtk_get_root_widget(widget);
 
return root->redraw.needed | root->redraw.child;
}
 
/** Perform a depth-first tree-walk, calling the redraw callback of the widgets in turn.
*
* This function makes no decisions of its own and simply walks the
* widget tree depth first calling widgets redraw callbacks if flagged
* to do so.
* The tree search is optimised with a flag to indicate wether the
* children of a node should be considered.
*/
#include <menuet/os.h>
static int
do_redraw(nsfb_t *nsfb, fbtk_widget_t *widget)
{
nsfb_bbox_t plot_ctx;
fbtk_widget_t *cwidget; /* child widget */
 
 
LOG(("DO REDRAW"));
//__menuet__debug_out("\n***********\nDO REDRAW\n********\n");
/* check if the widget requires redrawing */
if (widget->redraw.needed == true) {
plot_ctx.x0 = fbtk_get_absx(widget) + widget->redraw.x;
plot_ctx.y0 = fbtk_get_absy(widget) + widget->redraw.y;
plot_ctx.x1 = plot_ctx.x0 + widget->redraw.width;
plot_ctx.y1 = plot_ctx.y0 + widget->redraw.height;
 
LOG(("clipping %p %d,%d %d,%d",
widget, plot_ctx.x0, plot_ctx.y0,
plot_ctx.x1, plot_ctx.y1));
if (nsfb_plot_set_clip(nsfb, &plot_ctx) == true) {
LOG(("POST CALLBACK"));
//__menuet__debug_out("\n***********\nPOST CALLBACK\n********\n");
fbtk_post_callback(widget, FBTK_CBT_REDRAW);
}
widget->redraw.needed = false;
}
 
LOG(("DO CHILD"));
//__menuet__debug_out("\n***********\nDO CHILD\n********\n");
 
/* walk the widgets children if child flag is set */
if (widget->redraw.child) {
LOG(("DO CHILD 2"));
//__menuet__debug_out("\n***********\nDO CHILD 2\n********\n");
cwidget = widget->last_child;
while (cwidget != NULL) {
LOG(("DO CHILD 3 ZZZ"));
//__menuet__debug_out("\n***********\nDO CHILD 3 ZZZ\n********\n");
do_redraw(nsfb, cwidget);
cwidget = cwidget->prev;
}
LOG(("DO CHILD 4"));
//__menuet__debug_out("\n***********\nDO CHILD 4\n********\n");
widget->redraw.child = false;
}
 
 
LOG(("SUP"));
//__menuet__debug_out("\n***********\nFIN REDRAW\n********\n");
 
return 1;
}
 
/* exported function documented in fbtk.h */
int
fbtk_redraw(fbtk_widget_t *widget)
{
fbtk_widget_t *root;
 
/* ensure we have the root widget */
root = fbtk_get_root_widget(widget);
 
return do_redraw(root->u.root.fb, root);
}
 
/* exported function documented in fbtk.h */
fbtk_callback
fbtk_get_handler(fbtk_widget_t *widget, fbtk_callback_type cbt)
{
if ((cbt <= FBTK_CBT_START) || (cbt >= FBTK_CBT_END)) {
/* type out of range, no way to report error so return NULL */
return NULL;
}
 
return widget->callback[cbt];
}
 
/* exported function documented in fbtk.h */
fbtk_callback
fbtk_set_handler(fbtk_widget_t *widget,
fbtk_callback_type cbt,
fbtk_callback cb,
void *context)
{
fbtk_callback prevcb;
 
if ((cbt <= FBTK_CBT_START) || (cbt >= FBTK_CBT_END)) {
/* type out of range, no way to report error so return NULL */
return NULL;
}
 
prevcb = widget->callback[cbt];
 
widget->callback[cbt] = cb;
widget->callback_context[cbt] = context;
 
return prevcb;
}
 
/* exported function docuemnted in fbtk.h */
int
fbtk_post_callback(fbtk_widget_t *widget, fbtk_callback_type cbt, ...)
{
LOG(("DO POST CALLBACK"));
//__menuet__debug_out("\n***********\nDO POST CALLBACK\n********\n");
fbtk_callback_info cbi;
int ret = 0;
va_list ap;
 
if (widget == NULL)
return -1;
/* if the widget is not mapped do not attempt to post any
* events to it
*/
if (widget->mapped == false)
return ret;
 
LOG(("DO POST CALLBACK 2"));
//__menuet__debug_out("\n***********\nDO POST CALLBACK 2\n********\n");
 
if (widget->callback[cbt] != NULL) {
cbi.type = cbt;
cbi.context = widget->callback_context[cbt];
 
LOG(("DO POST CALLBACK 3 - VA"));
//__menuet__debug_out("\n***********\nDO POST CALLBACK 3 - VA\n********\n");
va_start(ap, cbt);
 
switch (cbt) {
case FBTK_CBT_SCROLLX:
//__menuet__debug_out("\n***********\n scroll x - VA\n********\n");
cbi.x = va_arg(ap,int);
break;
 
case FBTK_CBT_SCROLLY:
//__menuet__debug_out("\n***********\n scroll y - VA\n********\n");
cbi.y = va_arg(ap,int);
break;
 
case FBTK_CBT_CLICK:
//__menuet__debug_out("\n***********\n click - VA\n********\n");
cbi.event = va_arg(ap, void *);
cbi.x = va_arg(ap, int);
cbi.y = va_arg(ap, int);
break;
 
case FBTK_CBT_INPUT:
//__menuet__debug_out("\n***********\n input - VA\n********\n");
cbi.event = va_arg(ap, void *);
break;
 
case FBTK_CBT_POINTERMOVE:
//__menuet__debug_out("\n***********\n mouse move - VA\n********\n");
cbi.x = va_arg(ap, int);
cbi.y = va_arg(ap, int);
break;
 
case FBTK_CBT_REDRAW:
//__menuet__debug_out("\n***********\n red - VA\n********\n");
break;
 
case FBTK_CBT_USER:
//__menuet__debug_out("\n***********\n user - VA\n********\n");
break;
 
case FBTK_CBT_STRIP_FOCUS:
//__menuet__debug_out("\n***********\n focus - VA\n********\n");
break;
 
default:
//__menuet__debug_out("\n***********\n wtf - VA\n********\n");
break;
}
LOG(("DO POST CALLBACK free"));
//__menuet__debug_out("\n***********\nDO POST CALLBACK free\n********\n");
va_end(ap);
 
LOG(("DO CALLBACK YEAH"));
//__menuet__debug_out("\n***********\nWTF IS THIS\n********\n");
char zupa[64];
sprintf (zupa, "ADDRESS of callback is %x \n",(widget->callback[cbt]));
//__menuet__debug_out(zupa);
LOG(("ADDRESS of callback is %x \n",(widget->callback[cbt])));
ret = (widget->callback[cbt])(widget, &cbi);
LOG(("DO CALLBACK YEAH 2"));
//__menuet__debug_out("\n***********\nWTF IS THIS!!!12121\n********\n");
}
 
LOG(("DO POST CALLBACK OK"));
//__menuet__debug_out("\n***********\nDO POST CALLBACK OK\n********\n");
return ret;
}
 
/* exported function docuemnted in fbtk.h */
void
fbtk_set_focus(fbtk_widget_t *widget)
{
fbtk_widget_t *root;
 
/* ensure we have the root widget */
root = fbtk_get_root_widget(widget);
 
if (root->u.root.input != NULL &&
root->u.root.input != widget) {
/* inform previous holder of focus that it's being stripped
* of focus */
fbtk_post_callback(root->u.root.input, FBTK_CBT_STRIP_FOCUS);
}
 
root->u.root.input = widget;
}
 
 
 
/* exported function docuemnted in fbtk.h */
nsfb_t *
fbtk_get_nsfb(fbtk_widget_t *widget)
{
fbtk_widget_t *root;
 
/* ensure we have the root widget */
root = fbtk_get_root_widget(widget);
 
return root->u.root.fb;
}
 
/* exported function docuemnted in fbtk.h */
fbtk_widget_t *
fbtk_init(nsfb_t *fb)
{
fbtk_widget_t *root;
 
/* create and configure root widget */
root = calloc(1, sizeof(fbtk_widget_t));
if (root == NULL)
return NULL;
 
root->type = FB_WIDGET_TYPE_ROOT;
root->u.root.fb = fb;
root->u.root.caret.owner = NULL;
 
nsfb_get_geometry(fb, &root->width, &root->height, NULL);
 
root->mapped = true;
 
return root;
}
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/fbtk/fill.c
0,0 → 1,81
/*
* Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
*
* Framebuffer windowing toolkit filled area widget
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdbool.h>
#include <stdlib.h>
 
#include <libnsfb.h>
#include <libnsfb_plot.h>
 
#include "desktop/browser.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
#include "widget.h"
 
static int
fb_redraw_fill(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
nsfb_bbox_t bbox;
nsfb_t *nsfb;
 
nsfb = fbtk_get_nsfb(widget);
 
fbtk_get_bbox(widget, &bbox);
 
nsfb_claim(nsfb, &bbox);
 
/* clear background */
if ((widget->bg & 0xFF000000) != 0) {
/* transparent polygon filling isnt working so fake it */
nsfb_plot_rectangle_fill(nsfb, &bbox, widget->bg);
}
 
nsfb_update(nsfb, &bbox);
 
return 0;
}
 
/* exported function documented in fbtk.h */
fbtk_widget_t *
fbtk_create_fill(fbtk_widget_t *parent,
int x,
int y,
int width,
int height,
colour c)
{
fbtk_widget_t *neww;
 
neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_FILL, x, y, width, height);
neww->bg = c;
neww->mapped = true;
 
fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_fill, NULL);
 
return neww;
}
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/fbtk/make.fbtk
0,0 → 1,7
OBJS = fbtk.o event.o fill.o bitmap.o user.o window.o \
text.o scroll.o osk.o
 
OUTFILE = TEST.o
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include
include $(MENUETDEV)/makefiles/Makefile_for_o_lib
 
/programs/network/netsurf/netsurf/framebuffer/fbtk/osk.c
0,0 → 1,199
/*
* Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
*
* Framebuffer windowing toolkit on screen keyboard.
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdbool.h>
#include <limits.h>
 
#include <libnsfb.h>
#include <libnsfb_plot.h>
#include <libnsfb_event.h>
#include <libnsfb_cursor.h>
 
#include "utils/log.h"
#include "desktop/browser.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
#include "framebuffer/image_data.h"
 
#include "widget.h"
 
struct kbd_button_s {
int x;
int y;
int w;
int h;
const char *t;
enum nsfb_key_code_e keycode;
};
 
#define KEYCOUNT 58
 
static struct kbd_button_s kbdbase[KEYCOUNT] = {
{ 0, 0, 20, 15, "`", NSFB_KEY_BACKQUOTE},
{ 20, 0, 20, 15, "1", NSFB_KEY_1},
{ 40, 0, 20, 15, "2", NSFB_KEY_2},
{ 60, 0, 20, 15, "3", NSFB_KEY_3},
{ 80, 0, 20, 15, "4", NSFB_KEY_4},
{ 100, 0, 20, 15, "5", NSFB_KEY_5},
{ 120, 0, 20, 15, "6", NSFB_KEY_6},
{ 140, 0, 20, 15, "7", NSFB_KEY_7},
{ 160, 0, 20, 15, "8", NSFB_KEY_8},
{ 180, 0, 20, 15, "9", NSFB_KEY_9},
{ 200, 0, 20, 15, "0", NSFB_KEY_0},
{ 220, 0, 20, 15, "-", NSFB_KEY_MINUS},
{ 240, 0, 20, 15, "=", NSFB_KEY_EQUALS},
{ 260, 0, 40, 15, "\xe2\x8c\xab", NSFB_KEY_BACKSPACE},
{ 0, 15, 30, 15, "\xe2\x86\xb9", NSFB_KEY_TAB},
{ 30, 15, 20, 15, "q", NSFB_KEY_q},
{ 50, 15, 20, 15, "w", NSFB_KEY_w},
{ 70, 15, 20, 15, "e", NSFB_KEY_e},
{ 90, 15, 20, 15, "r", NSFB_KEY_r},
{ 110, 15, 20, 15, "t", NSFB_KEY_t},
{ 130, 15, 20, 15, "y", NSFB_KEY_y},
{ 150, 15, 20, 15, "u", NSFB_KEY_u},
{ 170, 15, 20, 15, "i", NSFB_KEY_i},
{ 190, 15, 20, 15, "o", NSFB_KEY_o},
{ 210, 15, 20, 15, "p", NSFB_KEY_p},
{ 230, 15, 20, 15, "[", NSFB_KEY_LEFTBRACKET},
{ 250, 15, 20, 15, "]", NSFB_KEY_RIGHTBRACKET},
{ 275, 15, 25, 30, "\xe2\x8f\x8e", NSFB_KEY_RETURN},
{ 35, 30, 20, 15, "a", NSFB_KEY_a},
{ 55, 30, 20, 15, "s", NSFB_KEY_s},
{ 75, 30, 20, 15, "d", NSFB_KEY_d},
{ 95, 30, 20, 15, "f", NSFB_KEY_f},
{ 115, 30, 20, 15, "g", NSFB_KEY_g},
{ 135, 30, 20, 15, "h", NSFB_KEY_h},
{ 155, 30, 20, 15, "j", NSFB_KEY_j},
{ 175, 30, 20, 15, "k", NSFB_KEY_k},
{ 195, 30, 20, 15, "l", NSFB_KEY_l},
{ 215, 30, 20, 15, ";", NSFB_KEY_SEMICOLON},
{ 235, 30, 20, 15, "'", NSFB_KEY_l},
{ 255, 30, 20, 15, "#", NSFB_KEY_HASH},
{ 0, 45, 25, 15, "\xe2\x87\xa7", NSFB_KEY_LSHIFT},
{ 25, 45, 20, 15, "\\", NSFB_KEY_SLASH},
{ 45, 45, 20, 15, "z", NSFB_KEY_z},
{ 65, 45, 20, 15, "x", NSFB_KEY_x},
{ 85, 45, 20, 15, "c", NSFB_KEY_c},
{ 105, 45, 20, 15, "v", NSFB_KEY_v},
{ 125, 45, 20, 15, "b", NSFB_KEY_b},
{ 145, 45, 20, 15, "n", NSFB_KEY_n},
{ 165, 45, 20, 15, "m", NSFB_KEY_m},
{ 185, 45, 20, 15, ",", NSFB_KEY_COMMA},
{ 205, 45, 20, 15, ".", NSFB_KEY_PERIOD},
{ 225, 45, 20, 15, "/", NSFB_KEY_BACKSLASH},
{ 245, 45, 55, 15, "\xe2\x87\xa7", NSFB_KEY_RSHIFT},
{ 40, 67, 185, 15, "", NSFB_KEY_SPACE},
{ 250, 60, 20, 15, "\xe2\x96\xb2", NSFB_KEY_UP},
{ 230, 67, 20, 15, "\xe2\x97\x80", NSFB_KEY_LEFT},
{ 270, 67, 20, 15, "\xe2\x96\xb6", NSFB_KEY_RIGHT},
{ 250, 75, 20, 15, "\xe2\x96\xbc", NSFB_KEY_DOWN},
};
 
static fbtk_widget_t *osk;
 
static int
osk_close(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
if (cbi->event->type != NSFB_EVENT_KEY_UP)
return 0;
 
fbtk_set_mapping(osk, false);
 
return 0;
}
 
static int
osk_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
nsfb_event_t event;
struct kbd_button_s *kbd_button = cbi->context;
 
event.type = cbi->event->type;
event.value.keycode = kbd_button->keycode;
fbtk_input(widget, &event);
 
return 0;
}
 
/* exported function documented in fbtk.h */
void
fbtk_enable_oskb(fbtk_widget_t *fbtk)
{
fbtk_widget_t *widget;
int kloop;
int maxx = 0;
int maxy = 0;
int ww;
int wh;
fbtk_widget_t *root = fbtk_get_root_widget(fbtk);
int furniture_width = 18;
 
for (kloop=0; kloop < KEYCOUNT; kloop++) {
if ((kbdbase[kloop].x + kbdbase[kloop].w) > maxx)
maxx=kbdbase[kloop].x + kbdbase[kloop].w;
if ((kbdbase[kloop].y + kbdbase[kloop].h) > maxy)
maxy=kbdbase[kloop].y + kbdbase[kloop].h;
}
 
ww = fbtk_get_width(root);
 
/* scale window height apropriately */
wh = (maxy * ww) / maxx;
 
osk = fbtk_create_window(root, 0, fbtk_get_height(root) - wh, 0, wh, 0xff202020);
 
for (kloop=0; kloop < KEYCOUNT; kloop++) {
widget = fbtk_create_text_button(osk,
(kbdbase[kloop].x * ww) / maxx,
(kbdbase[kloop].y * ww) / maxx,
(kbdbase[kloop].w * ww) / maxx,
(kbdbase[kloop].h *ww) / maxx,
FB_FRAME_COLOUR,
FB_COLOUR_BLACK,
osk_click,
&kbdbase[kloop]);
fbtk_set_text(widget, kbdbase[kloop].t);
}
 
widget = fbtk_create_button(osk,
fbtk_get_width(osk) - furniture_width,
fbtk_get_height(osk) - furniture_width,
furniture_width,
furniture_width,
FB_FRAME_COLOUR,
&osk_image,
osk_close,
NULL);
}
 
/* exported function documented in fbtk.h */
void
map_osk(void)
{
fbtk_set_zorder(osk, INT_MIN);
fbtk_set_mapping(osk, true);
}
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/fbtk/scroll.c
0,0 → 1,619
/*
* Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
*
* Framebuffer windowing toolkit scrollbar widgets
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
 
#include <stdbool.h>
 
#include <libnsfb.h>
#include <libnsfb_plot.h>
#include <libnsfb_event.h>
#include <libnsfb_cursor.h>
 
#include "utils/log.h"
#include "desktop/browser.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
#include "framebuffer/image_data.h"
 
 
 
#include "utils/log.h"
#include <menuet/os.h>
 
#include "widget.h"
 
/* Vertical scroll widget */
 
static int
vscroll_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
LOG(("REDRAW SCROLL"));
//__menuet__debug_out("REDRAW SCROLL");
int vscroll;
int vpos;
 
nsfb_bbox_t bbox;
nsfb_bbox_t rect;
LOG(("REDRAW SCROLL get rooot"));
//__menuet__debug_out("REDRAW SCROLL get root");
fbtk_widget_t *root = fbtk_get_root_widget(widget);
 
 
LOG(("REDRAW SCROLL get bbox"));
//__menuet__debug_out("REDRAW SCROLL get bbox");
fbtk_get_bbox(widget, &bbox);
 
LOG(("REDRAW SCROLL claim"));
//__menuet__debug_out("REDRAW SCROLL claim");
nsfb_claim(root->u.root.fb, &bbox);
 
rect = bbox;
 
/* background */
//STUB
nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->bg);
 
/* scroll well */
rect.x0 = bbox.x0 + 2;
rect.y0 = bbox.y0 + 1;
rect.x1 = bbox.x1 - 3;
rect.y1 = bbox.y1 - 2;
 
 
//STUB!!!
nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->fg);
nsfb_plot_rectangle(root->u.root.fb, &rect, 1, 0xFF999999, false, false);
 
LOG(("REDRAW SCROLL widg"));
//__menuet__debug_out("REDRAW SCROLL widg");
 
/* scroll bar */
if ((widget->u.scroll.maximum - widget->u.scroll.minimum) > 0) {
vscroll = ((widget->height - 4) * widget->u.scroll.thumb) /
(widget->u.scroll.maximum - widget->u.scroll.minimum) ;
vpos = ((widget->height - 4) * widget->u.scroll.position) /
(widget->u.scroll.maximum - widget->u.scroll.minimum) ;
} else {
vscroll = (widget->height - 4);
vpos = 0;
}
 
rect.x0 = bbox.x0 + 5;
rect.y0 = bbox.y0 + 3 + vpos;
rect.x1 = bbox.x0 + widget->width - 5;
rect.y1 = bbox.y0 + vscroll + vpos;
 
//STUB!!!
nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->bg);
 
LOG(("REDRAW SCROLL upd"));
//__menuet__debug_out("RED upd");
 
//STUB
nsfb_update(root->u.root.fb, &bbox); //&bbox
 
return 0;
}
 
static int
vscroll_drag(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
LOG(("REDRAG SCROLL"));
//__menuet__debug_out("REDRAG SCROLL");
int newpos;
fbtk_widget_t *scrollw = cbi->context;
 
newpos = ((widget->u.scroll.drag_position +
(cbi->y - widget->u.scroll.drag)) *
(widget->u.scroll.maximum - widget->u.scroll.minimum)) /
(widget->height - 4);
 
if (newpos < scrollw->u.scroll.minimum)
newpos = scrollw->u.scroll.minimum;
 
if (newpos > (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb ))
newpos = (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb);
 
if (newpos == scrollw->u.scroll.position)
return 0;
 
return fbtk_post_callback(widget, FBTK_CBT_SCROLLY, newpos);
}
 
static int
vscrollu_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
LOG(("REDRAW Ck SCROLL"));
//__menuet__debug_out("REDRAW Ck SCROLL");
int newpos;
fbtk_widget_t *scrollw = cbi->context;
 
if (cbi->event->type != NSFB_EVENT_KEY_DOWN)
return 0;
 
newpos = scrollw->u.scroll.position - scrollw->u.scroll.page;
if (newpos < scrollw->u.scroll.minimum)
newpos = scrollw->u.scroll.minimum;
 
if (newpos == scrollw->u.scroll.position)
return 0;
 
return fbtk_post_callback(scrollw, FBTK_CBT_SCROLLY, newpos);
}
 
static int
vscrolld_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
LOG(("REDRAW SCROLL 2"));
//__menuet__debug_out("REDRAW SCROLL 2");
int newpos;
fbtk_widget_t *scrollw = cbi->context;
 
if (cbi->event->type != NSFB_EVENT_KEY_DOWN)
return 0;
 
newpos = scrollw->u.scroll.position + scrollw->u.scroll.page;
if (newpos > (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb ))
newpos = (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb);
 
if (newpos == scrollw->u.scroll.position)
return 0;
 
return fbtk_post_callback(scrollw, FBTK_CBT_SCROLLY, newpos);
}
 
static int
vscrollarea_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
LOG(("REDRAW SCROLL 3"));
//__menuet__debug_out("REDRAW SCROLL 3");
int vscroll;
int vpos;
int newpos;
int ret = 0;
 
if (cbi->event->type != NSFB_EVENT_KEY_DOWN) {
/* end all drags, just in case */
if (fbtk_set_handler(widget, FBTK_CBT_POINTERMOVE, NULL, NULL) != NULL)
fbtk_tgrab_pointer(widget);
return 0;
}
 
switch (cbi->event->value.keycode) {
 
case NSFB_KEY_MOUSE_4:
/* scroll up */
newpos = widget->u.scroll.position - widget->u.scroll.page;
if (newpos < widget->u.scroll.minimum)
newpos = widget->u.scroll.minimum;
ret = fbtk_post_callback(cbi->context, FBTK_CBT_SCROLLY, newpos);
break;
 
case NSFB_KEY_MOUSE_5:
/* scroll down */
newpos = widget->u.scroll.position + widget->u.scroll.page;
if (newpos > widget->u.scroll.maximum)
newpos = widget->u.scroll.maximum;
ret = fbtk_post_callback(cbi->context, FBTK_CBT_SCROLLY, newpos);
break;
 
default:
 
if ((widget->u.scroll.maximum - widget->u.scroll.minimum) > 0) {
vscroll = ((widget->height - 4) * widget->u.scroll.thumb) /
(widget->u.scroll.maximum - widget->u.scroll.minimum) ;
vpos = ((widget->height - 4) * widget->u.scroll.position) /
(widget->u.scroll.maximum - widget->u.scroll.minimum) ;
} else {
vscroll = (widget->height - 4);
vpos = 0;
}
 
if (cbi->y < vpos) {
/* above bar */
newpos = widget->u.scroll.position - widget->u.scroll.thumb;
if (newpos < widget->u.scroll.minimum)
newpos = widget->u.scroll.minimum;
ret = fbtk_post_callback(cbi->context, FBTK_CBT_SCROLLY, newpos);
} else if (cbi->y > (vpos + vscroll)) {
/* below bar */
newpos = widget->u.scroll.position + widget->u.scroll.thumb;
if (newpos > widget->u.scroll.maximum)
newpos = widget->u.scroll.maximum;
ret = fbtk_post_callback(cbi->context, FBTK_CBT_SCROLLY, newpos);
} else {
/* on bar - start drag */
widget->u.scroll.drag = cbi->y;
widget->u.scroll.drag_position = vpos;
fbtk_set_handler(widget, FBTK_CBT_POINTERMOVE, vscroll_drag, widget);
fbtk_tgrab_pointer(widget);
}
}
return ret;
}
 
 
/* exported function documented in fbtk.h */
fbtk_widget_t *
fbtk_create_vscroll(fbtk_widget_t *parent,
int x,
int y,
int width,
int height,
colour fg,
colour bg,
fbtk_callback callback,
void *context)
{
LOG(("REDRAW SCROLL 4"));
//__menuet__debug_out("REDRAW SCROLL 4");
fbtk_widget_t *neww;
 
neww = fbtk_widget_new(parent,
FB_WIDGET_TYPE_VSCROLL,
x,
y + scrollu.height,
width,
height - scrollu.height - scrolld.height);
 
neww->fg = fg;
neww->bg = bg;
neww->mapped = true;
 
fbtk_set_handler(neww, FBTK_CBT_REDRAW, vscroll_redraw, NULL);
 
fbtk_set_handler(neww, FBTK_CBT_CLICK, vscrollarea_click, neww);
 
fbtk_set_handler(neww, FBTK_CBT_SCROLLY, callback, context);
 
neww->u.scroll.btnul = fbtk_create_button(parent,
x,
y,
width,
scrollu.height,
fg,
&scrollu,
vscrollu_click,
neww);
 
neww->u.scroll.btndr = fbtk_create_button(parent,
x,
y + height - scrolld.height,
width,
scrolld.height,
fg,
&scrolld,
vscrolld_click,
neww);
 
 
return neww;
}
 
/* Horizontal scroll widget */
 
static int
hscroll_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
LOG(("REDRAW SCROLL 5"));
//__menuet__debug_out("REDRAW SCROLL 5");
int hscroll;
int hpos;
nsfb_bbox_t bbox;
nsfb_bbox_t rect;
fbtk_widget_t *root = fbtk_get_root_widget(widget);
 
fbtk_get_bbox(widget, &bbox);
 
nsfb_claim(root->u.root.fb, &bbox);
 
rect = bbox;
 
/* background */
//STUB
nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->bg);
 
/* scroll well */
rect.x0 = bbox.x0 + 1;
rect.y0 = bbox.y0 + 2;
rect.x1 = bbox.x1 - 2;
rect.y1 = bbox.y1 - 3;
//STUB
nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->fg);
 
/* scroll well outline */
//STUB
nsfb_plot_rectangle(root->u.root.fb, &rect, 1, 0xFF999999, false, false);
 
if ((widget->u.scroll.maximum - widget->u.scroll.minimum) > 0) {
hscroll = ((widget->width - 4) * widget->u.scroll.thumb) /
(widget->u.scroll.maximum - widget->u.scroll.minimum) ;
hpos = ((widget->width - 4) * widget->u.scroll.position) /
(widget->u.scroll.maximum - widget->u.scroll.minimum) ;
} else {
hscroll = (widget->width - 4);
hpos = 0;
}
 
LOG(("hscroll %d", hscroll));
 
rect.x0 = bbox.x0 + 3 + hpos;
rect.y0 = bbox.y0 + 5;
rect.x1 = bbox.x0 + hscroll + hpos;
rect.y1 = bbox.y0 + widget->height - 5;
 
 
//STUB
nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->bg);
 
nsfb_update(root->u.root.fb, &bbox);
 
return 0;
}
 
static int
hscrolll_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
LOG(("REDRAW SCROLL 6"));
//__menuet__debug_out("REDRAW SCROLL 6");
int newpos;
fbtk_widget_t *scrollw = cbi->context;
 
if (cbi->event->type != NSFB_EVENT_KEY_DOWN)
return 0;
 
newpos = scrollw->u.scroll.position - scrollw->u.scroll.page;
if (newpos < scrollw->u.scroll.minimum)
newpos = scrollw->u.scroll.minimum;
 
if (newpos == scrollw->u.scroll.position) {
LOG(("horiz scroll was the same %d", newpos));
return 0;
}
 
return fbtk_post_callback(scrollw, FBTK_CBT_SCROLLX, newpos);
}
 
static int
hscrollr_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
LOG(("REDRAW SCROLL 7"));
//__menuet__debug_out("REDRAW SCROLL 7");
int newpos;
fbtk_widget_t *scrollw = cbi->context;
 
if (cbi->event->type != NSFB_EVENT_KEY_DOWN)
return 0;
 
newpos = scrollw->u.scroll.position + scrollw->u.scroll.page;
if (newpos > (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb ))
newpos = (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb);
 
if (newpos == scrollw->u.scroll.position)
return 0;
 
return fbtk_post_callback(scrollw, FBTK_CBT_SCROLLX, newpos);
}
 
static int
hscroll_drag(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
LOG(("REDRAW SCROLL 8"));
//__menuet__debug_out("REDRAW SCROLL 8");
int newpos;
fbtk_widget_t *scrollw = cbi->context;
 
newpos = ((widget->u.scroll.drag_position +
(cbi->x - widget->u.scroll.drag)) *
(widget->u.scroll.maximum - widget->u.scroll.minimum)) /
(widget->width - 4);
 
if (newpos < scrollw->u.scroll.minimum)
newpos = scrollw->u.scroll.minimum;
 
if (newpos > (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb ))
newpos = (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb);
 
if (newpos == scrollw->u.scroll.position)
return 0;
 
return fbtk_post_callback(widget, FBTK_CBT_SCROLLX, newpos);
}
 
static int
hscrollarea_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
LOG(("REDRAW SCROLL 9"));
//__menuet__debug_out("REDRAW SCROLL 9");
int hscroll;
int hpos;
int newpos;
int ret = 0;
 
if (cbi->event->type != NSFB_EVENT_KEY_DOWN) {
/* end all drags, just in case */
if (fbtk_set_handler(widget, FBTK_CBT_POINTERMOVE, NULL, NULL) != NULL)
fbtk_tgrab_pointer(widget);
return 0;
}
 
if ((widget->u.scroll.maximum - widget->u.scroll.minimum) > 0) {
hscroll = ((widget->width - 4) * widget->u.scroll.thumb) /
(widget->u.scroll.maximum - widget->u.scroll.minimum) ;
hpos = ((widget->width - 4) * widget->u.scroll.position) /
(widget->u.scroll.maximum - widget->u.scroll.minimum) ;
} else {
hscroll = (widget->width - 4);
hpos = 0;
}
 
if (cbi->x < hpos) {
/* left of bar */
newpos = widget->u.scroll.position - widget->u.scroll.page;
if (newpos < widget->u.scroll.minimum)
newpos = widget->u.scroll.minimum;
ret = fbtk_post_callback(cbi->context, FBTK_CBT_SCROLLX, newpos);
} else if (cbi->x > (hpos + hscroll)) {
/* right of bar */
newpos = widget->u.scroll.position + widget->u.scroll.page;
if (newpos > widget->u.scroll.maximum)
newpos = widget->u.scroll.maximum;
ret = fbtk_post_callback(cbi->context, FBTK_CBT_SCROLLX, newpos);
} else {
/* on bar - start drag */
widget->u.scroll.drag = cbi->x;
widget->u.scroll.drag_position = hpos;
fbtk_set_handler(widget, FBTK_CBT_POINTERMOVE, hscroll_drag, widget);
fbtk_tgrab_pointer(widget);
}
return ret;
}
 
/* exported function documented in fbtk.h */
fbtk_widget_t *
fbtk_create_hscroll(fbtk_widget_t *parent,
int x,
int y,
int width,
int height,
colour fg,
colour bg,
fbtk_callback callback,
void *context)
{
LOG(("REDRAW SCROLL 10"));
//__menuet__debug_out("REDRAW SCROLL 10");
fbtk_widget_t *neww;
 
neww = fbtk_widget_new(parent,
FB_WIDGET_TYPE_HSCROLL,
x + scrolll.width,
y,
width - scrolll.width - scrollr.width,
height);
 
neww->fg = fg;
neww->bg = bg;
neww->mapped = true;
 
fbtk_set_handler(neww, FBTK_CBT_REDRAW, hscroll_redraw, NULL);
fbtk_set_handler(neww, FBTK_CBT_CLICK, hscrollarea_click, neww);
fbtk_set_handler(neww, FBTK_CBT_SCROLLX, callback, context);
 
neww->u.scroll.btnul = fbtk_create_button(parent,
x,
y,
scrolll.width,
height,
fg,
&scrolll,
hscrolll_click,
neww);
 
neww->u.scroll.btndr = fbtk_create_button(parent,
x + width - scrollr.width,
y,
scrollr.width,
height,
fg,
&scrollr,
hscrollr_click,
neww);
 
return neww;
}
 
 
/* exported function documented in fbtk.h */
bool
fbtk_set_scroll_parameters(fbtk_widget_t *widget,
int min,
int max,
int thumb,
int page)
{
LOG(("REDRAW SCROLL 11"));
//__menuet__debug_out("REDRAW SCROLL 11");
if (widget == NULL)
return false;
 
if ((widget->type != FB_WIDGET_TYPE_HSCROLL) &&
(widget->type != FB_WIDGET_TYPE_VSCROLL))
return false;
 
widget->u.scroll.minimum = min;
widget->u.scroll.maximum = max;
widget->u.scroll.thumb = thumb;
widget->u.scroll.page = page;
 
if (widget->u.scroll.position > max)
widget->u.scroll.position = max;
if (widget->u.scroll.position < min)
widget->u.scroll.position = min;
 
fbtk_request_redraw(widget);
 
return true;
}
 
/* exported function documented in fbtk.h */
bool
fbtk_set_scroll_position(fbtk_widget_t *widget, int position)
{
LOG(("REDRAW SCROLL 12"));
//__menuet__debug_out("REDRAW SCROLL 12");
if (widget == NULL)
return false;
 
if ((widget->type != FB_WIDGET_TYPE_HSCROLL) &&
(widget->type != FB_WIDGET_TYPE_VSCROLL))
return false;
 
if ((position < widget->u.scroll.minimum) ||
(position > widget->u.scroll.maximum))
return false;
 
widget->u.scroll.position = position;
 
fbtk_request_redraw(widget);
 
return true;
}
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/fbtk/text.c
0,0 → 1,616
/*
* Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
*
* Framebuffer windowing toolkit scrollbar widgets.
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
 
#include <libnsfb.h>
#include <libnsfb_plot.h>
#include <libnsfb_plot_util.h>
#include <libnsfb_event.h>
 
#include "utils/log.h"
#include "desktop/browser.h"
#include "render/font.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
#include "framebuffer/font.h"
#include "framebuffer/framebuffer.h"
#include "framebuffer/image_data.h"
 
#include "widget.h"
 
//#define TEXT_WIDGET_BORDER 3 /**< The pixel border round a text widget. */
 
/* Lighten a colour by taking seven eights of each channel's intensity
* and adding a full eighth
*/
#define brighten_colour(c1) \
(((((7 * ((c1 >> 16) & 0xff)) >> 3) + 32) << 16) | \
((((7 * ((c1 >> 8) & 0xff)) >> 3) + 32) << 8) | \
((((7 * (c1 & 0xff)) >> 3) + 32) << 0))
 
/* Convert pixels to points, assuming a DPI of 90 */
#define px_to_pt(x) (((x) * 72) / FBTK_DPI)
 
/* Get a font style for a text input */
static inline void
fb_text_font_style(fbtk_widget_t *widget, int *font_height, int *padding,
plot_font_style_t *font_style)
{
if (widget->u.text.outline)
*padding = 1;
else
*padding = 0;
 
#ifdef FB_USE_FREETYPE
*padding += widget->height / 6;
*font_height = widget->height - *padding - *padding;
#else
*font_height = font_regular.height;
*padding = (widget->height - *padding - *font_height) / 2;
#endif
 
font_style->family = PLOT_FONT_FAMILY_SANS_SERIF;
font_style->size = px_to_pt(*font_height) * FONT_SIZE_SCALE;
font_style->weight = 400;
font_style->flags = FONTF_NONE;
font_style->background = widget->bg;
font_style->foreground = widget->fg;
}
 
/** Text redraw callback.
*
* Called when a text widget requires redrawing.
*
* @param widget The widget to be redrawn.
* @param cbi The callback parameters.
* @return The callback result.
*/
static int
fb_redraw_text(fbtk_widget_t *widget, fbtk_callback_info *cbi )
{
nsfb_bbox_t bbox;
nsfb_bbox_t rect;
fbtk_widget_t *root;
plot_font_style_t font_style;
int caret_x, caret_y, caret_h;
int fh;
int padding;
int scroll = 0;
bool caret = false;
 
fb_text_font_style(widget, &fh, &padding, &font_style);
 
if (fbtk_get_caret(widget, &caret_x, &caret_y, &caret_h)) {
caret = true;
}
 
root = fbtk_get_root_widget(widget);
 
fbtk_get_bbox(widget, &bbox);
 
rect = bbox;
 
nsfb_claim(root->u.root.fb, &bbox);
 
/* clear background */
if ((widget->bg & 0xFF000000) != 0) {
/* transparent polygon filling isnt working so fake it */
nsfb_plot_rectangle_fill(root->u.root.fb, &bbox, widget->bg);
}
 
/* widget can have a single pixel outline border */
if (widget->u.text.outline) {
rect.x1--;
rect.y1--;
nsfb_plot_rectangle(root->u.root.fb, &rect, 1,
0x00000000, false, false);
}
 
if (widget->u.text.text != NULL) {
int x = bbox.x0 + padding;
int y = bbox.y0 + ((fh * 3 + 2) / 4) + padding;
 
#ifdef FB_USE_FREETYPE
/* Freetype renders text higher */
y += 1;
#endif
 
if (caret && widget->width - padding - padding < caret_x) {
scroll = (widget->width - padding - padding) - caret_x;
x += scroll;
}
 
/* Call the fb text plotting, baseline is 3/4 down the font */
fb_plotters.text(x, y, widget->u.text.text,
widget->u.text.len, &font_style);
}
 
if (caret) {
/* This widget has caret, so render it */
nsfb_t *nsfb = fbtk_get_nsfb(widget);
nsfb_bbox_t line;
nsfb_plot_pen_t pen;
 
line.x0 = bbox.x0 + caret_x + scroll;
line.y0 = bbox.y0 + caret_y;
line.x1 = bbox.x0 + caret_x + scroll;
line.y1 = bbox.y0 + caret_y + caret_h;
 
pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID;
pen.stroke_width = 1;
pen.stroke_colour = 0xFF0000FF;
 
nsfb_plot_line(nsfb, &line, &pen);
}
 
nsfb_update(root->u.root.fb, &bbox);
 
return 0;
}
 
/** Text button redraw callback.
*
* Called when a text widget requires redrawing.
*
* @param widget The widget to be redrawn.
* @param cbi The callback parameters.
* @return The callback result.
*/
static int
fb_redraw_text_button(fbtk_widget_t *widget, fbtk_callback_info *cbi )
{
nsfb_bbox_t bbox;
nsfb_bbox_t rect;
nsfb_bbox_t line;
nsfb_plot_pen_t pen;
plot_font_style_t font_style;
int fh;
int border;
fbtk_widget_t *root = fbtk_get_root_widget(widget);
 
fb_text_font_style(widget, &fh, &border, &font_style);
 
pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID;
pen.stroke_width = 1;
pen.stroke_colour = brighten_colour(widget->bg);
 
fbtk_get_bbox(widget, &bbox);
 
rect = bbox;
rect.x1--;
rect.y1--;
 
nsfb_claim(root->u.root.fb, &bbox);
 
/* clear background */
if ((widget->bg & 0xFF000000) != 0) {
/* transparent polygon filling isnt working so fake it */
nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->bg);
}
 
if (widget->u.text.outline) {
line.x0 = rect.x0;
line.y0 = rect.y0;
line.x1 = rect.x0;
line.y1 = rect.y1;
nsfb_plot_line(root->u.root.fb, &line, &pen);
line.x0 = rect.x0;
line.y0 = rect.y0;
line.x1 = rect.x1;
line.y1 = rect.y0;
nsfb_plot_line(root->u.root.fb, &line, &pen);
pen.stroke_colour = darken_colour(widget->bg);
line.x0 = rect.x0;
line.y0 = rect.y1;
line.x1 = rect.x1;
line.y1 = rect.y1;
nsfb_plot_line(root->u.root.fb, &line, &pen);
line.x0 = rect.x1;
line.y0 = rect.y0;
line.x1 = rect.x1;
line.y1 = rect.y1;
nsfb_plot_line(root->u.root.fb, &line, &pen);
}
 
if (widget->u.text.text != NULL) {
/* Call the fb text plotting, baseline is 3/4 down the font */
fb_plotters.text(bbox.x0 + border,
bbox.y0 + ((fh * 3) / 4) + border,
widget->u.text.text,
widget->u.text.len,
&font_style);
}
 
nsfb_update(root->u.root.fb, &bbox);
 
return 0;
}
 
static void
fb_text_input_remove_caret_cb(fbtk_widget_t *widget)
{
int c_x, c_y, c_h;
 
if (fbtk_get_caret(widget, &c_x, &c_y, &c_h)) {
fbtk_request_redraw(widget);
}
}
 
/** Routine called when text events occour in writeable widget.
*
* @param widget The widget reciving input events.
* @param cbi The callback parameters.
* @return The callback result.
*/
static int
text_input(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
int value;
static fbtk_modifier_type modifier = FBTK_MOD_CLEAR;
char *temp;
plot_font_style_t font_style;
int fh;
int border;
bool caret_moved = false;
 
fb_text_font_style(widget, &fh, &border, &font_style);
 
if (cbi->event == NULL) {
/* gain focus */
if (widget->u.text.text == NULL)
widget->u.text.text = calloc(1,1);
 
return 0;
}
 
value = cbi->event->value.keycode;
 
if (cbi->event->type != NSFB_EVENT_KEY_DOWN) {
switch (value) {
case NSFB_KEY_RSHIFT:
modifier &= ~FBTK_MOD_RSHIFT;
break;
 
case NSFB_KEY_LSHIFT:
modifier &= ~FBTK_MOD_LSHIFT;
break;
 
case NSFB_KEY_RCTRL:
modifier &= ~FBTK_MOD_RCTRL;
break;
 
case NSFB_KEY_LCTRL:
modifier &= ~FBTK_MOD_LCTRL;
break;
 
default:
break;
}
return 0;
}
 
switch (value) {
case NSFB_KEY_BACKSPACE:
if (widget->u.text.idx <= 0)
break;
memmove(widget->u.text.text + widget->u.text.idx - 1,
widget->u.text.text + widget->u.text.idx,
widget->u.text.len - widget->u.text.idx);
widget->u.text.idx--;
widget->u.text.len--;
widget->u.text.text[widget->u.text.len] = 0;
 
nsfont.font_width(&font_style, widget->u.text.text,
widget->u.text.len, &widget->u.text.width);
 
caret_moved = true;
break;
 
case NSFB_KEY_RETURN:
widget->u.text.enter(widget->u.text.pw, widget->u.text.text);
break;
 
case NSFB_KEY_RIGHT:
if (widget->u.text.idx < widget->u.text.len) {
if (modifier == FBTK_MOD_CLEAR)
widget->u.text.idx++;
else
widget->u.text.idx = widget->u.text.len;
 
caret_moved = true;
}
break;
 
case NSFB_KEY_LEFT:
if (widget->u.text.idx > 0) {
if (modifier == FBTK_MOD_CLEAR)
widget->u.text.idx--;
else
widget->u.text.idx = 0;
 
caret_moved = true;
}
break;
 
case NSFB_KEY_PAGEUP:
case NSFB_KEY_PAGEDOWN:
case NSFB_KEY_UP:
case NSFB_KEY_DOWN:
/* Not handling any of these correctly yet, but avoid putting
* charcters in the text widget when they're pressed. */
break;
 
case NSFB_KEY_RSHIFT:
modifier |= FBTK_MOD_RSHIFT;
break;
 
case NSFB_KEY_LSHIFT:
modifier |= FBTK_MOD_LSHIFT;
break;
 
case NSFB_KEY_RCTRL:
modifier |= FBTK_MOD_RCTRL;
break;
 
case NSFB_KEY_LCTRL:
modifier |= FBTK_MOD_LCTRL;
break;
 
default:
if (modifier & FBTK_MOD_LCTRL || modifier & FBTK_MOD_RCTRL) {
/* CTRL pressed, don't enter any text */
if (value == NSFB_KEY_u) {
/* CTRL+U: clear writable */
widget->u.text.idx = 0;
widget->u.text.len = 0;
widget->u.text.text[widget->u.text.len] = '\0';
widget->u.text.width = 0;
caret_moved = true;
}
break;
}
 
/* allow for new character and null */
temp = realloc(widget->u.text.text, widget->u.text.len + 2);
if (temp == NULL) {
break;
}
 
widget->u.text.text = temp;
memmove(widget->u.text.text + widget->u.text.idx + 1,
widget->u.text.text + widget->u.text.idx,
widget->u.text.len - widget->u.text.idx);
widget->u.text.text[widget->u.text.idx] =
fbtk_keycode_to_ucs4(value, modifier);
widget->u.text.idx++;
widget->u.text.len++;
widget->u.text.text[widget->u.text.len] = '\0';
 
nsfont.font_width(&font_style, widget->u.text.text,
widget->u.text.len, &widget->u.text.width);
caret_moved = true;
break;
}
 
if (caret_moved) {
nsfont.font_width(&font_style, widget->u.text.text,
widget->u.text.idx, &widget->u.text.idx_offset);
fbtk_set_caret(widget, true,
widget->u.text.idx_offset + border,
border,
widget->height - border - border,
fb_text_input_remove_caret_cb);
}
 
fbtk_request_redraw(widget);
 
return 0;
}
 
/** Routine called when click events occour in writeable widget.
*
* @param widget The widget reciving click events.
* @param cbi The callback parameters.
* @return The callback result.
*/
static int
text_input_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
plot_font_style_t font_style;
int fh;
int border;
size_t idx;
 
fb_text_font_style(widget, &fh, &border, &font_style);
 
widget->u.text.idx = widget->u.text.len;
 
nsfont.font_position_in_string(&font_style, widget->u.text.text,
widget->u.text.len, cbi->x - border,
&idx,
&widget->u.text.idx_offset);
widget->u.text.idx = idx;
fbtk_set_caret(widget, true,
widget->u.text.idx_offset + border,
border,
widget->height - border - border,
fb_text_input_remove_caret_cb);
 
fbtk_request_redraw(widget);
 
return 0;
}
 
/** Routine called when "stripped of focus" event occours for writeable widget.
*
* @param widget The widget reciving "stripped of focus" event.
* @param cbi The callback parameters.
* @return The callback result.
*/
static int
text_input_strip_focus(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
fbtk_set_caret(widget, false, 0, 0, 0, NULL);
 
return 0;
}
 
/* exported function documented in fbtk.h */
void
fbtk_writable_text(fbtk_widget_t *widget, fbtk_enter_t enter, void *pw)
{
widget->u.text.enter = enter;
widget->u.text.pw = pw;
 
fbtk_set_handler(widget, FBTK_CBT_INPUT, text_input, widget);
}
 
/* exported function documented in fbtk.h */
void
fbtk_set_text(fbtk_widget_t *widget, const char *text)
{
plot_font_style_t font_style;
int c_x, c_y, c_h;
int fh;
int border;
 
if ((widget == NULL) || (widget->type != FB_WIDGET_TYPE_TEXT))
return;
if (widget->u.text.text != NULL) {
if (strcmp(widget->u.text.text, text) == 0)
return; /* text is being set to the same thing */
free(widget->u.text.text);
}
widget->u.text.text = strdup(text);
widget->u.text.len = strlen(text);
widget->u.text.idx = widget->u.text.len;
 
 
fb_text_font_style(widget, &fh, &border, &font_style);
nsfont.font_width(&font_style, widget->u.text.text,
widget->u.text.len, &widget->u.text.width);
nsfont.font_width(&font_style, widget->u.text.text,
widget->u.text.idx, &widget->u.text.idx_offset);
 
if (fbtk_get_caret(widget, &c_x, &c_y, &c_h)) {
/* Widget has caret; move it to end of new string */
fbtk_set_caret(widget, true,
widget->u.text.idx_offset + border,
border,
widget->height - border - border,
fb_text_input_remove_caret_cb);
}
 
fbtk_request_redraw(widget);
}
 
/* exported function documented in fbtk.h */
fbtk_widget_t *
fbtk_create_text(fbtk_widget_t *parent,
int x,
int y,
int width,
int height,
colour bg,
colour fg,
bool outline)
{
fbtk_widget_t *neww;
 
neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_TEXT, x, y, width, height);
neww->fg = fg;
neww->bg = bg;
neww->mapped = true;
neww->u.text.outline = outline;
 
fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_text, NULL);
 
return neww;
}
 
/* exported function documented in fbtk.h */
fbtk_widget_t *
fbtk_create_writable_text(fbtk_widget_t *parent,
int x,
int y,
int width,
int height,
colour bg,
colour fg,
bool outline,
fbtk_enter_t enter,
void *pw)
{
fbtk_widget_t *neww;
 
neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_TEXT, x, y, width, height);
neww->fg = fg;
neww->bg = bg;
neww->mapped = true;
 
neww->u.text.outline = outline;
neww->u.text.enter = enter;
neww->u.text.pw = pw;
 
fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_text, NULL);
fbtk_set_handler(neww, FBTK_CBT_CLICK, text_input_click, pw);
fbtk_set_handler(neww, FBTK_CBT_STRIP_FOCUS, text_input_strip_focus, NULL);
fbtk_set_handler(neww, FBTK_CBT_INPUT, text_input, neww);
 
return neww;
}
 
/* exported function documented in fbtk.h */
fbtk_widget_t *
fbtk_create_text_button(fbtk_widget_t *parent,
int x,
int y,
int width,
int height,
colour bg,
colour fg,
fbtk_callback click,
void *pw)
{
fbtk_widget_t *neww;
 
neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_TEXT, x, y, width, height);
neww->fg = fg;
neww->bg = bg;
neww->mapped = true;
 
neww->u.text.outline = true;
 
fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_text_button, NULL);
fbtk_set_handler(neww, FBTK_CBT_CLICK, click, pw);
fbtk_set_handler(neww, FBTK_CBT_POINTERENTER, fbtk_set_ptr, &hand_image);
 
return neww;
}
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/fbtk/user.c
0,0 → 1,64
/*
* Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
*
* Framebuffer windowing toolkit user widget.
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdlib.h>
#include <stdbool.h>
#include <libnsfb.h>
 
#include "desktop/plotters.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
#include "widget.h"
 
/* exported function documented in fbtk.h */
void *
fbtk_get_userpw(fbtk_widget_t *widget)
{
if ((widget == NULL) ||
(widget->type != FB_WIDGET_TYPE_USER))
return NULL;
 
return widget->u.user.pw;
}
 
/* exported function documented in fbtk.h */
fbtk_widget_t *
fbtk_create_user(fbtk_widget_t *parent,
int x,
int y,
int width,
int height,
void *pw)
{
fbtk_widget_t *neww;
 
neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_USER, x, y, width, height);
neww->u.user.pw = pw;
neww->mapped = true;
 
return neww;
}
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/fbtk/widget.h
0,0 → 1,259
/*
* Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_FB_FBTK_WIDGET_H
#define NETSURF_FB_FBTK_WIDGET_H
 
#include <stdbool.h>
 
enum fbtk_widgettype_e {
FB_WIDGET_TYPE_ROOT = 0,
FB_WIDGET_TYPE_WINDOW,
FB_WIDGET_TYPE_BITMAP,
FB_WIDGET_TYPE_FILL,
FB_WIDGET_TYPE_TEXT,
FB_WIDGET_TYPE_HSCROLL,
FB_WIDGET_TYPE_VSCROLL,
FB_WIDGET_TYPE_USER,
};
 
 
/** Widget description.
*
* A widget is an entry in a tree structure which represents a
* rectangular area with co-ordinates relative to its parent widget.
* This area has a distinct set of callback operations for handling
* events which occour within its boundries. A widget may have an
* arbitrary number of child widgets. The order within the tree
* determines a widgets z order.
*
* ---
* A
* |
* +----------+
* +--->| Button 3 |
* | +----------+
* | | A
* | V |
* | +----------+
* | | Button 2 |
* | +----------+
* | | A
* | V |
* | +----------+
* | | Button 1 |
* | +----------+
* | | A
* | V |
* --- | +----------+
* A | +->| Filled |
* | | | +----------+
* +----------+ | | |
* +---->| |-+ | V
* | | Window 1 | | --- ---
* | | |---+ A
* | +----------+ |
* | | A +----------+ ---
* | | | +--->| Button 2 | A
* | | | | +----------+ |
* | | | | | A +-------------+
* | | | | | | +--->| Button Up |
* | | | | | | | +-------------+
* | | | | | | | | A
* | | | | | | | V |
* | | | | | | | +-------------+
* | | | | | | | | Button Down |
* | | | | | | | +-------------+
* | | | | | | | | A
* | | | | | | | V |
* | | | | | | | +-------------+
* | | | | | | | +->| Scroller |
* | | | | V | | | +-------------+
* | | | | +----------+ | | |
* | | | | | |-+ | V
* | | | | | V Scroll | | ---
* | | | | | |---+
* | | | | +----------+
* | | | | | A
* | | | | V |
* | | | | +----------+
* | | | | +->| Button 1 |
* | | | | | +----------+
* | +----------+ | | |
* | | |-+ | V
* | | Window 2 | | ---
* | | |---+
* | +----------+
* | | A
* | V |
* | +------------+
* --- | | Background |
* A | +->| Bitmap |
* | | | +------------+
* +------+ | | |
* | |-+ | V
* | Root | | ---
* | |---+
* +------+
* |
* V
* ---
*
* Every widget is contained within this generic wrapper. The
* integrated union provides for data specific to a widget type.
*/
struct fbtk_widget_s {
struct fbtk_widget_s *next; /* next lower z ordered widget in tree */
struct fbtk_widget_s *prev; /* next higher z ordered widget in tree */
 
struct fbtk_widget_s *parent; /* parent widget */
 
struct fbtk_widget_s *first_child; /* first child widget */
struct fbtk_widget_s *last_child; /* last child widget */
 
/* flags */
bool mapped; /**< The widget is mapped/visible . */
 
/* Generic properties */
int x;
int y;
int width;
int height;
colour bg;
colour fg;
 
/* event callback handlers */
fbtk_callback callback[FBTK_CBT_END];
void *callback_context[FBTK_CBT_END];
 
/* widget redraw */
struct {
bool child; /* A child of this widget requires redrawing */
bool needed; /* the widget requires redrawing */
int x;
int y;
int width;
int height;
} redraw;
 
enum fbtk_widgettype_e type; /**< The type of the widget */
 
 
union {
/* toolkit base handle */
struct {
nsfb_t *fb;
struct fbtk_widget_s *prev; /* previous widget pointer wasin */
struct fbtk_widget_s *grabbed; /* widget that has grabbed pointer movement. */
struct fbtk_widget_s *input;
 
/* caret */
struct {
struct fbtk_widget_s *owner; /* widget / NULL */
int x; /* relative to owner */
int y; /* relative to owner */
int height;
void (*remove_cb)(fbtk_widget_t *widget);
} caret;
} root;
 
/* bitmap */
struct {
struct fbtk_bitmap *bitmap;
} bitmap;
 
/* text */
struct {
char* text;
bool outline;
fbtk_enter_t enter;
void *pw;
int idx; /* caret pos in text */
int len; /* text length */
int width; /* text width in px */
int idx_offset; /* caret pos in pixels */
} text;
 
/* application driven widget */
struct {
void *pw; /* private data for user widget */
} user;
 
struct {
int minimum; /* lowest value of scrollbar */
int maximum; /* highest value of scrollbar */
int thumb; /* size of bar representing a page */
int page; /* amount to page document */
int position; /* position of bar */
int drag; /* offset to start of drag */
int drag_position; /* indicator bar pos at drag start */
struct fbtk_widget_s *btnul; /* scroll button up/left */
struct fbtk_widget_s *btndr; /* scroll button down/right*/
} scroll;
 
} u;
};
 
 
/* These functions are not considered part of the public API but are
* not static as they are used by the higher level widget provision
* routines
*/
 
 
/** creates a new widget and insert it into to hierachy.
*
* The widget is set to defaults of false, 0 or NULL.
*
* @param parent The parent widget. The new widget will be added with
* the shallowest z order relative to its siblings.
* @param type The type of the widget.
* @param x The x co-ordinate relative to the parent widget.
* @param y The y co-ordinate relative to the parent widget.
* @param width the widgets width. This will be clipped to the parent, if
* the value is 0 the largest extent which can fit within the parent
* is used, if the value is negative the largest value that will fit
* within the parent less the value given will be used.
* @param height the widgets width. This will be clipped to the parent, if
* the value is 0 the largest extent which can fit within the parent
* is used, if the value is negative the largest value that will fit
* within the parent less the value given will be used.
*/
fbtk_widget_t *fbtk_widget_new(fbtk_widget_t *parent, enum fbtk_widgettype_e type, int x, int y, int width, int height);
 
/** find the root widget from any widget in the toolkit hierarchy.
*
* @param widget Any widget.
* @return The root widget or NULL if \a widget was not valid.
*/
fbtk_widget_t *fbtk_get_root_widget(fbtk_widget_t *widget);
 
/** set pointer to bitmap in context.
*
* widget helper callback to set cursor image to the bitmap passed in
* the callbacks private data.
*/
int fbtk_set_ptr(fbtk_widget_t *widget, fbtk_callback_info *cbi);
 
#endif
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/fbtk/window.c
0,0 → 1,98
/*
* Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
*
* Framebuffer windowing toolkit window widget.
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdbool.h>
#include <stdlib.h>
 
#include <libnsfb.h>
#include <libnsfb_plot.h>
 
#include "desktop/browser.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
#include "utils/log.h"
 
 
#include "widget.h"
 
/** Window redraw callback.
*
* Called when a window requires redrawing.
*
* @param widget The widget to be redrawn.
* @param cbi The callback parameters.
* @return The callback result.
*/
static int
fb_redraw_window(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
nsfb_bbox_t bbox;
nsfb_t *nsfb;
 
if ((widget->bg & 0xFF000000) == 0)
return 0;
 
nsfb = fbtk_get_nsfb(widget);
 
fbtk_get_bbox(widget, &bbox);
 
nsfb_claim(nsfb, &bbox);
 
nsfb_plot_rectangle_fill(nsfb, &bbox, widget->bg);
 
nsfb_update(nsfb, &bbox);
 
return 0;
}
 
/* exported function documented in fbtk.h */
fbtk_widget_t *
fbtk_create_window(fbtk_widget_t *parent,
int x,
int y,
int width,
int height,
colour bg)
{
LOG(("FBTK new window"));
fbtk_widget_t *neww;
 
if (parent == NULL)
{LOG(("FBTK no parent window"));return NULL;}
 
LOG(("FBTK new widget"));
neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_WINDOW, x, y, width, height);
 
LOG(("FBTK set bg widget"));
neww->bg = bg;
 
LOG(("FBTK set handler"));
fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_window, NULL);
 
return neww;
}
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/fbtk.h
0,0 → 1,469
/*
* Copyright 2008,2010 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_FB_FBTK_H
#define NETSURF_FB_FBTK_H
 
#ifdef FBTK_LOGGING
#define FBTK_LOG(x) LOG(x)
#else
#define FBTK_LOG(x)
#endif
 
#define FB_SCROLL_COLOUR 0xFFAAAAAA
#define FB_FRAME_COLOUR 0xFFDDDDDD
#define FB_COLOUR_BLACK 0xFF000000
#define FB_COLOUR_WHITE 0xFFFFFFFF
 
#define FBTK_WIDGET_PADDING 30 /* percentage of widget size used for padding */
#define FBTK_DPI 90 /* screen DPI */
 
typedef struct fbtk_widget_s fbtk_widget_t;
 
/* Widget Callback handling */
typedef enum fbtk_callback_type {
FBTK_CBT_START = 0,
FBTK_CBT_SCROLLX,
FBTK_CBT_SCROLLY,
FBTK_CBT_CLICK,
FBTK_CBT_INPUT,
FBTK_CBT_POINTERMOVE,
FBTK_CBT_POINTERLEAVE,
FBTK_CBT_POINTERENTER,
FBTK_CBT_REDRAW,
FBTK_CBT_DESTROY,
FBTK_CBT_USER,
FBTK_CBT_STRIP_FOCUS,
FBTK_CBT_END,
} fbtk_callback_type;
 
typedef struct fbtk_callback_info {
enum fbtk_callback_type type;
void *context;
nsfb_event_t *event;
int x;
int y;
char *text;
fbtk_widget_t *widget;
} fbtk_callback_info;
 
/* structure for framebuffer toolkit bitmaps */
struct fbtk_bitmap {
int width;
int height;
uint8_t *pixdata;
bool opaque;
 
/* The following two are only used for cursors */
int hot_x;
int hot_y;
};
 
/* Key modifier status */
typedef enum fbtk_modifier_type {
FBTK_MOD_CLEAR = 0,
FBTK_MOD_LSHIFT = (1 << 0),
FBTK_MOD_RSHIFT = (1 << 1),
FBTK_MOD_LCTRL = (1 << 2),
FBTK_MOD_RCTRL = (1 << 3)
} fbtk_modifier_type;
 
typedef int (*fbtk_callback)(fbtk_widget_t *widget, fbtk_callback_info *cbi);
 
/* enter pressed on writable icon */
typedef int (*fbtk_enter_t)(void *pw, char *text);
 
 
/************************ Core ****************************/
 
 
/** Initialise widget toolkit.
*
* Initialises widget toolkit against a framebuffer.
*
* @param fb The underlying framebuffer.
* @return The root widget handle.
*/
fbtk_widget_t *fbtk_init(nsfb_t *fb);
 
/** Retrieve the framebuffer library handle from toolkit widget.
*
* @param widget A fbtk widget.
* @return The underlying framebuffer.
*/
nsfb_t *fbtk_get_nsfb(fbtk_widget_t *widget);
 
/** Perform any pending widget redraws.
*
* @param widget A fbtk widget.
*/
int fbtk_redraw(fbtk_widget_t *widget);
 
/** Determine if there are any redraws pending for a widget.
*
* Mainly used by clients on the root widget to determine if they need
* to call ::fbtk_redraw
*
* @param widget to check.
*/
bool fbtk_get_redraw_pending(fbtk_widget_t *widget);
 
/** clip a bounding box to a widgets area.
*/
bool fbtk_clip_to_widget(fbtk_widget_t *widget, bbox_t * box);
 
/** clip one bounding box to another.
*/
bool fbtk_clip_rect(const bbox_t * clip, bbox_t * box);
 
/***************** Callback processing ********************/
 
/** Helper function to allow simple calling of callbacks with parameters.
*
* @param widget The fbtk widget to post the callback to.
* @param cbt The type of callback to post
* @param ... Parameters appropriate for the callback type.
*/
int fbtk_post_callback(fbtk_widget_t *widget, fbtk_callback_type cbt, ...);
 
/** Set a callback handler.
*
* Set a callback handler and the pointer to pass for a widget.
*
* @param widget The widget to set the handler for.
* @param cbt The type of callback to set.
* @param cb The callback.
* @param pw The private pointer to pass when calling teh callback.
* @return The previous callback handler for the type or NULL.
*/
fbtk_callback fbtk_set_handler(fbtk_widget_t *widget, fbtk_callback_type cbt, fbtk_callback cb, void *pw);
 
/** Get a callback handler.
*/
fbtk_callback fbtk_get_handler(fbtk_widget_t *widget, fbtk_callback_type cbt);
 
 
/******************* Event processing **********************/
 
/** Retrive events from the framebuffer input.
*
* Obtain events from the framebuffer input system with a
* timeout. Some events may be used by the toolkit instead of being
* returned to the caller.
*
* @param root An fbtk widget.
* @param event an event structure to update.
* @param timeout The number of miliseconds to wait for an event. 0
* means do not wait and -1 means wait foreevr.
* @return wether \a event has been updated.
*/
bool fbtk_event(fbtk_widget_t *root, nsfb_event_t *event, int timeout);
 
/** Insert mouse button press into toolkit.
*/
void fbtk_click(fbtk_widget_t *widget, nsfb_event_t *event);
 
/** Insert input into toolkit.
*/
void fbtk_input(fbtk_widget_t *widget, nsfb_event_t *event);
 
/** Move pointer.
*
* Move the pointer cursor to a given location.
*
* @param widget any tookit widget.
* @parm x movement in horizontal plane.
* @parm y movement in vertical plane.
* @parm relative Wheter the /a x and /a y should be considered relative to
* current pointer position.
*/
void fbtk_warp_pointer(fbtk_widget_t *widget, int x, int y, bool relative);
 
/** Toggle pointer grab.
*
* Toggles the movement grab for a widget.
*
* @param widget The widget trying to grab the movement.
* @return true if the grab was ok, false if the grab failed (already grabbed).
*/
bool fbtk_tgrab_pointer(fbtk_widget_t *widget);
 
/** Convert a framebuffer keycode to ucs4.
*
* Character mapping between keycode with modifier state and ucs-4.
*/
int fbtk_keycode_to_ucs4(int code, fbtk_modifier_type mods);
 
 
/******************* Widget Information **********************/
 
/** Obtain the widget at a point on screen.
*
* @param widget any tookit widget.
* @parm x location in horizontal plane.
* @parm y location in vertical plane.
* @return widget or NULL.
*/
fbtk_widget_t *fbtk_get_widget_at(fbtk_widget_t *widget, int x, int y);
 
/** Get a widget's absolute horizontal screen co-ordinate.
*
* @param widget The widget to inspect.
* @return The absolute screen co-ordinate.
*/
int fbtk_get_absx(fbtk_widget_t *widget);
 
/** Get a widget's absolute vertical screen co-ordinate.
*
* @param widget The widget to inspect.
* @return The absolute screen co-ordinate.
*/
int fbtk_get_absy(fbtk_widget_t *widget);
 
/** Get a widget's width.
*
* @param widget The widget to inspect.
* @return The widget width.
*/
int fbtk_get_width(fbtk_widget_t *widget);
 
/** Get a widget's height.
*
* @param widget The widget to inspect.
* @return The widget height.
*/
int fbtk_get_height(fbtk_widget_t *widget);
 
/** Get a widget's bounding box in absolute screen co-ordinates.
*
* @param widget The widget to inspect.
* @param bbox The bounding box structure to update.
* @return If the \a bbox parameter has been updated.
*/
bool fbtk_get_bbox(fbtk_widget_t *widget, struct nsfb_bbox_s *bbox);
 
/** Get a widget caret pos, if it owns caret.
*
* @param widget The widget to inspect.
* @param x If widget has caret, returns x-coord of caret within widget
* @param y If widget has caret, returns y-coord of caret within widget
* @param height If widget has caret, returns caret height
* @return true iff widget has caret
*/
bool fbtk_get_caret(fbtk_widget_t *widget, int *x, int *y, int *height);
 
 
/******************* Widget Manipulation **********************/
 
/** Change the widget's position and size.
*
*/
bool fbtk_set_pos_and_size(fbtk_widget_t *widget, int x, int y, int width, int height);
 
/** Set caret owner and position
*
* @param widget widget to give caret to, or ensure caret is released from
* @param set true: caret to be set for widget, false: caret to be released
* @param x x-coordinate of caret top
* @param y y-coordinate of caret top
* @param height height of caret
*/
void fbtk_set_caret(fbtk_widget_t *widget, bool set, int x, int y, int height,
void (*remove_caret)(fbtk_widget_t *widget));
 
/** Map a widget and request it is redrawn.
*/
int fbtk_set_mapping(fbtk_widget_t *widget, bool mapped);
 
/** Set the z order of a widget.
*/
int fbtk_set_zorder(fbtk_widget_t *widget, int z);
 
/** Indicate a widget should be redrawn.
*/
void fbtk_request_redraw(fbtk_widget_t *widget);
 
/** Destroy a widget and all its descendants.
*
* Removes a widget from the hierachy and frees it and all its children.
*
* @param widget The widget to destroy.
* @return 0 on success or -1 on error.
*/
int fbtk_destroy_widget(fbtk_widget_t *widget);
 
 
 
/********************************* Widgets *********************************/
 
 
/** Create a window widget.
*
* @param parent The parent window or the root widget for a top level window.
* @param x The x location relative to the parent window.
* @param y the y location relative to the parent window.
* @param width The width of the window. 0 indicates parents width should be
* used. Negative value indicates parents width less the value
* should be used. The width is limited to lie within the parent
* window.
* @param height The height of the window limited in a similar way to the
* /a width.
* @param c The background colour.
* @return new window widget handle or NULL on error.
*/
fbtk_widget_t *fbtk_create_window(fbtk_widget_t *parent, int x, int y, int width, int height, colour bg);
 
 
 
/** Create a filled rectangle
*
* Create a widget which is a filled rectangle, usually used for backgrounds.
*
* @param window The window to add the filled area widget to.
* @return new widget handle or NULL on error.
*/
fbtk_widget_t *
fbtk_create_fill(fbtk_widget_t *window, int x, int y, int width, int height, colour c);
 
 
 
 
/** Create a horizontal scroll widget
*
* Create a horizontal scroll widget.
*
* @param window The window to add the filled area widget to.
* @return new widget handle or NULL on error.
*/
fbtk_widget_t *
fbtk_create_hscroll(fbtk_widget_t *window, int x, int y, int width, int height, colour fg, colour bg, fbtk_callback callback, void *context);
 
/** Create a vertical scroll widget
*
* Create a vertical scroll widget.
*
* @param window The window to add the filled area widget to.
* @return new widget handle or NULL on error.
*/
fbtk_widget_t *
fbtk_create_vscroll(fbtk_widget_t *window, int x, int y, int width, int height, colour fg, colour bg, fbtk_callback callback, void *context);
 
bool fbtk_set_scroll_parameters(fbtk_widget_t *widget, int min, int max, int thumb, int page);
 
bool fbtk_set_scroll_position(fbtk_widget_t *widget, int pos);
 
 
 
 
 
/** Create a user widget.
*
* Create a widget which is to be handled entirely by the calling application.
*
* @param window The window to add the user widget to.
* @param pw The private pointer which can be read using ::fbtk_get_pw
* @return new widget handle or NULL on error.
*/
fbtk_widget_t *fbtk_create_user(fbtk_widget_t *window, int x, int y, int width, int height, void *pw);
 
void *fbtk_get_userpw(fbtk_widget_t *widget);
 
 
 
/** Create a bitmap widget.
*
* Create a widget which shows a bitmap.
*
* @param window The window to add the bitmap widget to.
* @return new widget handle or NULL on error.
*/
fbtk_widget_t *fbtk_create_bitmap(fbtk_widget_t *window, int x, int y, int width, int height, colour c,struct fbtk_bitmap *image);
 
void fbtk_set_bitmap(fbtk_widget_t *widget, struct fbtk_bitmap *image);
 
/** Create a button widget.
*
* Helper function which creates a bitmap widget and associate a handler for
* when it is clicked.
*
* @param window The window to add the button widget to.
* @return new widget handle or NULL on error.
*/
fbtk_widget_t *fbtk_create_button(fbtk_widget_t *window, int x, int y, int width, int height, colour c, struct fbtk_bitmap *image, fbtk_callback click, void *pw);
 
 
 
 
 
/** Create a text widget.
*
* @param window The window to add the text widget to.
* @return new widget handle or NULL on error.
*/
fbtk_widget_t *fbtk_create_text(fbtk_widget_t *window, int x, int y, int width, int height, colour bg, colour fg, bool outline);
 
/** Create a button with text.
*
* @param window The window to add the text widget to.
* @return new widget handle or NULL on error.
*/
fbtk_widget_t *fbtk_create_text_button(fbtk_widget_t *window, int x, int y, int width, int height, colour bg, colour fg, fbtk_callback click, void *pw);
 
/** Create a writable text widget.
*
* Helper function which creates a text widget and configures an input handler
* to create a writable text field. This call is equivalent to calling
* ::fbtk_create_text followed by ::fbtk_writable_text
*
* @param window The window to add the text widget to.
* @return new widget handle or NULL on error.
*/
fbtk_widget_t *fbtk_create_writable_text(fbtk_widget_t *window, int x, int y, int width, int height, colour bg, colour fg, bool outline, fbtk_enter_t enter, void *pw);
 
/** Alter a text widget to be writable.
*
* @param widget Text widget.
* @param enter The routine to call when enter is pressed.
* @param pw The context to pass to teh enter callback routine.
*/
void fbtk_writable_text(fbtk_widget_t *widget, fbtk_enter_t enter, void *pw);
 
/** Change the text of a text widget.
*
* @param widget Text widget.
* @param text The new UTF-8 text to put in the widget.
*/
void fbtk_set_text(fbtk_widget_t *widget, const char *text);
 
 
/** Give widget input focus.
*
* @param widget Widget to be given input focus.
*/
void fbtk_set_focus(fbtk_widget_t *widget);
 
 
 
 
/** enable the on screen keyboard for input */
void fbtk_enable_oskb(fbtk_widget_t *widget);
 
/** show the osk. */
void map_osk(void);
 
#endif
/programs/network/netsurf/netsurf/framebuffer/filetype.c
0,0 → 1,59
/*
* Copyright 2003 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdlib.h>
#include <string.h>
#include "content/fetch.h"
#include "utils/log.h"
#include "utils/utils.h"
 
/**
* filetype -- determine the MIME type of a local file
*/
 
const char *fetch_filetype(const char *unix_path)
{
int l;
LOG(("unix path %s", unix_path));
l = strlen(unix_path);
if (2 < l && strcasecmp(unix_path + l - 3, "css") == 0)
return "text/css";
if (2 < l && strcasecmp(unix_path + l - 3, "f79") == 0)
return "text/css";
if (2 < l && strcasecmp(unix_path + l - 3, "jpg") == 0)
return "image/jpeg";
if (3 < l && strcasecmp(unix_path + l - 4, "jpeg") == 0)
return "image/jpeg";
if (2 < l && strcasecmp(unix_path + l - 3, "gif") == 0)
return "image/gif";
if (2 < l && strcasecmp(unix_path + l - 3, "png") == 0)
return "image/png";
if (2 < l && strcasecmp(unix_path + l - 3, "b60") == 0)
return "image/png";
if (2 < l && strcasecmp(unix_path + l - 3, "jng") == 0)
return "image/jng";
if (2 < l && strcasecmp(unix_path + l - 3, "svg") == 0)
return "image/svg";
return "text/html";
}
 
 
char *fetch_mimetype(const char *ro_path)
{
return strdup("text/plain");
}
/programs/network/netsurf/netsurf/framebuffer/findfile.c
0,0 → 1,130
/*
* Copyright 2008 Daniel Silverstone <dsilvers@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <limits.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include <curl/curl.h>
 
#include "utils/filepath.h"
#include "utils/log.h"
#include "utils/url.h"
#include "desktop/gui.h"
 
#include "framebuffer/findfile.h"
 
char **respaths; /** resource search path vector */
 
/** Create an array of valid paths to search for resources.
*
* The idea is that all the complex path computation to find resources
* is performed here, once, rather than every time a resource is
* searched for.
*/
char **
fb_init_resource(const char *resource_path)
{
char **pathv; /* resource path string vector */
char **respath; /* resource paths vector */
const char *lang = NULL;
LOG(("Findfile: %s", resource_path));
pathv = filepath_path_to_strvec(resource_path);
 
LOG(("Findfile2: %s", pathv));
respath = filepath_generate(pathv, &lang);
 
filepath_free_strvec(pathv);
 
return respath;
}
 
 
char *path_to_url(const char *path)
{
int urllen;
char *url;
 
if (path == NULL)
return NULL;
 
urllen = strlen(path) + FILE_SCHEME_PREFIX_LEN + 1;
url = malloc(urllen);
 
if (*path == '/') {
path++; /* file: paths are already absolute */
}
 
snprintf(url, urllen, "%s%s", FILE_SCHEME_PREFIX, path);
 
LOG(("Findfile path2url: %s", url));
return url;
}
 
 
char *url_to_path(const char *url)
{
char *path;
char *respath;
url_func_result res; /* result from url routines */
 
res = url_path(url, &path);
if (res != URL_FUNC_OK) {
return NULL;
}
 
res = url_unescape(path, &respath);
free(path);
if (res != URL_FUNC_OK) {
return NULL;
}
 
LOG(("Findfile url2path: %s", respath));
return respath;
}
 
nsurl *gui_get_resource_url(const char *path)
{
char buf[PATH_MAX];
char *raw;
nsurl *url = NULL;
 
if (strcmp(path, "favicon.ico") == 0)
path = "favicon.png";
 
raw = path_to_url(filepath_sfind(respaths, buf, path));
LOG(("Findfile gui: %s", raw));
if (raw != NULL) {
nsurl_create(raw, &url);
free(raw);
}
 
return url;
}
 
/*
* Local Variables:
* c-basic-offset: 8
* End:
*/
 
/programs/network/netsurf/netsurf/framebuffer/findfile.h
0,0 → 1,32
/*
* Copyright 2008 Daniel Silverstone <dsilvers@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_FB_FINDFILE_H
#define NETSURF_FB_FINDFILE_H
 
extern char **respaths;
 
/** Create an array of valid paths to search for resources.
*
* The idea is that all the complex path computation to find resources
* is performed here, once, rather than every time a resource is
* searched for.
*/
char **fb_init_resource(const char *resource_path);
 
#endif /* NETSURF_FB_FINDFILE_H */
/programs/network/netsurf/netsurf/framebuffer/font.h
0,0 → 1,34
/*
* Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_FB_FONT_H
#define NETSURF_FB_FONT_H
 
#include "utils/utf8.h"
 
bool fb_font_init(void);
bool fb_font_finalise(void);
 
#ifdef FB_USE_FREETYPE
#include "framebuffer/font_freetype.h"
#else
#include "framebuffer/font_internal.h"
#endif
 
#endif /* NETSURF_FB_FONT_H */
 
/programs/network/netsurf/netsurf/framebuffer/font_freetype.c
0,0 → 1,598
/*
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
* 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <inttypes.h>
#include <assert.h>
 
#include <ft2build.h>
#include FT_CACHE_H
 
#include "css/css.h"
#include "css/utils.h"
#include "render/font.h"
#include "utils/filepath.h"
#include "utils/utf8.h"
#include "utils/log.h"
#include "desktop/options.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/font.h"
#include "framebuffer/findfile.h"
#include "font_freetype.h"
 
/* glyph cache minimum size */
#define CACHE_MIN_SIZE (100 * 1024)
 
#define BOLD_WEIGHT 700
 
static FT_Library library;
static FTC_Manager ft_cmanager;
static FTC_CMapCache ft_cmap_cache ;
static FTC_ImageCache ft_image_cache;
 
int ft_load_type;
 
/* cache manager faceID data to create freetype faceid on demand */
typedef struct fb_faceid_s {
char *fontfile; /* path to font */
int index; /* index of font */
int cidx; /* character map index for unicode */
} fb_faceid_t;
 
 
enum fb_face_e {
FB_FACE_SANS_SERIF = 0,
FB_FACE_SANS_SERIF_BOLD = 1,
FB_FACE_SANS_SERIF_ITALIC = 2,
FB_FACE_SANS_SERIF_ITALIC_BOLD = 3,
FB_FACE_SERIF = 4,
FB_FACE_SERIF_BOLD = 5,
FB_FACE_MONOSPACE = 6,
FB_FACE_MONOSPACE_BOLD = 7,
FB_FACE_CURSIVE = 8,
FB_FACE_FANTASY = 9,
};
 
/* defines for accesing the faces */
#define FB_FACE_DEFAULT 0
#define FB_FACE_COUNT 10
 
static fb_faceid_t *fb_faces[FB_FACE_COUNT];
 
 
utf8_convert_ret utf8_to_local_encoding(const char *string,
size_t len,
char **result)
{
return utf8_to_enc(string, "UTF-8", len, result);
}
 
utf8_convert_ret utf8_from_local_encoding(const char *string,
size_t len,
char **result)
{
*result = malloc(len + 1);
if (*result == NULL) {
return UTF8_CONVERT_NOMEM;
}
 
memcpy(*result, string, len);
 
(*result)[len] = '\0';
 
return UTF8_CONVERT_OK;
}
 
/* map cache manager handle to face id */
static FT_Error ft_face_requester(FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face *face )
{
FT_Error error;
fb_faceid_t *fb_face = (fb_faceid_t *)face_id;
int cidx;
 
error = FT_New_Face(library, fb_face->fontfile, fb_face->index, face);
if (error) {
LOG(("Could not find font (code %d)\n", error));
} else {
 
error = FT_Select_Charmap(*face, FT_ENCODING_UNICODE);
if (error) {
LOG(("Could not select charmap (code %d)\n", error));
} else {
for (cidx = 0; cidx < (*face)->num_charmaps; cidx++) {
if ((*face)->charmap == (*face)->charmaps[cidx]) {
fb_face->cidx = cidx;
break;
}
}
}
}
LOG(("Loaded face from %s\n", fb_face->fontfile));
 
return error;
}
 
/* create new framebuffer face and cause it to be loaded to check its ok */
static fb_faceid_t *
fb_new_face(const char *option, const char *resname, const char *fontname)
{
fb_faceid_t *newf;
FT_Error error;
FT_Face aface;
char buf[PATH_MAX];
 
newf = calloc(1, sizeof(fb_faceid_t));
 
if (option != NULL) {
newf->fontfile = strdup(option);
} else {
filepath_sfind(respaths, buf, fontname);
newf->fontfile = strdup(buf);
}
 
error = FTC_Manager_LookupFace(ft_cmanager, (FTC_FaceID)newf, &aface);
if (error) {
LOG(("Could not find font face %s (code %d)\n", fontname, error));
free(newf);
newf = NULL;
}
 
return newf;
}
 
#include <menuet/os.h>
 
/* initialise font handling */
bool fb_font_init(void)
{
FT_Error error;
FT_ULong max_cache_size;
FT_UInt max_faces = 6;
fb_faceid_t *fb_face;
 
LOG(("Freetype init..."));
 
nsoptions.fb_font_monochrome = false;
nsoptions.fb_font_cachesize = 2048;
nsoptions.fb_face_sans_serif = NULL;
nsoptions.fb_face_sans_serif_bold = NULL;
nsoptions.fb_face_sans_serif_italic = NULL;
nsoptions.fb_face_sans_serif_italic_bold = NULL;
nsoptions.fb_face_serif = NULL;
nsoptions.fb_face_serif_bold = NULL;
nsoptions.fb_face_monospace = NULL;
nsoptions.fb_face_monospace_bold = NULL;
nsoptions.fb_face_cursive = NULL;
nsoptions.fb_face_fantasy = NULL;
 
 
/* freetype library initialise */
error = FT_Init_FreeType( &library );
if (error) {
LOG(("Freetype could not initialised (code %d)\n", error));
return false;
}
 
/* set the Glyph cache size up */
max_cache_size = nsoption_int(fb_font_cachesize) * 1024;
 
if (max_cache_size < CACHE_MIN_SIZE) {
max_cache_size = CACHE_MIN_SIZE;
}
 
LOG(("Freetype cache..."));
__menuet__debug_out("Ft cache\n");
/* cache manager initialise */
error = FTC_Manager_New(library,
max_faces,
0,
max_cache_size,
ft_face_requester,
NULL,
&ft_cmanager);
if (error) {
LOG(("Freetype could not initialise cache manager (code %d)\n", error));
FT_Done_FreeType(library);
return false;
}
 
 
LOG(("Freetype map cache..."));
__menuet__debug_out("Ft map cache\n");
error = FTC_CMapCache_New(ft_cmanager, &ft_cmap_cache);
 
error = FTC_ImageCache_New(ft_cmanager, &ft_image_cache);
 
/* need to obtain the generic font faces */
 
 
LOG(("Freetype load fonts..."));
__menuet__debug_out("Ft load fonts\n");
 
/* Start with the sans serif font */
fb_face = fb_new_face(nsoption_charp(fb_face_sans_serif),
"sans_serif.ttf",
NETSURF_FB_FONT_SANS_SERIF);
if (fb_face == NULL) {
LOG(("Freetype load fonts failed due SANS unavailable :(..."));
__menuet__debug_out("Ft Z:(((\n");
/* The sans serif font is the default and must be found. */
LOG(("Could not find the default font\n"));
FTC_Manager_Done(ft_cmanager);
FT_Done_FreeType(library);
return false;
} else {
fb_faces[FB_FACE_SANS_SERIF] = fb_face;
}
 
LOG(("Freetype loaded sans.."));
__menuet__debug_out("Ft sans loaded:)\n");
 
/* Bold sans serif face */
fb_face = fb_new_face(nsoption_charp(fb_face_sans_serif_bold),
"sans_serif_bold.ttf",
NETSURF_FB_FONT_SANS_SERIF_BOLD);
if (fb_face == NULL) {
/* seperate bold face unavailabe use the normal weight version */
fb_faces[FB_FACE_SANS_SERIF_BOLD] = fb_faces[FB_FACE_SANS_SERIF];
} else {
fb_faces[FB_FACE_SANS_SERIF_BOLD] = fb_face;
}
 
/* Italic sans serif face */
fb_face = fb_new_face(nsoption_charp(fb_face_sans_serif_italic),
"sans_serif_italic.ttf",
NETSURF_FB_FONT_SANS_SERIF_ITALIC);
if (fb_face == NULL) {
/* seperate italic face unavailabe use the normal weight version */
fb_faces[FB_FACE_SANS_SERIF_ITALIC] = fb_faces[FB_FACE_SANS_SERIF];
} else {
fb_faces[FB_FACE_SANS_SERIF_ITALIC] = fb_face;
}
 
/* Bold italic sans serif face */
fb_face = fb_new_face(nsoption_charp(fb_face_sans_serif_italic_bold),
"sans_serif_italic_bold.ttf",
NETSURF_FB_FONT_SANS_SERIF_ITALIC_BOLD);
if (fb_face == NULL) {
/* seperate italic face unavailabe use the normal weight version */
fb_faces[FB_FACE_SANS_SERIF_ITALIC_BOLD] = fb_faces[FB_FACE_SANS_SERIF];
} else {
fb_faces[FB_FACE_SANS_SERIF_ITALIC_BOLD] = fb_face;
}
 
/* serif face */
fb_face = fb_new_face(nsoption_charp(fb_face_serif),
"serif.ttf",
NETSURF_FB_FONT_SERIF);
if (fb_face == NULL) {
/* serif face unavailabe use the default */
fb_faces[FB_FACE_SERIF] = fb_faces[FB_FACE_SANS_SERIF];
} else {
fb_faces[FB_FACE_SERIF] = fb_face;
}
 
/* bold serif face*/
fb_face = fb_new_face(nsoption_charp(fb_face_serif_bold),
"serif_bold.ttf",
NETSURF_FB_FONT_SERIF_BOLD);
if (fb_face == NULL) {
/* bold serif face unavailabe use the normal weight */
fb_faces[FB_FACE_SERIF_BOLD] = fb_faces[FB_FACE_SERIF];
} else {
fb_faces[FB_FACE_SERIF_BOLD] = fb_face;
}
 
 
/* monospace face */
fb_face = fb_new_face(nsoption_charp(fb_face_monospace),
"monospace.ttf",
NETSURF_FB_FONT_MONOSPACE);
if (fb_face == NULL) {
/* serif face unavailabe use the default */
fb_faces[FB_FACE_MONOSPACE] = fb_faces[FB_FACE_SANS_SERIF];
} else {
fb_faces[FB_FACE_MONOSPACE] = fb_face;
}
 
/* bold monospace face*/
fb_face = fb_new_face(nsoption_charp(fb_face_monospace_bold),
"monospace_bold.ttf",
NETSURF_FB_FONT_MONOSPACE_BOLD);
if (fb_face == NULL) {
/* bold serif face unavailabe use the normal weight */
fb_faces[FB_FACE_MONOSPACE_BOLD] = fb_faces[FB_FACE_MONOSPACE];
} else {
fb_faces[FB_FACE_MONOSPACE_BOLD] = fb_face;
}
 
/* cursive face */
fb_face = fb_new_face(nsoption_charp(fb_face_cursive),
"cursive.ttf",
NETSURF_FB_FONT_CURSIVE);
if (fb_face == NULL) {
/* cursive face unavailabe use the default */
fb_faces[FB_FACE_CURSIVE] = fb_faces[FB_FACE_SANS_SERIF];
} else {
fb_faces[FB_FACE_CURSIVE] = fb_face;
}
 
/* fantasy face */
fb_face = fb_new_face(nsoption_charp(fb_face_fantasy),
"fantasy.ttf",
NETSURF_FB_FONT_FANTASY);
if (fb_face == NULL) {
/* fantasy face unavailabe use the default */
fb_faces[FB_FACE_FANTASY] = fb_faces[FB_FACE_SANS_SERIF];
} else {
fb_faces[FB_FACE_FANTASY] = fb_face;
}
 
LOG(("Freetype fonts ready..."));
__menuet__debug_out("Ft ready :)\n");
/* set the default render mode */
if (nsoption_bool(fb_font_monochrome) == true)
ft_load_type = FT_LOAD_MONOCHROME; /* faster but less pretty */
else
ft_load_type = 0;
return true;
}
 
bool fb_font_finalise(void)
{
FTC_Manager_Done(ft_cmanager );
FT_Done_FreeType(library);
return true;
}
 
static void fb_fill_scalar(const plot_font_style_t *fstyle, FTC_Scaler srec)
{
int selected_face = FB_FACE_DEFAULT;
 
switch (fstyle->family) {
case PLOT_FONT_FAMILY_SERIF:
if (fstyle->weight >= BOLD_WEIGHT) {
selected_face = FB_FACE_SERIF_BOLD;
} else {
selected_face = FB_FACE_SERIF;
}
break;
 
case PLOT_FONT_FAMILY_MONOSPACE:
if (fstyle->weight >= BOLD_WEIGHT) {
selected_face = FB_FACE_MONOSPACE_BOLD;
} else {
selected_face = FB_FACE_MONOSPACE;
}
break;
 
case PLOT_FONT_FAMILY_CURSIVE:
selected_face = FB_FACE_CURSIVE;
break;
 
case PLOT_FONT_FAMILY_FANTASY:
selected_face = FB_FACE_FANTASY;
break;
 
case PLOT_FONT_FAMILY_SANS_SERIF:
default:
if ((fstyle->flags & FONTF_ITALIC) ||
(fstyle->flags & FONTF_OBLIQUE)) {
if (fstyle->weight >= BOLD_WEIGHT) {
selected_face = FB_FACE_SANS_SERIF_ITALIC_BOLD;
} else {
selected_face = FB_FACE_SANS_SERIF_ITALIC;
}
} else {
if (fstyle->weight >= BOLD_WEIGHT) {
selected_face = FB_FACE_SANS_SERIF_BOLD;
} else {
selected_face = FB_FACE_SANS_SERIF;
}
}
}
 
srec->face_id = (FTC_FaceID)fb_faces[selected_face];
 
srec->width = srec->height = (fstyle->size * 64) / FONT_SIZE_SCALE;
srec->pixel = 0;
 
srec->x_res = srec->y_res = FIXTOINT(nscss_screen_dpi);
}
 
FT_Glyph fb_getglyph(const plot_font_style_t *fstyle, uint32_t ucs4)
{
FT_UInt glyph_index;
FTC_ScalerRec srec;
FT_Glyph glyph;
FT_Error error;
fb_faceid_t *fb_face;
 
fb_fill_scalar(fstyle, &srec);
 
fb_face = (fb_faceid_t *)srec.face_id;
 
glyph_index = FTC_CMapCache_Lookup(ft_cmap_cache, srec.face_id,
fb_face->cidx, ucs4);
 
error = FTC_ImageCache_LookupScaler(ft_image_cache,
&srec,
FT_LOAD_RENDER |
FT_LOAD_FORCE_AUTOHINT |
ft_load_type,
glyph_index,
&glyph,
NULL);
if (error != 0)
return NULL;
 
return glyph;
}
 
 
/**
* Measure the width of a string.
*
* \param fstyle style for this text
* \param string UTF-8 string to measure
* \param length length of string
* \param width updated to width of string[0..length)
* \return true on success, false on error and error reported
*/
static bool nsfont_width(const plot_font_style_t *fstyle,
const char *string, size_t length,
int *width)
{
uint32_t ucs4;
size_t nxtchr = 0;
FT_Glyph glyph;
 
*width = 0;
while (nxtchr < length) {
ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
nxtchr = utf8_next(string, length, nxtchr);
 
glyph = fb_getglyph(fstyle, ucs4);
if (glyph == NULL)
continue;
 
*width += glyph->advance.x >> 16;
}
 
return true;
}
 
/**
* Find the position in a string where an x coordinate falls.
*
* \param fstyle style for this text
* \param string UTF-8 string to measure
* \param length length of string
* \param x x coordinate to search for
* \param char_offset updated to offset in string of actual_x, [0..length]
* \param actual_x updated to x coordinate of character closest to x
* \return true on success, false on error and error reported
*/
 
static bool nsfont_position_in_string(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
uint32_t ucs4;
size_t nxtchr = 0;
FT_Glyph glyph;
int prev_x = 0;
 
*actual_x = 0;
while (nxtchr < length) {
ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
 
glyph = fb_getglyph(fstyle, ucs4);
if (glyph == NULL)
continue;
 
*actual_x += glyph->advance.x >> 16;
if (*actual_x > x)
break;
 
prev_x = *actual_x;
nxtchr = utf8_next(string, length, nxtchr);
}
 
/* choose nearest of previous and last x */
if (abs(*actual_x - x) > abs(prev_x - x))
*actual_x = prev_x;
 
*char_offset = nxtchr;
return true;
}
 
 
/**
* Find where to split a string to make it fit a width.
*
* \param fstyle style for this text
* \param string UTF-8 string to measure
* \param length length of string
* \param x width available
* \param char_offset updated to offset in string of actual_x, [0..length]
* \param actual_x updated to x coordinate of character closest to x
* \return true on success, false on error and error reported
*
* On exit, [char_offset == 0 ||
* string[char_offset] == ' ' ||
* char_offset == length]
*/
 
static bool nsfont_split(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
uint32_t ucs4;
size_t nxtchr = 0;
int last_space_x = 0;
int last_space_idx = 0;
FT_Glyph glyph;
 
*actual_x = 0;
while (nxtchr < length) {
ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr);
 
glyph = fb_getglyph(fstyle, ucs4);
if (glyph == NULL)
continue;
 
if (ucs4 == 0x20) {
last_space_x = *actual_x;
last_space_idx = nxtchr;
}
 
*actual_x += glyph->advance.x >> 16;
if (*actual_x > x) {
/* string has exceeded available width return previous
* space
*/
*actual_x = last_space_x;
*char_offset = last_space_idx;
return true;
}
 
nxtchr = utf8_next(string, length, nxtchr);
}
 
*char_offset = nxtchr;
 
return true;
}
 
const struct font_functions nsfont = {
nsfont_width,
nsfont_position_in_string,
nsfont_split
};
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/font_freetype.h
0,0 → 1,42
/*
* Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_FB_FONT_FREETYPE_H
#define NETSURF_FB_FONT_FREETYPE_H
 
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
 
extern int ft_load_type;
 
FT_Glyph fb_getglyph(const plot_font_style_t *fstyle, uint32_t ucs4);
 
 
#define NETSURF_FB_FONT_SANS_SERIF "sans.ttf"
#define NETSURF_FB_FONT_SANS_SERIF_BOLD NULL
#define NETSURF_FB_FONT_SANS_SERIF_ITALIC NULL
#define NETSURF_FB_FONT_SANS_SERIF_ITALIC_BOLD NULL
#define NETSURF_FB_FONT_SERIF NULL
#define NETSURF_FB_FONT_SERIF_BOLD NULL
#define NETSURF_FB_FONT_MONOSPACE NULL
#define NETSURF_FB_FONT_MONOSPACE_BOLD NULL
#define NETSURF_FB_FONT_FANTASY NULL
#define NETSURF_FB_FONT_CURSIVE NULL
 
#endif /* NETSURF_FB_FONT_FREETYPE_H */
/programs/network/netsurf/netsurf/framebuffer/font_internal.c
0,0 → 1,170
/*
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
* 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <inttypes.h>
#include <string.h>
 
#include <assert.h>
#include "css/css.h"
#include "render/font.h"
#include "desktop/options.h"
#include "utils/utf8.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/font.h"
 
bool fb_font_init(void)
{
return true;
}
 
const struct fb_font_desc*
fb_get_font(const plot_font_style_t *fstyle)
{
if (fstyle->weight >= 700) {
if ((fstyle->flags & FONTF_ITALIC) ||
(fstyle->flags & FONTF_OBLIQUE)) {
return &font_italic_bold;
} else {
return &font_bold;
}
} else {
if ((fstyle->flags & FONTF_ITALIC) ||
(fstyle->flags & FONTF_OBLIQUE)) {
return &font_italic;
} else {
return &font_regular;
}
}
}
 
utf8_convert_ret utf8_to_font_encoding(const struct fb_font_desc* font,
const char *string,
size_t len,
char **result)
{
return utf8_to_enc(string, font->encoding, len, result);
 
}
 
utf8_convert_ret utf8_to_local_encoding(const char *string,
size_t len,
char **result)
{
return utf8_to_enc(string, "CP1252", len, result);
 
}
 
utf8_convert_ret utf8_from_local_encoding(const char *string,
size_t len,
char **result)
{
*result = malloc(len + 1);
if (*result == NULL) {
return UTF8_CONVERT_NOMEM;
}
 
memcpy(*result, string, len);
 
(*result)[len] = '\0';
 
return UTF8_CONVERT_OK;
}
 
static bool nsfont_width(const plot_font_style_t *fstyle,
const char *string, size_t length,
int *width)
{
const struct fb_font_desc* fb_font = fb_get_font(fstyle);
*width = fb_font->width * utf8_bounded_length(string, length);
return true;
}
 
/**
* Find the position in a string where an x coordinate falls.
*
* \param fstyle style for this text
* \param string UTF-8 string to measure
* \param length length of string
* \param x x coordinate to search for
* \param char_offset updated to offset in string of actual_x, [0..length]
* \param actual_x updated to x coordinate of character closest to x
* \return true on success, false on error and error reported
*/
 
static bool nsfont_position_in_string(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
const struct fb_font_desc* fb_font = fb_get_font(fstyle);
*char_offset = (x + fb_font->width / 2) / fb_font->width;
if (*char_offset > length)
*char_offset = length;
*actual_x = *char_offset * fb_font->width;
return true;
}
 
 
/**
* Find where to split a string to make it fit a width.
*
* \param fstyle style for this text
* \param string UTF-8 string to measure
* \param length length of string
* \param x width available
* \param char_offset updated to offset in string of actual_x, [0..length]
* \param actual_x updated to x coordinate of character closest to x
* \return true on success, false on error and error reported
*
* On exit, [char_offset == 0 ||
* string[char_offset] == ' ' ||
* char_offset == length]
*/
 
static bool nsfont_split(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
 
const struct fb_font_desc* fb_font = fb_get_font(fstyle);
*char_offset = x / fb_font->width;
if (*char_offset > length) {
*char_offset = length;
} else {
while (*char_offset > 0) {
if (string[*char_offset] == ' ')
break;
(*char_offset)--;
}
}
*actual_x = *char_offset * fb_font->width;
return true;
}
 
const struct font_functions nsfont = {
nsfont_width,
nsfont_position_in_string,
nsfont_split
};
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/font_internal.h
0,0 → 1,42
/*
* Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_FB_FONT_INTERNAL_H
#define NETSURF_FB_FONT_INTERNAL_H
 
struct fb_font_desc {
const char *name;
int width, height;
const char *encoding;
const uint32_t *data;
};
 
extern const struct fb_font_desc font_regular;
extern const struct fb_font_desc font_italic;
extern const struct fb_font_desc font_bold;
extern const struct fb_font_desc font_italic_bold;
 
extern const struct fb_font_desc* fb_get_font(const plot_font_style_t *fstyle);
 
extern utf8_convert_ret utf8_to_font_encoding(const struct fb_font_desc* font,
const char *string,
size_t len,
char **result);
 
#endif /* NETSURF_FB_FONT_INTERNAL_H */
 
/programs/network/netsurf/netsurf/framebuffer/framebuffer.c
0,0 → 1,443
/*
* Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
*
* Framebuffer interface
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
 
#include <libnsfb.h>
#include <libnsfb_plot.h>
#include <libnsfb_event.h>
#include <libnsfb_cursor.h>
 
#include "utils/log.h"
#include "desktop/browser.h"
#include "image/bitmap.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
#include "framebuffer/framebuffer.h"
#include "framebuffer/font.h"
 
 
/* netsurf framebuffer library handle */
static nsfb_t *nsfb;
 
 
static bool
framebuffer_plot_disc(int x, int y, int radius, const plot_style_t *style)
{
nsfb_bbox_t ellipse;
ellipse.x0 = x - radius;
ellipse.y0 = y - radius;
ellipse.x1 = x + radius;
ellipse.y1 = y + radius;
 
if (style->fill_type != PLOT_OP_TYPE_NONE) {
nsfb_plot_ellipse_fill(nsfb, &ellipse, style->fill_colour);
}
 
if (style->stroke_type != PLOT_OP_TYPE_NONE) {
nsfb_plot_ellipse(nsfb, &ellipse, style->stroke_colour);
}
return true;
}
 
static bool
framebuffer_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
{
return nsfb_plot_arc(nsfb, x, y, radius, angle1, angle2, style->fill_colour);
}
 
static bool
framebuffer_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
{
return nsfb_plot_polygon(nsfb, p, n, style->fill_colour);
}
 
 
#ifdef FB_USE_FREETYPE
static bool
framebuffer_plot_text(int x, int y, const char *text, size_t length,
const plot_font_style_t *fstyle)
{
uint32_t ucs4;
size_t nxtchr = 0;
FT_Glyph glyph;
FT_BitmapGlyph bglyph;
nsfb_bbox_t loc;
 
while (nxtchr < length) {
ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr);
nxtchr = utf8_next(text, length, nxtchr);
 
glyph = fb_getglyph(fstyle, ucs4);
if (glyph == NULL)
continue;
 
if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
bglyph = (FT_BitmapGlyph)glyph;
 
loc.x0 = x + bglyph->left;
loc.y0 = y - bglyph->top;
loc.x1 = loc.x0 + bglyph->bitmap.width;
loc.y1 = loc.y0 + bglyph->bitmap.rows;
 
/* now, draw to our target surface */
if (bglyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
nsfb_plot_glyph1(nsfb,
&loc,
bglyph->bitmap.buffer,
bglyph->bitmap.pitch,
fstyle->foreground);
} else {
nsfb_plot_glyph8(nsfb,
&loc,
bglyph->bitmap.buffer,
bglyph->bitmap.pitch,
fstyle->foreground);
}
}
x += glyph->advance.x >> 16;
 
}
return true;
 
}
#else
static bool framebuffer_plot_text(int x, int y, const char *text, size_t length,
const plot_font_style_t *fstyle)
{
const struct fb_font_desc* fb_font = fb_get_font(fstyle);
const uint32_t *chrp;
char *buffer = NULL;
int chr;
int blen;
nsfb_bbox_t loc;
 
utf8_to_font_encoding(fb_font, text, length, &buffer);
if (buffer == NULL)
return true;
 
/* y is given as the baseline, at 3/4 from top.
* we need it to the top */
y -= ((fb_font->height * 3) / 4);
 
/* the coord is the bottom-left of the pixels offset by 1 to make
* it work since fb coords are the top-left of pixels
*/
y += 1;
 
blen = strlen(buffer);
 
for (chr = 0; chr < blen; chr++) {
loc.x0 = x;
loc.y0 = y;
loc.x1 = loc.x0 + fb_font->width;
loc.y1 = loc.y0 + fb_font->height;
 
chrp = fb_font->data + ((unsigned char)buffer[chr] * fb_font->height);
nsfb_plot_glyph1(nsfb, &loc, (uint8_t *)chrp, 32, fstyle->foreground);
 
x += fb_font->width;
 
}
 
free(buffer);
return true;
}
#endif
 
 
static bool
framebuffer_plot_bitmap(int x, int y,
int width, int height,
struct bitmap *bitmap, colour bg,
bitmap_flags_t flags)
{
int xf,yf;
nsfb_bbox_t loc;
nsfb_bbox_t clipbox;
bool repeat_x = (flags & BITMAPF_REPEAT_X);
bool repeat_y = (flags & BITMAPF_REPEAT_Y);
int bmwidth;
int bmheight;
unsigned char *bmptr;
nsfb_t *bm = (nsfb_t *)bitmap;
 
/* x and y define coordinate of top left of of the initial explicitly
* placed tile. The width and height are the image scaling and the
* bounding box defines the extent of the repeat (which may go in all
* four directions from the initial tile).
*/
 
if (!(repeat_x || repeat_y)) {
/* Not repeating at all, so just plot it */
loc.x0 = x;
loc.y0 = y;
loc.x1 = loc.x0 + width;
loc.y1 = loc.y0 + height;
 
return nsfb_plot_copy(bm, NULL, nsfb, &loc);
}
 
nsfb_plot_get_clip(nsfb, &clipbox);
nsfb_get_geometry(bm, &bmwidth, &bmheight, NULL);
nsfb_get_buffer(bm, &bmptr, NULL);
 
/* Optimise tiled plots of 1x1 bitmaps by replacing with a flat fill
* of the area. Can only be done when image is fully opaque. */
if ((bmwidth == 1) && (bmheight == 1)) {
if ((*(nsfb_colour_t *)bmptr & 0xff000000) != 0) {
return nsfb_plot_rectangle_fill(nsfb, &clipbox,
*(nsfb_colour_t *)bmptr);
}
}
 
/* Optimise tiled plots of bitmaps scaled to 1x1 by replacing with
* a flat fill of the area. Can only be done when image is fully
* opaque. */
if ((width == 1) && (height == 1)) {
if (bitmap_get_opaque(bm)) {
/** TODO: Currently using top left pixel. Maybe centre
* pixel or average value would be better. */
return nsfb_plot_rectangle_fill(nsfb, &clipbox,
*(nsfb_colour_t *)bmptr);
}
}
 
/* get left most tile position */
if (repeat_x)
for (; x > clipbox.x0; x -= width);
 
/* get top most tile position */
if (repeat_y)
for (; y > clipbox.y0; y -= height);
 
/* tile down and across to extents */
for (xf = x; xf < clipbox.x1; xf += width) {
for (yf = y; yf < clipbox.y1; yf += height) {
 
loc.x0 = xf;
loc.y0 = yf;
loc.x1 = loc.x0 + width;
loc.y1 = loc.y0 + height;
 
nsfb_plot_copy(bm, NULL, nsfb, &loc);
 
if (!repeat_y)
break;
}
if (!repeat_x)
break;
}
return true;
}
 
static bool
framebuffer_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
{
nsfb_bbox_t rect;
bool dotted = false;
bool dashed = false;
 
rect.x0 = x0;
rect.y0 = y0;
rect.x1 = x1;
rect.y1 = y1;
 
if (style->fill_type != PLOT_OP_TYPE_NONE) {
nsfb_plot_rectangle_fill(nsfb, &rect, style->fill_colour);
}
if (style->stroke_type != PLOT_OP_TYPE_NONE) {
if (style->stroke_type == PLOT_OP_TYPE_DOT)
dotted = true;
 
if (style->stroke_type == PLOT_OP_TYPE_DASH)
dashed = true;
 
nsfb_plot_rectangle(nsfb, &rect, style->stroke_width, style->stroke_colour, dotted, dashed);
}
 
return true;
}
 
static bool
framebuffer_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
{
nsfb_bbox_t rect;
nsfb_plot_pen_t pen;
 
rect.x0 = x0;
rect.y0 = y0;
rect.x1 = x1;
rect.y1 = y1;
if (style->stroke_type != PLOT_OP_TYPE_NONE) {
 
if (style->stroke_type == PLOT_OP_TYPE_DOT) {
pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN;
pen.stroke_pattern = 0xAAAAAAAA;
} else if (style->stroke_type == PLOT_OP_TYPE_DASH) {
pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN;
pen.stroke_pattern = 0xF0F0F0F0;
} else {
pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID;
}
 
pen.stroke_colour = style->stroke_colour;
pen.stroke_width = style->stroke_width;
nsfb_plot_line(nsfb, &rect, &pen);
}
 
return true;
}
 
 
static bool
framebuffer_plot_path(const float *p,
unsigned int n,
colour fill,
float width,
colour c,
const float transform[6])
{
LOG(("path unimplemented"));
return true;
}
 
static bool
framebuffer_plot_clip(const struct rect *clip)
{
nsfb_bbox_t nsfb_clip;
nsfb_clip.x0 = clip->x0;
nsfb_clip.y0 = clip->y0;
nsfb_clip.x1 = clip->x1;
nsfb_clip.y1 = clip->y1;
 
return nsfb_plot_set_clip(nsfb, &nsfb_clip);
}
 
const struct plotter_table fb_plotters = {
.clip = framebuffer_plot_clip,
.arc = framebuffer_plot_arc,
.disc = framebuffer_plot_disc,
.line = framebuffer_plot_line,
.rectangle = framebuffer_plot_rectangle,
.polygon = framebuffer_plot_polygon,
.path = framebuffer_plot_path,
.bitmap = framebuffer_plot_bitmap,
.text = framebuffer_plot_text,
.option_knockout = true,
};
 
 
 
nsfb_t *
framebuffer_initialise(const char *fename, int width, int height, int bpp)
{
enum nsfb_type_e fbtype;
enum nsfb_format_e fbfmt;
 
/* bpp is a proxy for the framebuffer format */
switch (bpp) {
case 32:
fbfmt = NSFB_FMT_XRGB8888;
break;
 
case 24:
fbfmt = NSFB_FMT_RGB888;
break;
 
case 16:
fbfmt = NSFB_FMT_RGB565;
break;
 
case 8:
fbfmt = NSFB_FMT_I8;
break;
 
case 4:
fbfmt = NSFB_FMT_I4;
break;
 
case 1:
fbfmt = NSFB_FMT_I1;
break;
 
default:
LOG(("Bad bits per pixel (%d)\n", bpp));
return NULL;
}
 
 
fbtype = nsfb_type_from_name(fename);
if (fbtype == NSFB_SURFACE_NONE) {
LOG(("The %s surface is not available from libnsfb\n", fename));
return NULL;
}
 
nsfb = nsfb_new(fbtype);
if (nsfb == NULL) {
LOG(("Unable to create %s fb surface\n", fename));
return NULL;
}
if (nsfb_set_geometry(nsfb, width, height, fbfmt) == -1) {
LOG(("Unable to set surface geometry\n"));
nsfb_free(nsfb);
return NULL;
}
 
nsfb_cursor_init(nsfb);
if (nsfb_init(nsfb) == -1) {
LOG(("Unable to initialise nsfb surface\n"));
nsfb_free(nsfb);
return NULL;
}
 
return nsfb;
 
}
 
void
framebuffer_finalise(void)
{
nsfb_free(nsfb);
}
 
bool
framebuffer_set_cursor(struct fbtk_bitmap *bm)
{
return nsfb_cursor_set(nsfb, (nsfb_colour_t *)bm->pixdata, bm->width, bm->height, bm->width, bm->hot_x, bm->hot_y);
}
 
nsfb_t *framebuffer_set_surface(nsfb_t *new_nsfb)
{
nsfb_t *old_nsfb;
old_nsfb = nsfb;
nsfb = new_nsfb;
return old_nsfb;
}
/programs/network/netsurf/netsurf/framebuffer/framebuffer.h
0,0 → 1,13
#include "desktop/plotters.h"
 
extern const struct plotter_table fb_plotters;
 
nsfb_t *framebuffer_initialise(const char *fename, int width, int height, int bpp);
void framebuffer_finalise(void);
bool framebuffer_set_cursor(struct fbtk_bitmap *bm);
 
/** Set framebuffer surface to render into
*
* @return return old surface
*/
nsfb_t *framebuffer_set_surface(nsfb_t *new_nsfb);
/programs/network/netsurf/netsurf/framebuffer/gui.c
0,0 → 1,1898
/*
* Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <limits.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
 
#include <libnsfb.h>
#include <libnsfb_plot.h>
#include <libnsfb_event.h>
 
#include "desktop/browser_private.h"
#include "desktop/gui.h"
#include "desktop/mouse.h"
#include "desktop/plotters.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
#include "utils/filepath.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/schedule.h"
#include "utils/types.h"
#include "utils/url.h"
#include "utils/utils.h"
#include "desktop/textinput.h"
#include "render/form.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
#include "framebuffer/framebuffer.h"
#include "framebuffer/schedule.h"
#include "framebuffer/findfile.h"
#include "framebuffer/image_data.h"
#include "framebuffer/font.h"
 
 
 
 
#include "content/urldb.h"
#include "desktop/history_core.h"
#include "content/fetch.h"
 
#define NSFB_TOOLBAR_DEFAULT_LAYOUT "blfsrut"
 
fbtk_widget_t *fbtk;
 
struct gui_window *input_window = NULL;
struct gui_window *search_current_window;
struct gui_window *window_list = NULL;
 
/* private data for browser user widget */
struct browser_widget_s {
struct browser_window *bw; /**< The browser window connected to this gui window */
int scrollx, scrolly; /**< scroll offsets. */
 
/* Pending window redraw state. */
bool redraw_required; /**< flag indicating the foreground loop
* needs to redraw the browser widget.
*/
bbox_t redraw_box; /**< Area requiring redraw. */
bool pan_required; /**< flag indicating the foreground loop
* needs to pan the window.
*/
int panx, pany; /**< Panning required. */
};
 
static struct gui_drag {
enum state {
GUI_DRAG_NONE,
GUI_DRAG_PRESSED,
GUI_DRAG_DRAG
} state;
int button;
int x;
int y;
bool grabbed_pointer;
} gui_drag;
 
 
/* queue a redraw operation, co-ordinates are relative to the window */
static void
fb_queue_redraw(struct fbtk_widget_s *widget, int x0, int y0, int x1, int y1)
{
struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
 
bwidget->redraw_box.x0 = min(bwidget->redraw_box.x0, x0);
bwidget->redraw_box.y0 = min(bwidget->redraw_box.y0, y0);
bwidget->redraw_box.x1 = max(bwidget->redraw_box.x1, x1);
bwidget->redraw_box.y1 = max(bwidget->redraw_box.y1, y1);
 
if (fbtk_clip_to_widget(widget, &bwidget->redraw_box)) {
bwidget->redraw_required = true;
fbtk_request_redraw(widget);
} else {
bwidget->redraw_box.y0 = bwidget->redraw_box.x0 = INT_MAX;
bwidget->redraw_box.y1 = bwidget->redraw_box.x1 = -(INT_MAX);
bwidget->redraw_required = false;
}
}
 
/* queue a window scroll */
static void
widget_scroll_y(struct gui_window *gw, int y, bool abs)
{
struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser);
int content_height;
int height;
float scale = gw->bw->scale;
 
LOG(("window scroll"));
if (abs) {
bwidget->pany = y - bwidget->scrolly;
} else {
bwidget->pany += y;
}
 
content_height = content_get_height(gw->bw->current_content) * scale;
 
height = fbtk_get_height(gw->browser);
 
/* dont pan off the top */
if ((bwidget->scrolly + bwidget->pany) < 0)
bwidget->pany = -bwidget->scrolly;
 
/* do not pan off the bottom of the content */
if ((bwidget->scrolly + bwidget->pany) > (content_height - height))
bwidget->pany = (content_height - height) - bwidget->scrolly;
 
if (bwidget->pany == 0)
return;
 
bwidget->pan_required = true;
 
fbtk_request_redraw(gw->browser);
 
fbtk_set_scroll_position(gw->vscroll, bwidget->scrolly + bwidget->pany);
}
 
/* queue a window scroll */
static void
widget_scroll_x(struct gui_window *gw, int x, bool abs)
{
struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser);
int content_width;
int width;
float scale = gw->bw->scale;
 
if (abs) {
bwidget->panx = x - bwidget->scrollx;
} else {
bwidget->panx += x;
}
 
content_width = content_get_width(gw->bw->current_content) * scale;
 
width = fbtk_get_width(gw->browser);
 
/* dont pan off the left */
if ((bwidget->scrollx + bwidget->panx) < 0)
bwidget->panx = - bwidget->scrollx;
 
/* do not pan off the right of the content */
if ((bwidget->scrollx + bwidget->panx) > (content_width - width))
bwidget->panx = (content_width - width) - bwidget->scrollx;
 
if (bwidget->panx == 0)
return;
 
bwidget->pan_required = true;
 
fbtk_request_redraw(gw->browser);
 
fbtk_set_scroll_position(gw->hscroll, bwidget->scrollx + bwidget->panx);
}
 
static void
fb_pan(fbtk_widget_t *widget,
struct browser_widget_s *bwidget,
struct browser_window *bw)
{
int x;
int y;
int width;
int height;
nsfb_bbox_t srcbox;
nsfb_bbox_t dstbox;
 
nsfb_t *nsfb = fbtk_get_nsfb(widget);
 
height = fbtk_get_height(widget);
width = fbtk_get_width(widget);
 
LOG(("panning %d, %d", bwidget->panx, bwidget->pany));
 
x = fbtk_get_absx(widget);
y = fbtk_get_absy(widget);
 
/* if the pan exceeds the viewport size just redraw the whole area */
if (bwidget->pany >= height || bwidget->pany <= -height ||
bwidget->panx >= width || bwidget->panx <= -width) {
 
bwidget->scrolly += bwidget->pany;
bwidget->scrollx += bwidget->panx;
fb_queue_redraw(widget, 0, 0, width, height);
 
/* ensure we don't try to scroll again */
bwidget->panx = 0;
bwidget->pany = 0;
bwidget->pan_required = false;
return;
}
 
if (bwidget->pany < 0) {
/* pan up by less then viewport height */
srcbox.x0 = x;
srcbox.y0 = y;
srcbox.x1 = srcbox.x0 + width;
srcbox.y1 = srcbox.y0 + height + bwidget->pany;
 
dstbox.x0 = x;
dstbox.y0 = y - bwidget->pany;
dstbox.x1 = dstbox.x0 + width;
dstbox.y1 = dstbox.y0 + height + bwidget->pany;
 
/* move part that remains visible up */
nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox);
 
/* redraw newly exposed area */
bwidget->scrolly += bwidget->pany;
fb_queue_redraw(widget, 0, 0, width, - bwidget->pany);
 
} else if (bwidget->pany > 0) {
/* pan down by less then viewport height */
srcbox.x0 = x;
srcbox.y0 = y + bwidget->pany;
srcbox.x1 = srcbox.x0 + width;
srcbox.y1 = srcbox.y0 + height - bwidget->pany;
 
dstbox.x0 = x;
dstbox.y0 = y;
dstbox.x1 = dstbox.x0 + width;
dstbox.y1 = dstbox.y0 + height - bwidget->pany;
 
/* move part that remains visible down */
nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox);
 
/* redraw newly exposed area */
bwidget->scrolly += bwidget->pany;
fb_queue_redraw(widget, 0, height - bwidget->pany,
width, height);
}
 
if (bwidget->panx < 0) {
/* pan left by less then viewport width */
srcbox.x0 = x;
srcbox.y0 = y;
srcbox.x1 = srcbox.x0 + width + bwidget->panx;
srcbox.y1 = srcbox.y0 + height;
 
dstbox.x0 = x - bwidget->panx;
dstbox.y0 = y;
dstbox.x1 = dstbox.x0 + width + bwidget->panx;
dstbox.y1 = dstbox.y0 + height;
 
/* move part that remains visible left */
nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox);
 
/* redraw newly exposed area */
bwidget->scrollx += bwidget->panx;
fb_queue_redraw(widget, 0, 0, -bwidget->panx, height);
 
} else if (bwidget->panx > 0) {
/* pan right by less then viewport width */
srcbox.x0 = x + bwidget->panx;
srcbox.y0 = y;
srcbox.x1 = srcbox.x0 + width - bwidget->panx;
srcbox.y1 = srcbox.y0 + height;
 
dstbox.x0 = x;
dstbox.y0 = y;
dstbox.x1 = dstbox.x0 + width - bwidget->panx;
dstbox.y1 = dstbox.y0 + height;
 
/* move part that remains visible right */
nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox);
 
/* redraw newly exposed area */
bwidget->scrollx += bwidget->panx;
fb_queue_redraw(widget, width - bwidget->panx, 0,
width, height);
}
 
bwidget->pan_required = false;
bwidget->panx = 0;
bwidget->pany = 0;
}
 
static void
fb_redraw(fbtk_widget_t *widget,
struct browser_widget_s *bwidget,
struct browser_window *bw)
{
int x;
int y;
int caret_x, caret_y, caret_h;
struct rect clip;
struct redraw_context ctx = {
.interactive = true,
.background_images = true,
.plot = &fb_plotters
};
nsfb_t *nsfb = fbtk_get_nsfb(widget);
 
LOG(("%d,%d to %d,%d",
bwidget->redraw_box.x0,
bwidget->redraw_box.y0,
bwidget->redraw_box.x1,
bwidget->redraw_box.y1));
 
x = fbtk_get_absx(widget);
y = fbtk_get_absy(widget);
 
/* adjust clipping co-ordinates according to window location */
bwidget->redraw_box.y0 += y;
bwidget->redraw_box.y1 += y;
bwidget->redraw_box.x0 += x;
bwidget->redraw_box.x1 += x;
 
nsfb_claim(nsfb, &bwidget->redraw_box);
 
/* redraw bounding box is relative to window */
clip.x0 = bwidget->redraw_box.x0;
clip.y0 = bwidget->redraw_box.y0;
clip.x1 = bwidget->redraw_box.x1;
clip.y1 = bwidget->redraw_box.y1;
 
browser_window_redraw(bw,
(x - bwidget->scrollx) / bw->scale,
(y - bwidget->scrolly) / bw->scale,
&clip, &ctx);
 
if (fbtk_get_caret(widget, &caret_x, &caret_y, &caret_h)) {
/* This widget has caret, so render it */
nsfb_bbox_t line;
nsfb_plot_pen_t pen;
 
line.x0 = x - bwidget->scrollx + caret_x;
line.y0 = y - bwidget->scrolly + caret_y;
line.x1 = x - bwidget->scrollx + caret_x;
line.y1 = y - bwidget->scrolly + caret_y + caret_h;
 
pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID;
pen.stroke_width = 1;
pen.stroke_colour = 0xFF0000FF;
 
nsfb_plot_line(nsfb, &line, &pen);
}
///STUB???
nsfb_update(fbtk_get_nsfb(widget), &bwidget->redraw_box);
 
bwidget->redraw_box.y0 = bwidget->redraw_box.x0 = INT_MAX;
bwidget->redraw_box.y1 = bwidget->redraw_box.x1 = INT_MIN;
bwidget->redraw_required = false;
}
 
static int
fb_browser_window_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
struct gui_window *gw = cbi->context;
struct browser_widget_s *bwidget;
 
bwidget = fbtk_get_userpw(widget);
if (bwidget == NULL) {
LOG(("browser widget from widget %p was null", widget));
return -1;
}
 
if (bwidget->pan_required) {
fb_pan(widget, bwidget, gw->bw);
}
 
if (bwidget->redraw_required) {
fb_redraw(widget, bwidget, gw->bw);
} else {
bwidget->redraw_box.x0 = 0;
bwidget->redraw_box.y0 = 0;
bwidget->redraw_box.x1 = fbtk_get_width(widget);
bwidget->redraw_box.y1 = fbtk_get_height(widget);
fb_redraw(widget, bwidget, gw->bw);
}
return 0;
}
 
 
static const char *fename;
static int febpp;
static int fewidth;
static int feheight;
static const char *feurl;
 
static bool
process_cmdline(int argc, char** argv)
{
int opt;
 
LOG(("argc %d, argv %p", argc, argv));
 
fename = "sdl";
febpp = 16;
 
if ((nsoption_int(window_width) != 0) &&
(nsoption_int(window_height) != 0)) {
fewidth = nsoption_int(window_width);
feheight = nsoption_int(window_height);
} else {
fewidth = 800; //640;
feheight = 560; //400;
}
 
if ((nsoption_charp(homepage_url) != NULL) &&
(nsoption_charp(homepage_url)[0] != '\0')) {
feurl = nsoption_charp(homepage_url);
} else {
feurl = "about:about";
}
 
while((opt = getopt(argc, argv, "f:b:w:h:")) != -1) {
switch (opt) {
case 'f':
fename = optarg;
break;
 
case 'b':
febpp = atoi(optarg);
break;
 
case 'w':
fewidth = atoi(optarg);
break;
 
case 'h':
feheight = atoi(optarg);
break;
 
default:
fprintf(stderr,
"Usage: %s [-f frontend] [-b bpp] url\n",
argv[0]);
return false;
}
}
 
if (optind < argc) {
feurl = argv[optind];
}
 
return true;
}
 
/* Documented in desktop/options.h */
void gui_options_init_defaults(void)
{
/* Set defaults for absent option strings */
nsoption_setnull_charp(cookie_file, strdup("~/.netsurf/Cookies"));
nsoption_setnull_charp(cookie_jar, strdup("~/.netsurf/Cookies"));
 
if (nsoption_charp(cookie_file) == NULL ||
nsoption_charp(cookie_jar == NULL)) {
die("Failed initialising cookie options");
}
}
 
static void
gui_init(int argc, char** argv)
{
nsfb_t *nsfb;
 
/* Override, since we have no support for non-core SELECT menu */
nsoption_set_bool(core_select_menu, true);
 
if (process_cmdline(argc,argv) != true)
die("unable to process command line.\n");
 
nsfb = framebuffer_initialise(fename, fewidth, feheight, febpp);
if (nsfb == NULL)
die("Unable to initialise framebuffer");
 
framebuffer_set_cursor(&pointer_image);
 
if (fb_font_init() == false)
die("Unable to initialise the font system");
 
fbtk = fbtk_init(nsfb);
 
fbtk_enable_oskb(fbtk);
 
urldb_load_cookies(nsoption_charp(cookie_file));
}
 
/** Entry point from OS.
*
* /param argc The number of arguments in the string vector.
* /param argv The argument string vector.
* /return The return code to the OS
*/
 
#include <surface.h>
 
int
main(int argc, char** argv)
{
struct browser_window *bw;
char *options;
char *messages;
 
setbuf(stderr, NULL);
 
freopen( "stderr.log", "w", stderr );
freopen( "stdout.log", "w", stdout );
LOG(("Registering surfaces for SDL and RAM.."));
extern nsfb_surface_rtns_t sdl_rtns;
extern nsfb_surface_rtns_t ram_rtns;
extern nsfb_surface_rtns_t able_rtns;
_nsfb_register_surface(NSFB_SURFACE_SDL, &sdl_rtns, "sdl");
_nsfb_register_surface(NSFB_SURFACE_RAM, &ram_rtns, "ram");
_nsfb_register_surface(NSFB_SURFACE_RAM, &able_rtns, "able");
 
respaths = fb_init_resource("/tmp9/1/netsurf/res/:res/:fonts/");
 
options = filepath_find(respaths, "Choices");
messages = filepath_find(respaths, "messages");
 
netsurf_init(&argc, &argv, options, "res/messages");
LOG(("NS init okay"));
free(messages);
free(options);
 
LOG(("freed opts and msgs, start gui init"));
 
gui_init(argc, argv);
 
LOG(("calling browser_window_create in MAIN()"));
bw = browser_window_create(feurl, 0, 0, true, false);
 
 
LOG(("NS main loop..."));
netsurf_main_loop();
 
browser_window_destroy(bw);
 
netsurf_exit();
 
return 0;
}
 
 
void
gui_poll(bool active)
{
LOG(("GUI poll in"));
 
nsfb_event_t event;
int timeout; /* timeout in miliseconds */
 
LOG(("schedule run"));
/* run the scheduler and discover how long to wait for the next event */
timeout = schedule_run();
 
/* if active do not wait for event, return immediately */
if (active)
timeout = 0;
 
LOG(("redraw pending"));
/* if redraws are pending do not wait for event, return immediately */
if (fbtk_get_redraw_pending(fbtk))
timeout = 0;
 
LOG(("fbtk event"));
if (fbtk_event(fbtk, &event, timeout)) {
if ((event.type == NSFB_EVENT_CONTROL) &&
(event.value.controlcode == NSFB_CONTROL_QUIT))
netsurf_quit = true;
}
 
LOG(("fbtk redraw"));
fbtk_redraw(fbtk);
 
LOG(("GUI poll out success"));
}
 
void
gui_quit(void)
{
LOG(("gui_quit"));
 
urldb_save_cookies(nsoption_charp(cookie_jar));
 
framebuffer_finalise();
}
 
/* called back when click in browser window */
static int
fb_browser_window_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
struct gui_window *gw = cbi->context;
struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
float scale = gw->bw->scale;
int x = (cbi->x + bwidget->scrollx) / scale;
int y = (cbi->y + bwidget->scrolly) / scale;
 
if (cbi->event->type != NSFB_EVENT_KEY_DOWN &&
cbi->event->type != NSFB_EVENT_KEY_UP)
return 0;
 
LOG(("browser window clicked at %d,%d", cbi->x, cbi->y));
 
switch (cbi->event->type) {
case NSFB_EVENT_KEY_DOWN:
switch (cbi->event->value.keycode) {
case NSFB_KEY_MOUSE_1:
browser_window_mouse_click(gw->bw,
BROWSER_MOUSE_PRESS_1, x, y);
gui_drag.state = GUI_DRAG_PRESSED;
gui_drag.button = 1;
gui_drag.x = x;
gui_drag.y = y;
break;
 
case NSFB_KEY_MOUSE_3:
browser_window_mouse_click(gw->bw,
BROWSER_MOUSE_PRESS_2, x, y);
gui_drag.state = GUI_DRAG_PRESSED;
gui_drag.button = 2;
gui_drag.x = x;
gui_drag.y = y;
break;
 
case NSFB_KEY_MOUSE_4:
/* scroll up */
if (browser_window_scroll_at_point(gw->bw, x, y,
0, -100) == false)
widget_scroll_y(gw, -100, false);
break;
 
case NSFB_KEY_MOUSE_5:
/* scroll down */
if (browser_window_scroll_at_point(gw->bw, x, y,
0, 100) == false)
widget_scroll_y(gw, 100, false);
break;
 
default:
break;
 
}
 
break;
case NSFB_EVENT_KEY_UP:
switch (cbi->event->value.keycode) {
case NSFB_KEY_MOUSE_1:
if (gui_drag.state == GUI_DRAG_DRAG) {
/* End of a drag, rather than click */
 
if (gui_drag.grabbed_pointer) {
/* need to ungrab pointer */
fbtk_tgrab_pointer(widget);
gui_drag.grabbed_pointer = false;
}
 
gui_drag.state = GUI_DRAG_NONE;
 
/* Tell core */
browser_window_mouse_track(gw->bw, 0, x, y);
break;
}
/* This is a click;
* clear PRESSED state and pass to core */
gui_drag.state = GUI_DRAG_NONE;
browser_window_mouse_click(gw->bw,
BROWSER_MOUSE_CLICK_1, x, y);
break;
 
case NSFB_KEY_MOUSE_3:
if (gui_drag.state == GUI_DRAG_DRAG) {
/* End of a drag, rather than click */
gui_drag.state = GUI_DRAG_NONE;
 
if (gui_drag.grabbed_pointer) {
/* need to ungrab pointer */
fbtk_tgrab_pointer(widget);
gui_drag.grabbed_pointer = false;
}
 
/* Tell core */
browser_window_mouse_track(gw->bw, 0, x, y);
break;
}
/* This is a click;
* clear PRESSED state and pass to core */
gui_drag.state = GUI_DRAG_NONE;
browser_window_mouse_click(gw->bw,
BROWSER_MOUSE_CLICK_2, x, y);
break;
 
default:
break;
 
}
 
break;
default:
break;
 
}
return 1;
}
 
/* called back when movement in browser window */
static int
fb_browser_window_move(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
browser_mouse_state mouse = 0;
struct gui_window *gw = cbi->context;
struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
int x = (cbi->x + bwidget->scrollx) / gw->bw->scale;
int y = (cbi->y + bwidget->scrolly) / gw->bw->scale;
 
if (gui_drag.state == GUI_DRAG_PRESSED &&
(abs(x - gui_drag.x) > 5 ||
abs(y - gui_drag.y) > 5)) {
/* Drag started */
if (gui_drag.button == 1) {
browser_window_mouse_click(gw->bw,
BROWSER_MOUSE_DRAG_1,
gui_drag.x, gui_drag.y);
} else {
browser_window_mouse_click(gw->bw,
BROWSER_MOUSE_DRAG_2,
gui_drag.x, gui_drag.y);
}
gui_drag.grabbed_pointer = fbtk_tgrab_pointer(widget);
gui_drag.state = GUI_DRAG_DRAG;
}
 
if (gui_drag.state == GUI_DRAG_DRAG) {
/* set up mouse state */
mouse |= BROWSER_MOUSE_DRAG_ON;
 
if (gui_drag.button == 1)
mouse |= BROWSER_MOUSE_HOLDING_1;
else
mouse |= BROWSER_MOUSE_HOLDING_2;
}
 
browser_window_mouse_track(gw->bw, mouse, x, y);
 
return 0;
}
 
 
static int
fb_browser_window_input(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
struct gui_window *gw = cbi->context;
static fbtk_modifier_type modifier = FBTK_MOD_CLEAR;
int ucs4 = -1;
 
LOG(("got value %d", cbi->event->value.keycode));
 
switch (cbi->event->type) {
case NSFB_EVENT_KEY_DOWN:
switch (cbi->event->value.keycode) {
 
case NSFB_KEY_PAGEUP:
if (browser_window_key_press(gw->bw,
KEY_PAGE_UP) == false)
widget_scroll_y(gw, -fbtk_get_height(
gw->browser), false);
break;
 
case NSFB_KEY_PAGEDOWN:
if (browser_window_key_press(gw->bw,
KEY_PAGE_DOWN) == false)
widget_scroll_y(gw, fbtk_get_height(
gw->browser), false);
break;
 
case NSFB_KEY_RIGHT:
if (modifier & FBTK_MOD_RCTRL ||
modifier & FBTK_MOD_LCTRL) {
/* CTRL held */
if (browser_window_key_press(gw->bw,
KEY_LINE_END) == false)
widget_scroll_x(gw, INT_MAX, true);
 
} else if (modifier & FBTK_MOD_RSHIFT ||
modifier & FBTK_MOD_LSHIFT) {
/* SHIFT held */
if (browser_window_key_press(gw->bw,
KEY_WORD_RIGHT) == false)
widget_scroll_x(gw, fbtk_get_width(
gw->browser), false);
 
} else {
/* no modifier */
if (browser_window_key_press(gw->bw,
KEY_RIGHT) == false)
widget_scroll_x(gw, 100, false);
}
break;
 
case NSFB_KEY_LEFT:
if (modifier & FBTK_MOD_RCTRL ||
modifier & FBTK_MOD_LCTRL) {
/* CTRL held */
if (browser_window_key_press(gw->bw,
KEY_LINE_START) == false)
widget_scroll_x(gw, 0, true);
 
} else if (modifier & FBTK_MOD_RSHIFT ||
modifier & FBTK_MOD_LSHIFT) {
/* SHIFT held */
if (browser_window_key_press(gw->bw,
KEY_WORD_LEFT) == false)
widget_scroll_x(gw, -fbtk_get_width(
gw->browser), false);
 
} else {
/* no modifier */
if (browser_window_key_press(gw->bw,
KEY_LEFT) == false)
widget_scroll_x(gw, -100, false);
}
break;
 
case NSFB_KEY_UP:
if (browser_window_key_press(gw->bw,
KEY_UP) == false)
widget_scroll_y(gw, -100, false);
break;
 
case NSFB_KEY_DOWN:
if (browser_window_key_press(gw->bw,
KEY_DOWN) == false)
widget_scroll_y(gw, 100, false);
break;
 
case NSFB_KEY_RSHIFT:
modifier |= FBTK_MOD_RSHIFT;
break;
 
case NSFB_KEY_LSHIFT:
modifier |= FBTK_MOD_LSHIFT;
break;
 
case NSFB_KEY_RCTRL:
modifier |= FBTK_MOD_RCTRL;
break;
 
case NSFB_KEY_LCTRL:
modifier |= FBTK_MOD_LCTRL;
break;
 
default:
ucs4 = fbtk_keycode_to_ucs4(cbi->event->value.keycode,
modifier);
if (ucs4 != -1)
browser_window_key_press(gw->bw, ucs4);
break;
}
break;
 
case NSFB_EVENT_KEY_UP:
switch (cbi->event->value.keycode) {
case NSFB_KEY_RSHIFT:
modifier &= ~FBTK_MOD_RSHIFT;
break;
 
case NSFB_KEY_LSHIFT:
modifier &= ~FBTK_MOD_LSHIFT;
break;
 
case NSFB_KEY_RCTRL:
modifier &= ~FBTK_MOD_RCTRL;
break;
 
case NSFB_KEY_LCTRL:
modifier &= ~FBTK_MOD_LCTRL;
break;
 
default:
break;
}
break;
 
default:
break;
}
 
return 0;
}
 
static void
fb_update_back_forward(struct gui_window *gw)
{
struct browser_window *bw = gw->bw;
 
fbtk_set_bitmap(gw->back,
(browser_window_back_available(bw)) ?
&left_arrow : &left_arrow_g);
fbtk_set_bitmap(gw->forward,
(browser_window_forward_available(bw)) ?
&right_arrow : &right_arrow_g);
}
 
/* left icon click routine */
static int
fb_leftarrow_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
struct gui_window *gw = cbi->context;
struct browser_window *bw = gw->bw;
 
if (cbi->event->type != NSFB_EVENT_KEY_UP)
return 0;
 
if (history_back_available(bw->history))
history_back(bw, bw->history);
 
fb_update_back_forward(gw);
 
return 1;
}
 
/* right arrow icon click routine */
static int
fb_rightarrow_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
struct gui_window *gw = cbi->context;
struct browser_window *bw = gw->bw;
 
if (cbi->event->type != NSFB_EVENT_KEY_UP)
return 0;
 
if (history_forward_available(bw->history))
history_forward(bw, bw->history);
 
fb_update_back_forward(gw);
return 1;
 
}
 
/* reload icon click routine */
static int
fb_reload_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
struct browser_window *bw = cbi->context;
 
if (cbi->event->type != NSFB_EVENT_KEY_UP)
return 0;
 
browser_window_reload(bw, true);
return 1;
}
 
/* stop icon click routine */
static int
fb_stop_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
struct browser_window *bw = cbi->context;
 
if (cbi->event->type != NSFB_EVENT_KEY_UP)
return 0;
 
browser_window_stop(bw);
return 0;
}
 
static int
fb_osk_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
 
if (cbi->event->type != NSFB_EVENT_KEY_UP)
return 0;
 
map_osk();
 
return 0;
}
 
/* close browser window icon click routine */
static int
fb_close_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
if (cbi->event->type != NSFB_EVENT_KEY_UP)
return 0;
 
netsurf_quit = true;
return 0;
}
 
static int
fb_scroll_callback(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
struct gui_window *gw = cbi->context;
 
switch (cbi->type) {
case FBTK_CBT_SCROLLY:
widget_scroll_y(gw, cbi->y, true);
break;
 
case FBTK_CBT_SCROLLX:
widget_scroll_x(gw, cbi->x, true);
break;
 
default:
break;
}
return 0;
}
 
static int
fb_url_enter(void *pw, char *text)
{
struct browser_window *bw = pw;
browser_window_go(bw, text, 0, true);
return 0;
}
 
static int
fb_url_move(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
framebuffer_set_cursor(&caret_image);
return 0;
}
 
static int
set_ptr_default_move(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
framebuffer_set_cursor(&pointer_image);
return 0;
}
 
static int
fb_localhistory_btn_clik(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
struct gui_window *gw = cbi->context;
 
if (cbi->event->type != NSFB_EVENT_KEY_UP)
return 0;
 
fb_localhistory_map(gw->localhistory);
 
return 0;
}
 
 
/** Create a toolbar window and populate it with buttons.
*
* The toolbar layout uses a character to define buttons type and position:
* b - back
* l - local history
* f - forward
* s - stop
* r - refresh
* u - url bar expands to fit remaining space
* t - throbber/activity indicator
* c - close the current window
*
* The default layout is "blfsrut" there should be no more than a
* single url bar entry or behaviour will be undefined.
*
* @param gw Parent window
* @param toolbar_height The height in pixels of the toolbar
* @param padding The padding in pixels round each element of the toolbar
* @param frame_col Frame colour.
* @param toolbar_layout A string defining which buttons and controls
* should be added to the toolbar. May be empty
* string to disable the bar..
*
*/
static fbtk_widget_t *
create_toolbar(struct gui_window *gw,
int toolbar_height,
int padding,
colour frame_col,
const char *toolbar_layout)
{
fbtk_widget_t *toolbar;
fbtk_widget_t *widget;
 
int xpos; /* The position of the next widget. */
int xlhs = 0; /* extent of the left hand side widgets */
int xdir = 1; /* the direction of movement + or - 1 */
const char *itmtype; /* type of the next item */
 
if (toolbar_layout == NULL) {
toolbar_layout = NSFB_TOOLBAR_DEFAULT_LAYOUT;
}
 
LOG(("Using toolbar layout %s", toolbar_layout));
 
itmtype = toolbar_layout;
 
if (*itmtype == 0) {
return NULL;
}
 
toolbar = fbtk_create_window(gw->window, 0, 0, 0,
toolbar_height,
frame_col);
 
if (toolbar == NULL) {
return NULL;
}
 
fbtk_set_handler(toolbar,
FBTK_CBT_POINTERENTER,
set_ptr_default_move,
NULL);
 
 
xpos = padding;
 
/* loop proceeds creating widget on the left hand side until
* it runs out of layout or encounters a url bar declaration
* wherupon it works backwards from the end of the layout
* untill the space left is for the url bar
*/
while ((itmtype >= toolbar_layout) &&
(*itmtype != 0) &&
(xdir !=0)) {
 
LOG(("toolbar adding %c", *itmtype));
 
 
switch (*itmtype) {
 
case 'b': /* back */
widget = fbtk_create_button(toolbar,
(xdir == 1) ? xpos :
xpos - left_arrow.width,
padding,
left_arrow.width,
-padding,
frame_col,
&left_arrow,
fb_leftarrow_click,
gw);
gw->back = widget; /* keep reference */
break;
 
case 'l': /* local history */
widget = fbtk_create_button(toolbar,
(xdir == 1) ? xpos :
xpos - history_image.width,
padding,
history_image.width,
-padding,
frame_col,
&history_image,
fb_localhistory_btn_clik,
gw);
break;
 
case 'f': /* forward */
widget = fbtk_create_button(toolbar,
(xdir == 1)?xpos :
xpos - right_arrow.width,
padding,
right_arrow.width,
-padding,
frame_col,
&right_arrow,
fb_rightarrow_click,
gw);
gw->forward = widget;
break;
 
case 'c': /* close the current window */
widget = fbtk_create_button(toolbar,
(xdir == 1)?xpos :
xpos - stop_image_g.width,
padding,
stop_image_g.width,
-padding,
frame_col,
&stop_image_g,
fb_close_click,
gw->bw);
break;
 
case 's': /* stop */
widget = fbtk_create_button(toolbar,
(xdir == 1)?xpos :
xpos - stop_image.width,
padding,
stop_image.width,
-padding,
frame_col,
&stop_image,
fb_stop_click,
gw->bw);
break;
 
case 'r': /* reload */
widget = fbtk_create_button(toolbar,
(xdir == 1)?xpos :
xpos - reload.width,
padding,
reload.width,
-padding,
frame_col,
&reload,
fb_reload_click,
gw->bw);
break;
 
case 't': /* throbber/activity indicator */
widget = fbtk_create_bitmap(toolbar,
(xdir == 1)?xpos :
xpos - throbber0.width,
padding,
throbber0.width,
-padding,
frame_col,
&throbber0);
gw->throbber = widget;
break;
 
 
case 'u': /* url bar*/
if (xdir == -1) {
/* met the u going backwards add url
* now we know available extent
*/
 
widget = fbtk_create_writable_text(toolbar,
xlhs,
padding,
xpos - xlhs,
-padding,
FB_COLOUR_WHITE,
FB_COLOUR_BLACK,
true,
fb_url_enter,
gw->bw);
 
fbtk_set_handler(widget,
FBTK_CBT_POINTERENTER,
fb_url_move, gw->bw);
 
gw->url = widget; /* keep reference */
 
/* toolbar is complete */
xdir = 0;
break;
}
/* met url going forwards, note position and
* reverse direction
*/
itmtype = toolbar_layout + strlen(toolbar_layout);
xdir = -1;
xlhs = xpos;
xpos = (2 * fbtk_get_width(toolbar));
widget = toolbar;
break;
 
default:
widget = NULL;
xdir = 0;
LOG(("Unknown element %c in toolbar layout", *itmtype));
break;
 
}
 
if (widget != NULL) {
xpos += (xdir * (fbtk_get_width(widget) + padding));
}
 
LOG(("xpos is %d",xpos));
 
itmtype += xdir;
}
 
fbtk_set_mapping(toolbar, true);
 
return toolbar;
}
 
/** Routine called when "stripped of focus" event occours for browser widget.
*
* @param widget The widget reciving "stripped of focus" event.
* @param cbi The callback parameters.
* @return The callback result.
*/
static int
fb_browser_window_strip_focus(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
fbtk_set_caret(widget, false, 0, 0, 0, NULL);
 
return 0;
}
 
static void
create_browser_widget(struct gui_window *gw, int toolbar_height, int furniture_width)
{
struct browser_widget_s *browser_widget;
browser_widget = calloc(1, sizeof(struct browser_widget_s));
 
gw->browser = fbtk_create_user(gw->window,
0,
toolbar_height,
-furniture_width,
-furniture_width,
browser_widget);
 
fbtk_set_handler(gw->browser, FBTK_CBT_REDRAW, fb_browser_window_redraw, gw);
fbtk_set_handler(gw->browser, FBTK_CBT_INPUT, fb_browser_window_input, gw);
fbtk_set_handler(gw->browser, FBTK_CBT_CLICK, fb_browser_window_click, gw);
fbtk_set_handler(gw->browser, FBTK_CBT_STRIP_FOCUS, fb_browser_window_strip_focus, gw);
fbtk_set_handler(gw->browser, FBTK_CBT_POINTERMOVE, fb_browser_window_move, gw);
}
 
static void
create_normal_browser_window(struct gui_window *gw, int furniture_width)
{
LOG(("enter norm win"));
fbtk_widget_t *widget;
fbtk_widget_t *toolbar;
int statusbar_width = 0;
int toolbar_height = 30; //nsoption_int(fb_toolbar_size);
 
LOG(("Normal window"));
 
gw->window = fbtk_create_window(fbtk, 0, 0, 0, 0, 0);
 
statusbar_width = nsoption_int(toolbar_status_width) *
fbtk_get_width(gw->window) / 10000;
 
LOG(("STUB options"));
 
nsoptions.fb_depth = 16;
nsoptions.fb_refresh = 70;
nsoptions.fb_device = NULL;
nsoptions.fb_input_devpath = NULL;
nsoptions.fb_input_glob = NULL;
nsoptions.fb_furniture_size = 18;
nsoptions.fb_toolbar_size = 30;
nsoptions.fb_toolbar_layout = NULL;
nsoptions.fb_osk = false;
 
 
/* toolbar */
LOG(("toolbar"));
toolbar = create_toolbar(gw,
toolbar_height,
2,
FB_FRAME_COLOUR,
nsoption_charp(fb_toolbar_layout));
 
/* set the actually created toolbar height */
if (toolbar != NULL) {
toolbar_height = fbtk_get_height(toolbar);
} else {
toolbar_height = 0;
}
 
LOG(("statbar"));
/* status bar */
gw->status = fbtk_create_text(gw->window,
0,
fbtk_get_height(gw->window) - furniture_width,
statusbar_width, furniture_width,
FB_FRAME_COLOUR, FB_COLOUR_BLACK,
false);
LOG(("handler"));
fbtk_set_handler(gw->status, FBTK_CBT_POINTERENTER, set_ptr_default_move, NULL);
 
LOG(("status bar %p at %d,%d", gw->status, fbtk_get_absx(gw->status), fbtk_get_absy(gw->status)));
 
/* create horizontal scrollbar */
LOG(("hor sb"));
gw->hscroll = fbtk_create_hscroll(gw->window,
statusbar_width,
fbtk_get_height(gw->window) - furniture_width,
fbtk_get_width(gw->window) - statusbar_width - furniture_width,
furniture_width,
FB_SCROLL_COLOUR,
FB_FRAME_COLOUR,
fb_scroll_callback,
gw);
 
/* fill bottom right area */
LOG(("fill bottom"));
 
if (nsoption_bool(fb_osk) == true) {
widget = fbtk_create_text_button(gw->window,
fbtk_get_width(gw->window) - furniture_width,
fbtk_get_height(gw->window) - furniture_width,
furniture_width,
furniture_width,
FB_FRAME_COLOUR, FB_COLOUR_BLACK,
fb_osk_click,
NULL);
widget = fbtk_create_button(gw->window,
fbtk_get_width(gw->window) - furniture_width,
fbtk_get_height(gw->window) - furniture_width,
furniture_width,
furniture_width,
FB_FRAME_COLOUR,
&osk_image,
fb_osk_click,
NULL);
} else {
widget = fbtk_create_fill(gw->window,
fbtk_get_width(gw->window) - furniture_width,
fbtk_get_height(gw->window) - furniture_width,
furniture_width,
furniture_width,
FB_FRAME_COLOUR);
 
fbtk_set_handler(widget, FBTK_CBT_POINTERENTER, set_ptr_default_move, NULL);
}
 
LOG(("vsb GUI"));
/* create vertical scrollbar */
gw->vscroll = fbtk_create_vscroll(gw->window,
fbtk_get_width(gw->window) - furniture_width,
toolbar_height,
furniture_width,
fbtk_get_height(gw->window) - toolbar_height - furniture_width,
FB_SCROLL_COLOUR,
FB_FRAME_COLOUR,
fb_scroll_callback,
gw);
 
LOG(("BRO widget"));
/* browser widget */
create_browser_widget(gw, toolbar_height, nsoption_int(fb_furniture_size));
 
LOG(("set focus"));
/* Give browser_window's user widget input focus */
fbtk_set_focus(gw->browser);
LOG(("GUI OK"));
}
 
 
struct gui_window *
gui_create_browser_window(struct browser_window *bw,
struct browser_window *clone,
bool new_tab)
{
struct gui_window *gw;
LOG(("GCBW calloc"));
gw = calloc(1, sizeof(struct gui_window));
 
if (gw == NULL)
return NULL;
 
/* seems we need to associate the gui window with the underlying
* browser window
*/
LOG(("GCBW next.."));
gw->bw = bw;
 
LOG(("fb_furn_size is STUB now!..."));
//nsoption_int(fb_furniture_size);
LOG(("GCBW create normal window..."));
create_normal_browser_window(gw, 18); //nsoption_int(fb_furniture_size));
LOG(("GCBW create local history..."));
gw->localhistory = fb_create_localhistory(bw, fbtk, nsoption_int(fb_furniture_size));
 
/* map and request redraw of gui window */
LOG(("GCBW set mapping"));
fbtk_set_mapping(gw->window, true);
LOG(("GCBW OK!"));
 
return gw;
}
 
void
gui_window_destroy(struct gui_window *gw)
{
fbtk_destroy_widget(gw->window);
 
free(gw);
 
 
}
 
void
gui_window_set_title(struct gui_window *g, const char *title)
{
LOG(("%p, %s", g, title));
}
 
void
gui_window_redraw_window(struct gui_window *g)
{
fb_queue_redraw(g->browser, 0, 0, fbtk_get_width(g->browser), fbtk_get_height(g->browser) );
}
 
void
gui_window_update_box(struct gui_window *g, const struct rect *rect)
{
struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser);
fb_queue_redraw(g->browser,
rect->x0 - bwidget->scrollx,
rect->y0 - bwidget->scrolly,
rect->x1 - bwidget->scrollx,
rect->y1 - bwidget->scrolly);
}
 
bool
gui_window_get_scroll(struct gui_window *g, int *sx, int *sy)
{
struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser);
 
*sx = bwidget->scrollx / g->bw->scale;
*sy = bwidget->scrolly / g->bw->scale;
 
return true;
}
 
void
gui_window_set_scroll(struct gui_window *gw, int sx, int sy)
{
struct browser_widget_s *bwidget = fbtk_get_userpw(gw->browser);
 
assert(bwidget);
 
widget_scroll_x(gw, sx * gw->bw->scale, true);
widget_scroll_y(gw, sy * gw->bw->scale, true);
}
 
void
gui_window_scroll_visible(struct gui_window *g, int x0, int y0,
int x1, int y1)
{
LOG(("%s:(%p, %d, %d, %d, %d)", __func__, g, x0, y0, x1, y1));
}
 
void
gui_window_get_dimensions(struct gui_window *g,
int *width,
int *height,
bool scaled)
{
*width = fbtk_get_width(g->browser);
*height = fbtk_get_height(g->browser);
 
if (scaled) {
*width /= g->bw->scale;
*height /= g->bw->scale;
}
}
 
void
gui_window_update_extent(struct gui_window *gw)
{
float scale = gw->bw->scale;
 
fbtk_set_scroll_parameters(gw->hscroll, 0,
content_get_width(gw->bw->current_content) * scale,
fbtk_get_width(gw->browser), 100);
 
fbtk_set_scroll_parameters(gw->vscroll, 0,
content_get_height(gw->bw->current_content) * scale,
fbtk_get_height(gw->browser), 100);
}
 
void
gui_window_set_status(struct gui_window *g, const char *text)
{
fbtk_set_text(g->status, text);
}
 
void
gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape)
{
switch (shape) {
case GUI_POINTER_POINT:
framebuffer_set_cursor(&hand_image);
break;
 
case GUI_POINTER_CARET:
framebuffer_set_cursor(&caret_image);
break;
 
case GUI_POINTER_MENU:
framebuffer_set_cursor(&menu_image);
break;
 
case GUI_POINTER_PROGRESS:
framebuffer_set_cursor(&progress_image);
break;
 
case GUI_POINTER_MOVE:
framebuffer_set_cursor(&move_image);
break;
 
default:
framebuffer_set_cursor(&pointer_image);
break;
}
}
 
void
gui_window_hide_pointer(struct gui_window *g)
{
}
 
void
gui_window_set_url(struct gui_window *g, const char *url)
{
fbtk_set_text(g->url, url);
}
 
static void
throbber_advance(void *pw)
{
struct gui_window *g = pw;
struct fbtk_bitmap *image;
 
switch (g->throbber_index) {
case 0:
image = &throbber1;
g->throbber_index = 1;
break;
 
case 1:
image = &throbber2;
g->throbber_index = 2;
break;
 
case 2:
image = &throbber3;
g->throbber_index = 3;
break;
 
case 3:
image = &throbber4;
g->throbber_index = 4;
break;
 
case 4:
image = &throbber5;
g->throbber_index = 5;
break;
 
case 5:
image = &throbber6;
g->throbber_index = 6;
break;
 
case 6:
image = &throbber7;
g->throbber_index = 7;
break;
 
case 7:
image = &throbber8;
g->throbber_index = 0;
break;
 
default:
return;
}
 
if (g->throbber_index >= 0) {
fbtk_set_bitmap(g->throbber, image);
schedule(10, throbber_advance, g);
}
}
 
void
gui_window_start_throbber(struct gui_window *g)
{
g->throbber_index = 0;
schedule(10, throbber_advance, g);
}
 
void
gui_window_stop_throbber(struct gui_window *gw)
{
gw->throbber_index = -1;
fbtk_set_bitmap(gw->throbber, &throbber0);
 
fb_update_back_forward(gw);
 
}
 
static void
gui_window_remove_caret_cb(fbtk_widget_t *widget)
{
struct browser_widget_s *bwidget = fbtk_get_userpw(widget);
int c_x, c_y, c_h;
 
if (fbtk_get_caret(widget, &c_x, &c_y, &c_h)) {
/* browser window already had caret:
* redraw its area to remove it first */
fb_queue_redraw(widget,
c_x - bwidget->scrollx,
c_y - bwidget->scrolly,
c_x + 1 - bwidget->scrollx,
c_y + c_h - bwidget->scrolly);
}
}
 
void
gui_window_place_caret(struct gui_window *g, int x, int y, int height)
{
struct browser_widget_s *bwidget = fbtk_get_userpw(g->browser);
 
/* set new pos */
fbtk_set_caret(g->browser, true, x, y, height,
gui_window_remove_caret_cb);
 
/* redraw new caret pos */
fb_queue_redraw(g->browser,
x - bwidget->scrollx,
y - bwidget->scrolly,
x + 1 - bwidget->scrollx,
y + height - bwidget->scrolly);
}
 
void
gui_window_remove_caret(struct gui_window *g)
{
int c_x, c_y, c_h;
 
if (fbtk_get_caret(g->browser, &c_x, &c_y, &c_h)) {
/* browser window owns the caret, so can remove it */
fbtk_set_caret(g->browser, false, 0, 0, 0, NULL);
}
}
 
void
gui_window_new_content(struct gui_window *g)
{
}
 
bool
gui_window_scroll_start(struct gui_window *g)
{
return true;
}
 
bool
gui_window_drag_start(struct gui_window *g, gui_drag_type type,
const struct rect *rect)
{
return true;
}
 
void
gui_window_save_link(struct gui_window *g, const char *url, const char *title)
{
}
 
/**
* set favicon
*/
void
gui_window_set_icon(struct gui_window *g, hlcache_handle *icon)
{
}
 
/**
* set gui display of a retrieved favicon representing the search provider
* \param ico may be NULL for local calls; then access current cache from
* search_web_ico()
*/
void
gui_window_set_search_ico(hlcache_handle *ico)
{
}
 
struct gui_download_window *
gui_download_window_create(download_context *ctx, struct gui_window *parent)
{
return NULL;
}
 
nserror
gui_download_window_data(struct gui_download_window *dw,
const char *data,
unsigned int size)
{
return NSERROR_OK;
}
 
void
gui_download_window_error(struct gui_download_window *dw,
const char *error_msg)
{
}
 
void
gui_download_window_done(struct gui_download_window *dw)
{
}
 
void
gui_drag_save_object(gui_save_type type,
hlcache_handle *c,
struct gui_window *w)
{
}
 
void
gui_drag_save_selection(struct selection *s, struct gui_window *g)
{
}
 
void
gui_start_selection(struct gui_window *g)
{
}
 
void
gui_clear_selection(struct gui_window *g)
{
}
 
void
gui_create_form_select_menu(struct browser_window *bw,
struct form_control *control)
{
}
 
void
gui_launch_url(const char *url)
{
}
 
void
gui_cert_verify(nsurl *url,
const struct ssl_cert_info *certs,
unsigned long num,
nserror (*cb)(bool proceed, void *pw),
void *cbpw)
{
cb(false, cbpw);
}
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/gui.h
0,0 → 1,69
/*
* Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_FB_GUI_H
#define NETSURF_FB_GUI_H
 
typedef struct fb_cursor_s fb_cursor_t;
 
/* bounding box */
typedef struct nsfb_bbox_s bbox_t;
 
struct gui_localhistory {
struct browser_window *bw;
 
struct fbtk_widget_s *window;
struct fbtk_widget_s *hscroll;
struct fbtk_widget_s *vscroll;
struct fbtk_widget_s *history;
 
int scrollx, scrolly; /**< scroll offsets. */
};
 
struct gui_window {
struct browser_window *bw;
 
struct fbtk_widget_s *window;
struct fbtk_widget_s *back;
struct fbtk_widget_s *forward;
struct fbtk_widget_s *url;
struct fbtk_widget_s *status;
struct fbtk_widget_s *throbber;
struct fbtk_widget_s *hscroll;
struct fbtk_widget_s *vscroll;
struct fbtk_widget_s *browser;
 
int throbber_index;
 
struct gui_localhistory *localhistory;
};
 
 
extern struct gui_window *window_list;
 
struct gui_localhistory *fb_create_localhistory(struct browser_window *bw, struct fbtk_widget_s *parent, int furniture_width);
void fb_localhistory_map(struct gui_localhistory * glh);
 
 
#endif /* NETSURF_FB_GUI_H */
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/image_data.h
0,0 → 1,60
/*
* Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef FB_IMAGE_DATA
#define FB_IMAGE_DATA
 
#include "framebuffer/fbtk.h"
 
extern struct fbtk_bitmap left_arrow;
extern struct fbtk_bitmap right_arrow;
extern struct fbtk_bitmap reload;
extern struct fbtk_bitmap stop_image;
extern struct fbtk_bitmap history_image;
 
extern struct fbtk_bitmap left_arrow_g;
extern struct fbtk_bitmap right_arrow_g;
extern struct fbtk_bitmap reload_g;
extern struct fbtk_bitmap stop_image_g;
extern struct fbtk_bitmap history_image_g;
 
extern struct fbtk_bitmap scrolll;
extern struct fbtk_bitmap scrollr;
extern struct fbtk_bitmap scrollu;
extern struct fbtk_bitmap scrolld;
 
extern struct fbtk_bitmap osk_image;
 
extern struct fbtk_bitmap pointer_image;
extern struct fbtk_bitmap hand_image;
extern struct fbtk_bitmap caret_image;
extern struct fbtk_bitmap menu_image;
extern struct fbtk_bitmap move_image;
extern struct fbtk_bitmap progress_image;
 
extern struct fbtk_bitmap throbber0;
extern struct fbtk_bitmap throbber1;
extern struct fbtk_bitmap throbber2;
extern struct fbtk_bitmap throbber3;
extern struct fbtk_bitmap throbber4;
extern struct fbtk_bitmap throbber5;
extern struct fbtk_bitmap throbber6;
extern struct fbtk_bitmap throbber7;
extern struct fbtk_bitmap throbber8;
 
#endif /* FB_IMAGE_DATA */
/programs/network/netsurf/netsurf/framebuffer/imgs/caret_image.c
0,0 → 1,47
/* This file is auto-generated from framebuffer/res/pointers/caret.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t caret_image_pixdata[] = {
0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff,
};
 
struct fbtk_bitmap caret_image = {
.width = 7,
.height = 19,
.hot_x = 3,
.hot_y = 8,
.pixdata = caret_image_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/hand_image.c
0,0 → 1,50
/* This file is auto-generated from framebuffer/res/pointers/point.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t hand_image_pixdata[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
 
struct fbtk_bitmap hand_image = {
.width = 16,
.height = 22,
.hot_x = 4,
.hot_y = 0,
.pixdata = hand_image_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/history_image.c
0,0 → 1,54
/* This file is auto-generated from framebuffer/res/icons/history.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t history_image_pixdata[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x24, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x28, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x01, 0x01, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x02, 0x02, 0xf6, 0x00, 0x00, 0x00, 0x14, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x02, 0x02, 0xf9, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 0x01, 0xf9, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xff, 0x43, 0x86, 0x86, 0xff, 0x4d, 0x99, 0x99, 0xff, 0x4d, 0x99, 0x99, 0xff, 0x47, 0x95, 0x95, 0xff, 0x41, 0x90, 0x90, 0xff, 0x2c, 0x69, 0x69, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xff, 0x3e, 0x7c, 0x7c, 0xff, 0x47, 0x95, 0x95, 0xff, 0x41, 0x90, 0x90, 0xff, 0x3b, 0x8c, 0x8c, 0xff, 0x34, 0x87, 0x87, 0xff, 0x25, 0x6a, 0x6a, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xff, 0x59, 0xb3, 0xb3, 0xff, 0x66, 0xcc, 0xcc, 0xff, 0x60, 0xc8, 0xc8, 0xff, 0x58, 0xc1, 0xc1, 0xff, 0x50, 0xbb, 0xbb, 0xff, 0x35, 0x88, 0x88, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0xff, 0x4e, 0xa3, 0xa3, 0xff, 0x58, 0xc1, 0xc1, 0xff, 0x50, 0xbb, 0xbb, 0xff, 0x47, 0xb5, 0xb5, 0xff, 0x3f, 0xaf, 0xaf, 0xff, 0x2d, 0x89, 0x89, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xff, 0x59, 0xb3, 0xb3, 0xff, 0x62, 0xc9, 0xc9, 0xff, 0x5a, 0xc3, 0xc3, 0xff, 0x52, 0xbd, 0xbd, 0xff, 0x49, 0xb7, 0xb7, 0xff, 0x31, 0x85, 0x85, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xff, 0x49, 0x9e, 0x9e, 0xff, 0x52, 0xbd, 0xbd, 0xff, 0x49, 0xb7, 0xb7, 0xff, 0x41, 0xb1, 0xb1, 0xff, 0x39, 0xaa, 0xaa, 0xff, 0x29, 0x87, 0x87, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xff, 0x21, 0x43, 0x43, 0xff, 0x23, 0x4a, 0x4a, 0xff, 0x20, 0x47, 0x47, 0xff, 0x1c, 0x45, 0x45, 0xff, 0x19, 0x43, 0x43, 0xff, 0x11, 0x30, 0x30, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0x9b, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xff, 0x1a, 0x3a, 0x3a, 0xff, 0x1c, 0x45, 0x45, 0xff, 0x19, 0x43, 0x43, 0xff, 0x16, 0x41, 0x41, 0xff, 0x13, 0x3e, 0x3e, 0xff, 0x10, 0x33, 0x33, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x14, 0x02, 0x05, 0x05, 0xcc, 0x02, 0x04, 0x04, 0xe4, 0x01, 0x03, 0x03, 0xe3, 0x01, 0x03, 0x03, 0xe3, 0x01, 0x03, 0x03, 0xe3, 0x01, 0x03, 0x03, 0xe3, 0x01, 0x03, 0x03, 0xe3, 0x02, 0x04, 0x04, 0xbc, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x03, 0x03, 0xc3, 0x01, 0x03, 0x03, 0xe3, 0x01, 0x03, 0x03, 0xe3, 0x01, 0x03, 0x03, 0xe3, 0x01, 0x03, 0x03, 0xe3, 0x01, 0x03, 0x03, 0xe3, 0x01, 0x03, 0x03, 0xe3, 0x02, 0x03, 0x03, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x54, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0x36, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x03, 0x03, 0xf1, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x02, 0x04, 0x04, 0xe5, 0x00, 0x00, 0x00, 0x0e, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x33, 0x02, 0x04, 0x04, 0xec, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x03, 0x03, 0xec, 0x00, 0x00, 0x00, 0x16, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xff, 0x38, 0x70, 0x70, 0xff, 0x40, 0x80, 0x80, 0xff, 0x3b, 0x7c, 0x7c, 0xff, 0x36, 0x78, 0x78, 0xff, 0x31, 0x74, 0x74, 0xff, 0x20, 0x54, 0x54, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0xff, 0x34, 0x68, 0x68, 0xff, 0x3b, 0x7c, 0x7c, 0xff, 0x36, 0x78, 0x78, 0xff, 0x31, 0x74, 0x74, 0xff, 0x2b, 0x71, 0x71, 0xff, 0x1f, 0x58, 0x58, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xff, 0x59, 0xb3, 0xb3, 0xff, 0x60, 0xc8, 0xc8, 0xff, 0x58, 0xc1, 0xc1, 0xff, 0x50, 0xbb, 0xbb, 0xff, 0x47, 0xb5, 0xb5, 0xff, 0x2f, 0x83, 0x83, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x22, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xff, 0x4e, 0xa3, 0xa3, 0xff, 0x58, 0xc1, 0xc1, 0xff, 0x50, 0xbb, 0xbb, 0xff, 0x47, 0xb5, 0xb5, 0xff, 0x3f, 0xaf, 0xaf, 0xff, 0x2d, 0x89, 0x89, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xff, 0x56, 0xb0, 0xb0, 0xff, 0x5a, 0xc3, 0xc3, 0xff, 0x52, 0xbd, 0xbd, 0xff, 0x49, 0xb7, 0xb7, 0xff, 0x41, 0xb1, 0xb1, 0xff, 0x2b, 0x80, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xff, 0x49, 0x9e, 0x9e, 0xff, 0x52, 0xbd, 0xbd, 0xff, 0x49, 0xb7, 0xb7, 0xff, 0x41, 0xb1, 0xb1, 0xff, 0x39, 0xaa, 0xaa, 0xff, 0x29, 0x87, 0x87, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xff, 0x32, 0x6b, 0x6b, 0xff, 0x35, 0x77, 0x77, 0xff, 0x2f, 0x73, 0x73, 0xff, 0x2a, 0x6f, 0x6f, 0xff, 0x25, 0x6c, 0x6c, 0xff, 0x18, 0x4e, 0x4e, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x6e, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xff, 0x2b, 0x60, 0x60, 0xff, 0x2f, 0x73, 0x73, 0xff, 0x2a, 0x6f, 0x6f, 0xff, 0x25, 0x6c, 0x6c, 0xff, 0x20, 0x68, 0x68, 0xff, 0x1a, 0x54, 0x54, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x24, 0x01, 0x02, 0x02, 0xf6, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x03, 0x03, 0xeb, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0x4c, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x02, 0x03, 0x03, 0xf1, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x03, 0x03, 0xf1, 0x00, 0x00, 0x00, 0x1a, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x12, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x19, 0x02, 0x05, 0x05, 0xc4, 0x02, 0x03, 0x03, 0xe3, 0x02, 0x03, 0x03, 0xe3, 0x02, 0x04, 0x04, 0xe4, 0x01, 0x03, 0x03, 0xe3, 0x01, 0x03, 0x03, 0xe3, 0x01, 0x03, 0x03, 0xe3, 0x01, 0x03, 0x03, 0xc3, 0x00, 0x00, 0x00, 0x0e, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x3e, 0x3e, 0xff, 0x23, 0x4a, 0x4a, 0xff, 0x20, 0x48, 0x48, 0xff, 0x1d, 0x46, 0x46, 0xff, 0x1a, 0x44, 0x44, 0xff, 0x13, 0x35, 0x35, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd5, 0x00, 0x00, 0x00, 0xff, 0x4e, 0xa3, 0xa3, 0xff, 0x58, 0xc1, 0xc1, 0xff, 0x50, 0xbb, 0xbb, 0xff, 0x47, 0xb5, 0xb5, 0xff, 0x3f, 0xaf, 0xaf, 0xff, 0x2d, 0x89, 0x89, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xff, 0x49, 0x9e, 0x9e, 0xff, 0x52, 0xbd, 0xbd, 0xff, 0x49, 0xb7, 0xb7, 0xff, 0x41, 0xb1, 0xb1, 0xff, 0x39, 0xaa, 0xaa, 0xff, 0x29, 0x87, 0x87, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xff, 0x3c, 0x87, 0x87, 0xff, 0x42, 0xa1, 0xa1, 0xff, 0x3b, 0x9c, 0x9c, 0xff, 0x34, 0x97, 0x97, 0xff, 0x2d, 0x91, 0x91, 0xff, 0x24, 0x76, 0x76, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0x01, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x22, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x2c, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
};
 
struct fbtk_bitmap history_image = {
.width = 26,
.height = 26,
.hot_x = 0,
.hot_y = 0,
.pixdata = history_image_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/history_image_g.c
0,0 → 1,54
/* This file is auto-generated from framebuffer/res/icons/history_g.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t history_image_g_pixdata[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0d, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x03, 0x03, 0x03, 0x52, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x03, 0x03, 0x03, 0x53, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x0b, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x55, 0x87, 0x87, 0x87, 0x55, 0x99, 0x99, 0x99, 0x55, 0x99, 0x99, 0x99, 0x55, 0x96, 0x96, 0x96, 0x55, 0x93, 0x93, 0x93, 0x55, 0x6c, 0x6c, 0x6c, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x0b, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x55, 0x7b, 0x7b, 0x7b, 0x55, 0x96, 0x96, 0x96, 0x55, 0x93, 0x93, 0x93, 0x55, 0x90, 0x90, 0x90, 0x55, 0x8d, 0x8d, 0x8d, 0x55, 0x6f, 0x6f, 0x6f, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0x8d, 0x8d, 0x8d, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x55, 0xa2, 0xa2, 0xa2, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0x93, 0x93, 0x93, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0x8d, 0x8d, 0x8d, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x55, 0xa2, 0xa2, 0xa2, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x90, 0x90, 0x90, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x55, 0x42, 0x42, 0x42, 0x55, 0x4b, 0x4b, 0x4b, 0x55, 0x48, 0x48, 0x48, 0x55, 0x48, 0x48, 0x48, 0x55, 0x45, 0x45, 0x45, 0x55, 0x33, 0x33, 0x33, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x34, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x55, 0x3c, 0x3c, 0x3c, 0x55, 0x48, 0x48, 0x48, 0x55, 0x45, 0x45, 0x45, 0x55, 0x45, 0x45, 0x45, 0x55, 0x42, 0x42, 0x42, 0x55, 0x36, 0x36, 0x36, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0x03, 0x03, 0x44, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x04, 0x04, 0x04, 0x3e, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x27, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x05, 0x03, 0x03, 0x03, 0x41, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x41, 0x00, 0x00, 0x00, 0x05, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x12, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x03, 0x03, 0x03, 0x50, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x03, 0x03, 0x03, 0x4c, 0x00, 0x00, 0x00, 0x05, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x11, 0x03, 0x03, 0x03, 0x4e, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x03, 0x03, 0x03, 0x4e, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x55, 0x6f, 0x6f, 0x6f, 0x55, 0x81, 0x81, 0x81, 0x55, 0x7e, 0x7e, 0x7e, 0x55, 0x7b, 0x7b, 0x7b, 0x55, 0x78, 0x78, 0x78, 0x55, 0x57, 0x57, 0x57, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x0b, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x55, 0x69, 0x69, 0x69, 0x55, 0x7e, 0x7e, 0x7e, 0x55, 0x7b, 0x7b, 0x7b, 0x55, 0x78, 0x78, 0x78, 0x55, 0x75, 0x75, 0x75, 0x55, 0x5d, 0x5d, 0x5d, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0x8a, 0x8a, 0x8a, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x0b, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x55, 0xa2, 0xa2, 0xa2, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0x93, 0x93, 0x93, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x55, 0xb1, 0xb1, 0xb1, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0x8a, 0x8a, 0x8a, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x55, 0xa2, 0xa2, 0xa2, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x90, 0x90, 0x90, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x55, 0x6c, 0x6c, 0x6c, 0x55, 0x7b, 0x7b, 0x7b, 0x55, 0x78, 0x78, 0x78, 0x55, 0x75, 0x75, 0x75, 0x55, 0x72, 0x72, 0x72, 0x55, 0x54, 0x54, 0x54, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x25, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x55, 0x63, 0x63, 0x63, 0x55, 0x78, 0x78, 0x78, 0x55, 0x75, 0x75, 0x75, 0x55, 0x72, 0x72, 0x72, 0x55, 0x6f, 0x6f, 0x6f, 0x55, 0x5a, 0x5a, 0x5a, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x03, 0x03, 0x52, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x03, 0x03, 0x03, 0x4e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x19, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x09, 0x03, 0x03, 0x03, 0x50, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x03, 0x03, 0x03, 0x50, 0x00, 0x00, 0x00, 0x09, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x05, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x06, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x09, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x08, 0x03, 0x03, 0x03, 0x41, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x4c, 0x03, 0x03, 0x03, 0x41, 0x00, 0x00, 0x00, 0x05, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x55, 0x3f, 0x3f, 0x3f, 0x55, 0x4b, 0x4b, 0x4b, 0x55, 0x4b, 0x4b, 0x4b, 0x55, 0x48, 0x48, 0x48, 0x55, 0x48, 0x48, 0x48, 0x55, 0x39, 0x39, 0x39, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x55, 0xa2, 0xa2, 0xa2, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0x93, 0x93, 0x93, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x55, 0xa2, 0xa2, 0xa2, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x90, 0x90, 0x90, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x55, 0x8a, 0x8a, 0x8a, 0x55, 0xa8, 0xa8, 0xa8, 0x55, 0xa5, 0xa5, 0xa5, 0x55, 0x9f, 0x9f, 0x9f, 0x55, 0x9c, 0x9c, 0x9c, 0x55, 0x7e, 0x7e, 0x7e, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x0b, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
};
 
struct fbtk_bitmap history_image_g = {
.width = 26,
.height = 26,
.hot_x = 0,
.hot_y = 0,
.pixdata = history_image_g_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/left_arrow.c
0,0 → 1,54
/* This file is auto-generated from framebuffer/res/icons/back.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t left_arrow_pixdata[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x03, 0x01, 0xd2, 0x00, 0x00, 0x00, 0xff, 0x01, 0x03, 0x01, 0xf2, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x03, 0x01, 0xf2, 0x05, 0x0b, 0x05, 0xfc, 0x33, 0x6d, 0x33, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xaf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0xff, 0x12, 0x26, 0x12, 0xfc, 0x53, 0xb0, 0x53, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xff, 0x26, 0x51, 0x26, 0xff, 0x60, 0xcb, 0x60, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xff, 0x39, 0x7a, 0x39, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x62, 0xd8, 0x62, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x0c, 0x19, 0x0c, 0xfd, 0x53, 0xb0, 0x53, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x62, 0xd8, 0x62, 0xff, 0x5b, 0xd6, 0x5b, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xff, 0x1a, 0x36, 0x1a, 0xff, 0x60, 0xcb, 0x60, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x61, 0xd8, 0x61, 0xff, 0x5a, 0xd6, 0x5a, 0xff, 0x54, 0xd4, 0x54, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x02, 0x01, 0xe1, 0x00, 0x00, 0x00, 0xff, 0x33, 0x6d, 0x33, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x60, 0xd7, 0x60, 0xff, 0x5a, 0xd6, 0x5a, 0xff, 0x53, 0xd4, 0x53, 0xff, 0x4d, 0xd3, 0x4d, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xff, 0x06, 0x0c, 0x06, 0xfd, 0x4d, 0xa3, 0x4d, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x65, 0xd9, 0x65, 0xff, 0x5f, 0xd7, 0x5f, 0xff, 0x59, 0xd6, 0x59, 0xff, 0x52, 0xd4, 0x52, 0xff, 0x4c, 0xd2, 0x4c, 0xff, 0x46, 0xd1, 0x46, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xff, 0x13, 0x29, 0x13, 0xff, 0x59, 0xbe, 0x59, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x64, 0xd9, 0x64, 0xff, 0x5e, 0xd7, 0x5e, 0xff, 0x58, 0xd5, 0x58, 0xff, 0x51, 0xd4, 0x51, 0xff, 0x4b, 0xd2, 0x4b, 0xff, 0x45, 0xd1, 0x45, 0xff, 0x3e, 0xcf, 0x3e, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x03, 0x01, 0xd2, 0x00, 0x00, 0x00, 0xff, 0x2d, 0x5f, 0x2d, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x64, 0xd8, 0x64, 0xff, 0x5d, 0xd7, 0x5d, 0xff, 0x57, 0xd5, 0x57, 0xff, 0x50, 0xd3, 0x50, 0xff, 0x4a, 0xd2, 0x4a, 0xff, 0x44, 0xd0, 0x44, 0xff, 0x3e, 0xcf, 0x3e, 0xff, 0x37, 0xcd, 0x37, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x03, 0x01, 0xf2, 0x05, 0x0b, 0x05, 0xfc, 0x40, 0x88, 0x40, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x62, 0xd8, 0x62, 0xff, 0x5c, 0xd7, 0x5c, 0xff, 0x56, 0xd5, 0x56, 0xff, 0x50, 0xd3, 0x50, 0xff, 0x49, 0xd2, 0x49, 0xff, 0x43, 0xd0, 0x43, 0xff, 0x3c, 0xce, 0x3c, 0xff, 0x36, 0xcd, 0x36, 0xff, 0x30, 0xcb, 0x30, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x03, 0x01, 0xf2, 0x05, 0x0b, 0x05, 0xfc, 0x40, 0x88, 0x40, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x62, 0xd8, 0x62, 0xff, 0x5b, 0xd6, 0x5b, 0xff, 0x55, 0xd5, 0x55, 0xff, 0x4f, 0xd3, 0x4f, 0xff, 0x48, 0xd1, 0x48, 0xff, 0x42, 0xd0, 0x42, 0xff, 0x3c, 0xce, 0x3c, 0xff, 0x35, 0xcd, 0x35, 0xff, 0x2f, 0xcb, 0x2f, 0xff, 0x28, 0xc9, 0x28, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x03, 0x01, 0xd2, 0x00, 0x00, 0x00, 0xff, 0x2d, 0x5f, 0x2d, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x61, 0xd8, 0x61, 0xff, 0x5a, 0xd6, 0x5a, 0xff, 0x54, 0xd4, 0x54, 0xff, 0x4e, 0xd3, 0x4e, 0xff, 0x47, 0xd1, 0x47, 0xff, 0x41, 0xd0, 0x41, 0xff, 0x3b, 0xce, 0x3b, 0xff, 0x34, 0xcc, 0x34, 0xff, 0x2e, 0xcb, 0x2e, 0xff, 0x28, 0xc9, 0x28, 0xff, 0x21, 0xc7, 0x21, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xff, 0x12, 0x28, 0x12, 0xff, 0x4f, 0xbb, 0x4f, 0xff, 0x53, 0xd4, 0x53, 0xff, 0x4d, 0xd3, 0x4d, 0xff, 0x46, 0xd1, 0x46, 0xff, 0x40, 0xcf, 0x40, 0xff, 0x3a, 0xce, 0x3a, 0xff, 0x34, 0xcc, 0x34, 0xff, 0x2d, 0xcb, 0x2d, 0xff, 0x27, 0xc9, 0x27, 0xff, 0x20, 0xc7, 0x20, 0xff, 0x1a, 0xc6, 0x1a, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xff, 0x05, 0x0c, 0x05, 0xfd, 0x39, 0x9e, 0x39, 0xff, 0x46, 0xd1, 0x46, 0xff, 0x3f, 0xcf, 0x3f, 0xff, 0x39, 0xcd, 0x39, 0xff, 0x32, 0xcc, 0x32, 0xff, 0x2c, 0xca, 0x2c, 0xff, 0x26, 0xc9, 0x26, 0xff, 0x20, 0xc7, 0x20, 0xff, 0x19, 0xc5, 0x19, 0xff, 0x13, 0xc4, 0x13, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x02, 0x01, 0xe1, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x68, 0x1f, 0xff, 0x38, 0xcd, 0x38, 0xff, 0x32, 0xcc, 0x32, 0xff, 0x2b, 0xca, 0x2b, 0xff, 0x25, 0xc8, 0x25, 0xff, 0x1f, 0xc7, 0x1f, 0xff, 0x18, 0xc5, 0x18, 0xff, 0x12, 0xc4, 0x12, 0xff, 0x0c, 0xc2, 0x0c, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xff, 0x0c, 0x33, 0x0c, 0xff, 0x27, 0xbd, 0x27, 0xff, 0x24, 0xc8, 0x24, 0xff, 0x1e, 0xc7, 0x1e, 0xff, 0x17, 0xc5, 0x17, 0xff, 0x11, 0xc3, 0x11, 0xff, 0x0b, 0xc2, 0x0b, 0xff, 0x04, 0xc0, 0x04, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x04, 0x18, 0x04, 0xfd, 0x18, 0xa1, 0x18, 0xff, 0x16, 0xc5, 0x16, 0xff, 0x10, 0xc3, 0x10, 0xff, 0x0a, 0xc1, 0x0a, 0xff, 0x04, 0xc0, 0x04, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x02, 0x00, 0xf1, 0x00, 0x00, 0x00, 0xff, 0x08, 0x6e, 0x08, 0xff, 0x09, 0xc1, 0x09, 0xff, 0x02, 0xc0, 0x02, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xff, 0x01, 0x48, 0x01, 0xff, 0x00, 0xb3, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x22, 0x00, 0xfc, 0x00, 0x9b, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x02, 0x00, 0xf2, 0x00, 0x0a, 0x00, 0xfc, 0x00, 0x60, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xaf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xff, 0x00, 0x02, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
};
 
struct fbtk_bitmap left_arrow = {
.width = 22,
.height = 26,
.hot_x = 0,
.hot_y = 0,
.pixdata = left_arrow_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/left_arrow_g.c
0,0 → 1,54
/* This file is auto-generated from framebuffer/res/icons/back_g.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t left_arrow_g_pixdata[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x0b, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x09, 0x03, 0x03, 0x03, 0x44, 0x00, 0x00, 0x00, 0x55, 0x03, 0x03, 0x03, 0x4e, 0x00, 0x00, 0x00, 0x0d, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x17, 0x03, 0x03, 0x03, 0x50, 0x0c, 0x0c, 0x0c, 0x54, 0x7e, 0x7e, 0x7e, 0x55, 0x0f, 0x0f, 0x0f, 0x55, 0x00, 0x00, 0x00, 0x31, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x54, 0x27, 0x27, 0x27, 0x54, 0xb1, 0xb1, 0xb1, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0x24, 0x24, 0x24, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x55, 0x54, 0x54, 0x54, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0x24, 0x24, 0x24, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x12, 0x03, 0x03, 0x03, 0x4c, 0x06, 0x06, 0x06, 0x54, 0x81, 0x81, 0x81, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0x24, 0x24, 0x24, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x53, 0x1e, 0x1e, 0x1e, 0x54, 0xa8, 0xa8, 0xa8, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0x24, 0x24, 0x24, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x55, 0x45, 0x45, 0x45, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0x24, 0x24, 0x24, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x03, 0x03, 0x03, 0x48, 0x03, 0x03, 0x03, 0x55, 0x72, 0x72, 0x72, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0x24, 0x24, 0x24, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x03, 0x03, 0x03, 0x52, 0x15, 0x15, 0x15, 0x54, 0x9f, 0x9f, 0x9f, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x55, 0x36, 0x36, 0x36, 0x55, 0xba, 0xba, 0xba, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x09, 0x03, 0x03, 0x03, 0x44, 0x00, 0x00, 0x00, 0x54, 0x63, 0x63, 0x63, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x09, 0x03, 0x03, 0x03, 0x50, 0x0c, 0x0c, 0x0c, 0x54, 0x90, 0x90, 0x90, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x03, 0x03, 0x50, 0x0c, 0x0c, 0x0c, 0x54, 0x90, 0x90, 0x90, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x09, 0x03, 0x03, 0x03, 0x44, 0x00, 0x00, 0x00, 0x54, 0x60, 0x60, 0x60, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x55, 0x33, 0x33, 0x33, 0x54, 0xb4, 0xb4, 0xb4, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x03, 0x03, 0x03, 0x52, 0x12, 0x12, 0x12, 0x54, 0x99, 0x99, 0x99, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x03, 0x03, 0x03, 0x48, 0x03, 0x03, 0x03, 0x55, 0x6f, 0x6f, 0x6f, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x55, 0x3f, 0x3f, 0x3f, 0x54, 0xb7, 0xb7, 0xb7, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x53, 0x1b, 0x1b, 0x1b, 0x54, 0x9f, 0x9f, 0x9f, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x12, 0x03, 0x03, 0x03, 0x4c, 0x06, 0x06, 0x06, 0x54, 0x7b, 0x7b, 0x7b, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x55, 0x4e, 0x4e, 0x4e, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x54, 0x24, 0x24, 0x24, 0x54, 0xa2, 0xa2, 0xa2, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x17, 0x03, 0x03, 0x03, 0x50, 0x0c, 0x0c, 0x0c, 0x54, 0x6f, 0x6f, 0x6f, 0x55, 0x0c, 0x0c, 0x0c, 0x54, 0x00, 0x00, 0x00, 0x31, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x09, 0x03, 0x03, 0x03, 0x44, 0x00, 0x00, 0x00, 0x55, 0x03, 0x03, 0x03, 0x4e, 0x00, 0x00, 0x00, 0x0d, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
};
 
struct fbtk_bitmap left_arrow_g = {
.width = 22,
.height = 26,
.hot_x = 0,
.hot_y = 0,
.pixdata = left_arrow_g_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/make.res
0,0 → 1,10
OBJS = caret_image.o history_image_g.o menu_image.o pointer_image.o reload_g.o scrolld.o scrollu.o throbber0.o throbber3.o throbber6.o \
hand_image.o left_arrow.o move_image.o progress_image.o right_arrow.o scrolll.o stop_image.o throbber1.o throbber4.o throbber7.o \
history_image.o left_arrow_g.o osk_image.o reload.o right_arrow_g.o scrollr.o stop_image_g.o throbber2.o throbber5.o throbber8.o
 
 
OUTFILE = TEST.o
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include
include $(MENUETDEV)/makefiles/Makefile_for_o_lib
 
/programs/network/netsurf/netsurf/framebuffer/imgs/menu_image.c
0,0 → 1,53
/* This file is auto-generated from framebuffer/res/pointers/menu.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t menu_image_pixdata[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x00, 0x00, 0x19, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x00, 0x00, 0x19, 0xff, 0x00, 0x00, 0x19, 0xff, 0x00, 0x00, 0x19, 0xff, 0x00, 0x00, 0x19, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x00, 0x00, 0x19, 0xff, 0x00, 0x00, 0x19, 0xff, 0x00, 0x00, 0x19, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x00, 0x00, 0x19, 0xff, 0x00, 0x00, 0x19, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x00, 0x00, 0x19, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x00, 0x00, 0x19, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x00, 0x00, 0x19, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x00, 0x00, 0x19, 0xff, 0x00, 0x00, 0x19, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x00, 0x00, 0x19, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff,
};
 
struct fbtk_bitmap menu_image = {
.width = 26,
.height = 25,
.hot_x = 8,
.hot_y = 3,
.pixdata = menu_image_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/move_image.c
0,0 → 1,50
/* This file is auto-generated from framebuffer/res/pointers/move.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t move_image_pixdata[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
 
struct fbtk_bitmap move_image = {
.width = 16,
.height = 22,
.hot_x = 6,
.hot_y = 0,
.pixdata = move_image_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/osk_image.c
0,0 → 1,46
/* This file is auto-generated from framebuffer/res/icons/osk.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t osk_image_pixdata[] = {
0xea, 0xea, 0xea, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xd9, 0xd9, 0xd9, 0xff,
0xee, 0xee, 0xee, 0xff, 0xe1, 0xe1, 0xe1, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xc1, 0xc1, 0xc1, 0xff, 0xa5, 0xa5, 0xa5, 0xff, 0x88, 0x88, 0x88, 0xff, 0x88, 0x88, 0x88, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xc1, 0xc1, 0xc1, 0xff, 0x5c, 0x5c, 0x5c, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x79, 0x79, 0x79, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0x00, 0x00, 0xff, 0x6b, 0x6b, 0x6b, 0xff, 0xa5, 0xa5, 0xa5, 0xff, 0x4d, 0x4d, 0x4d, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x2f, 0x2f, 0x2f, 0xff, 0x00, 0x00, 0x00, 0xff, 0x10, 0x10, 0x10, 0xff, 0xc1, 0xc1, 0xc1, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xa5, 0xa5, 0xa5, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x88, 0x88, 0x88, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xc1, 0xc1, 0xc1, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0x88, 0x88, 0x88, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x88, 0x88, 0x88, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xc1, 0xc1, 0xc1, 0xff, 0xc1, 0xc1, 0xc1, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0x6b, 0x6b, 0x6b, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x88, 0x88, 0x88, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0x79, 0x79, 0x79, 0xff, 0x3e, 0x3e, 0x3e, 0xff, 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x88, 0x88, 0x88, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x96, 0x96, 0x96, 0xff, 0x10, 0x10, 0x10, 0xff, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0x96, 0x96, 0x96, 0xff, 0x96, 0x96, 0x96, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x88, 0x88, 0x88, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xc1, 0xc1, 0xc1, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x79, 0x79, 0x79, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x96, 0x96, 0x96, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x4d, 0x4d, 0x4d, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x88, 0x88, 0x88, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x79, 0x79, 0x79, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x2f, 0x2f, 0x2f, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x2f, 0x2f, 0x2f, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x10, 0x10, 0x10, 0xff, 0x3e, 0x3e, 0x3e, 0xff, 0x88, 0x88, 0x88, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xa5, 0xa5, 0xa5, 0xff, 0x2f, 0x2f, 0x2f, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x3e, 0x3e, 0x3e, 0xff, 0xa5, 0xa5, 0xa5, 0xff, 0x79, 0x79, 0x79, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0x79, 0x79, 0x79, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xc1, 0xc1, 0xc1, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0xc1, 0xc1, 0xc1, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xd9, 0xd9, 0xd9, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xe2, 0xe2, 0xe2, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xd1, 0xd1, 0xd1, 0xff,
};
 
struct fbtk_bitmap osk_image = {
.width = 18,
.height = 18,
.hot_x = 0,
.hot_y = 0,
.pixdata = osk_image_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/pointer_image.c
0,0 → 1,50
/* This file is auto-generated from framebuffer/res/pointers/default.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t pointer_image_pixdata[] = {
0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
};
 
struct fbtk_bitmap pointer_image = {
.width = 12,
.height = 22,
.hot_x = 0,
.hot_y = 0,
.pixdata = pointer_image_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/progress_image.c
0,0 → 1,50
/* This file is auto-generated from framebuffer/res/pointers/progress.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t progress_image_pixdata[] = {
0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00,
0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0xbb, 0xbb, 0xd4, 0xff, 0xf0, 0xf0, 0xff, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x33, 0x33, 0x4c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
 
struct fbtk_bitmap progress_image = {
.width = 23,
.height = 22,
.hot_x = 0,
.hot_y = 0,
.pixdata = progress_image_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/reload.c
0,0 → 1,54
/* This file is auto-generated from framebuffer/res/icons/reload.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t reload_pixdata[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x01, 0x02, 0xe1, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x7f, 0x01, 0x01, 0x03, 0xf2, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x17, 0x17, 0x2b, 0xff, 0x2e, 0x2e, 0x56, 0xff, 0x45, 0x45, 0x81, 0xff, 0x3d, 0x3d, 0x73, 0xff, 0x1e, 0x1e, 0x39, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x06, 0x06, 0x0c, 0xfd, 0x51, 0x51, 0xa7, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x01, 0x02, 0xe1, 0x00, 0x00, 0x00, 0xff, 0x26, 0x26, 0x48, 0xff, 0x72, 0x72, 0xd8, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x78, 0x78, 0xe5, 0xff, 0x75, 0x75, 0xe3, 0xff, 0x72, 0x72, 0xe1, 0xff, 0x5a, 0x5a, 0xb6, 0xff, 0x64, 0x64, 0xd0, 0xff, 0x68, 0x68, 0xdc, 0xff, 0x26, 0x26, 0x52, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, 0x02, 0xe1, 0x07, 0x07, 0x0d, 0xfd, 0x54, 0x54, 0x9e, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x78, 0x78, 0xe5, 0xff, 0x75, 0x75, 0xe3, 0xff, 0x71, 0x71, 0xe1, 0xff, 0x6e, 0x6e, 0xdf, 0xff, 0x6b, 0x6b, 0xdd, 0xff, 0x68, 0x68, 0xdc, 0xff, 0x64, 0x64, 0xda, 0xff, 0x55, 0x55, 0xbd, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xff, 0x5c, 0x5c, 0xad, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x72, 0x72, 0xd8, 0xff, 0x59, 0x59, 0xab, 0xff, 0x3a, 0x3a, 0x72, 0xff, 0x47, 0x47, 0x8d, 0xff, 0x59, 0x59, 0xb5, 0xff, 0x6a, 0x6a, 0xdd, 0xff, 0x67, 0x67, 0xdb, 0xff, 0x64, 0x64, 0xd9, 0xff, 0x61, 0x61, 0xd8, 0xff, 0x5d, 0x5d, 0xd6, 0xff, 0x22, 0x22, 0x50, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xff, 0x35, 0x35, 0x65, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x54, 0x54, 0x9e, 0xff, 0x0e, 0x0e, 0x1b, 0xfd, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x3a, 0x3a, 0x7b, 0xff, 0x63, 0x63, 0xd9, 0xff, 0x60, 0x60, 0xd7, 0xff, 0x5d, 0x5d, 0xd5, 0xff, 0x5a, 0x5a, 0xd4, 0xff, 0x46, 0x46, 0xab, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x07, 0x07, 0x0d, 0xfd, 0x7a, 0x7a, 0xe6, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x53, 0x53, 0x9e, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x01, 0x02, 0xe1, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x19, 0x19, 0x36, 0xff, 0x30, 0x30, 0x6c, 0xff, 0x1d, 0x1d, 0x43, 0xff, 0x16, 0x16, 0x35, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x01, 0x02, 0xe1, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, 0x01, 0x02, 0xf1, 0x26, 0x26, 0x48, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x6a, 0x6a, 0xc8, 0xff, 0x06, 0x06, 0x0c, 0xfc, 0x01, 0x01, 0x03, 0xd2, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xff, 0x45, 0x45, 0x81, 0xff, 0x7a, 0x7a, 0xe6, 0xff, 0x78, 0x78, 0xe5, 0xff, 0x49, 0x49, 0x8e, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0x17, 0x17, 0x2b, 0xff, 0x1e, 0x1e, 0x39, 0xff, 0x1d, 0x1d, 0x39, 0xff, 0x0e, 0x0e, 0x1c, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x8f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x70, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xff, 0x0e, 0x0e, 0x26, 0xff, 0x13, 0x13, 0x33, 0xff, 0x13, 0x13, 0x33, 0xff, 0x05, 0x05, 0x0d, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x0e, 0x0e, 0x26, 0xff, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xff, 0x1d, 0x1d, 0x4d, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x8f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x06, 0x06, 0x0d, 0xfe, 0x19, 0x19, 0x36, 0xff, 0x24, 0x24, 0x51, 0xff, 0x2e, 0x2e, 0x6b, 0xff, 0x06, 0x06, 0x0d, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x04, 0x04, 0x0c, 0xfe, 0x47, 0x47, 0xbf, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x34, 0x34, 0x8c, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, 0x02, 0xf1, 0x0d, 0x0d, 0x1c, 0xff, 0x65, 0x65, 0xda, 0xff, 0x62, 0x62, 0xd8, 0xff, 0x5e, 0x5e, 0xd6, 0xff, 0x5b, 0x5b, 0xd5, 0xff, 0x58, 0x58, 0xd3, 0xff, 0x0f, 0x0f, 0x25, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x13, 0x13, 0x33, 0xff, 0x43, 0x43, 0xb3, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x47, 0x47, 0xbf, 0xff, 0x09, 0x09, 0x18, 0xfd, 0x01, 0x01, 0x02, 0xe1, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x49, 0x49, 0xa2, 0xff, 0x5e, 0x5e, 0xd6, 0xff, 0x5b, 0x5b, 0xd4, 0xff, 0x57, 0x57, 0xd2, 0xff, 0x54, 0x54, 0xd1, 0xff, 0x4c, 0x4c, 0xc2, 0xff, 0x3b, 0x3b, 0x9a, 0xff, 0x26, 0x26, 0x66, 0xff, 0x30, 0x30, 0x80, 0xff, 0x39, 0x39, 0x99, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x18, 0x18, 0x40, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, 0x02, 0xf1, 0x17, 0x17, 0x36, 0xff, 0x5a, 0x5a, 0xd4, 0xff, 0x57, 0x57, 0xd2, 0xff, 0x54, 0x54, 0xd0, 0xff, 0x50, 0x50, 0xce, 0xff, 0x4d, 0x4d, 0xcd, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x47, 0x47, 0xbf, 0xff, 0x21, 0x21, 0x59, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x8f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x41, 0x41, 0x9e, 0xff, 0x53, 0x53, 0xd0, 0xff, 0x46, 0x46, 0xb4, 0xff, 0x43, 0x43, 0xb3, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x4c, 0x4c, 0xcc, 0xff, 0x39, 0x39, 0x99, 0xff, 0x09, 0x09, 0x18, 0xfd, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, 0x02, 0xf1, 0x15, 0x15, 0x34, 0xff, 0x31, 0x31, 0x81, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x09, 0x09, 0x18, 0xfd, 0x1d, 0x1d, 0x4d, 0xff, 0x2b, 0x2b, 0x73, 0xff, 0x26, 0x26, 0x66, 0xff, 0x18, 0x18, 0x40, 0xff, 0x09, 0x09, 0x18, 0xfd, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x50, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x01, 0x02, 0xf1, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, 0x02, 0xf1, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
};
 
struct fbtk_bitmap reload = {
.width = 24,
.height = 26,
.hot_x = 0,
.hot_y = 0,
.pixdata = reload_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/reload_g.c
0,0 → 1,54
/* This file is auto-generated from framebuffer/res/icons/reload_g.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t reload_g_pixdata[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x32, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x3f, 0x03, 0x03, 0x03, 0x51, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x54, 0x03, 0x03, 0x03, 0x46, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x21, 0x03, 0x03, 0x03, 0x50, 0x0f, 0x0f, 0x0f, 0x55, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x53, 0x09, 0x09, 0x09, 0x54, 0x36, 0x36, 0x36, 0x55, 0x5a, 0x5a, 0x5a, 0x55, 0x84, 0x84, 0x84, 0x55, 0x72, 0x72, 0x72, 0x55, 0x42, 0x42, 0x42, 0x55, 0x0f, 0x0f, 0x0f, 0x54, 0x00, 0x00, 0x00, 0x55, 0x12, 0x12, 0x12, 0x53, 0xab, 0xab, 0xab, 0x55, 0x0c, 0x0c, 0x0c, 0x54, 0x00, 0x00, 0x00, 0x32, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x03, 0x03, 0x03, 0x46, 0x00, 0x00, 0x00, 0x54, 0x54, 0x54, 0x54, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xae, 0xae, 0xae, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0x66, 0x66, 0x66, 0x55, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x03, 0x44, 0x15, 0x15, 0x15, 0x54, 0x9c, 0x9c, 0x9c, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0x0c, 0x0c, 0x0c, 0x54, 0x00, 0x00, 0x00, 0x32, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x03, 0x03, 0x03, 0x55, 0xa2, 0xa2, 0xa2, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0x9f, 0x9f, 0x9f, 0x55, 0x7b, 0x7b, 0x7b, 0x55, 0x87, 0x87, 0x87, 0x55, 0xab, 0xab, 0xab, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0x63, 0x63, 0x63, 0x55, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x54, 0x6c, 0x6c, 0x6c, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0x99, 0x99, 0x99, 0x55, 0x1b, 0x1b, 0x1b, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x7e, 0x7e, 0x7e, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xab, 0xab, 0xab, 0x55, 0x06, 0x06, 0x06, 0x54, 0x00, 0x00, 0x00, 0x32, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x32, 0x18, 0x18, 0x18, 0x53, 0xc9, 0xc9, 0xc9, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0x96, 0x96, 0x96, 0x55, 0x00, 0x00, 0x00, 0x54, 0x03, 0x03, 0x03, 0x45, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0x48, 0x48, 0x48, 0x55, 0x69, 0x69, 0x69, 0x55, 0x4b, 0x4b, 0x4b, 0x55, 0x30, 0x30, 0x30, 0x54, 0x12, 0x12, 0x12, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x03, 0x03, 0x03, 0x45, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x03, 0x03, 0x03, 0x49, 0x54, 0x54, 0x54, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0x12, 0x12, 0x12, 0x54, 0x03, 0x03, 0x03, 0x40, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x03, 0x03, 0x03, 0x4c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x55, 0x87, 0x87, 0x87, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0x8a, 0x8a, 0x8a, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x0d, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x55, 0x2a, 0x2a, 0x2a, 0x55, 0x33, 0x33, 0x33, 0x55, 0x33, 0x33, 0x33, 0x55, 0x18, 0x18, 0x18, 0x55, 0x03, 0x03, 0x03, 0x4b, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x27, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x1d, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x55, 0x2a, 0x2a, 0x2a, 0x55, 0x2d, 0x2d, 0x2d, 0x55, 0x2d, 0x2d, 0x2d, 0x55, 0x12, 0x12, 0x12, 0x55, 0x03, 0x03, 0x03, 0x4c, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x06, 0x06, 0x06, 0x53, 0xb1, 0xb1, 0xb1, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0x2a, 0x2a, 0x2a, 0x54, 0x00, 0x00, 0x00, 0x39, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x36, 0x03, 0x03, 0x03, 0x44, 0x03, 0x03, 0x03, 0x50, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x0e, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x03, 0x03, 0x54, 0x4e, 0x4e, 0x4e, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb1, 0xb1, 0xb1, 0x55, 0x06, 0x06, 0x06, 0x53, 0x00, 0x00, 0x00, 0x29, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x55, 0x03, 0x03, 0x03, 0x54, 0x1e, 0x1e, 0x1e, 0x54, 0x39, 0x39, 0x39, 0x55, 0x54, 0x54, 0x54, 0x55, 0x6f, 0x6f, 0x6f, 0x55, 0x1b, 0x1b, 0x1b, 0x55, 0x03, 0x03, 0x03, 0x4f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x25, 0x03, 0x03, 0x03, 0x52, 0x1b, 0x1b, 0x1b, 0x54, 0xab, 0xab, 0xab, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0x87, 0x87, 0x87, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x16, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x03, 0x03, 0x50, 0x42, 0x42, 0x42, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0x31, 0x31, 0x31, 0x53, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x54, 0x3f, 0x3f, 0x3f, 0x55, 0xa5, 0xa5, 0xa5, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xae, 0xae, 0xae, 0x55, 0x18, 0x18, 0x18, 0x53, 0x03, 0x03, 0x03, 0x45, 0x00, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x03, 0x03, 0x54, 0xa8, 0xa8, 0xa8, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb1, 0xb1, 0xb1, 0x55, 0x90, 0x90, 0x90, 0x55, 0x6c, 0x6c, 0x6c, 0x55, 0x78, 0x78, 0x78, 0x55, 0x9c, 0x9c, 0x9c, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0x54, 0x54, 0x54, 0x55, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x03, 0x03, 0x50, 0x4b, 0x4b, 0x4b, 0x54, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xae, 0xae, 0xae, 0x55, 0x54, 0x54, 0x54, 0x55, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x29, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x03, 0x03, 0x54, 0xa2, 0xa2, 0xa2, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xa5, 0xa5, 0xa5, 0x55, 0xa8, 0xa8, 0xa8, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0x93, 0x93, 0x93, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x03, 0x03, 0x50, 0x4b, 0x4b, 0x4b, 0x55, 0x78, 0x78, 0x78, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x1e, 0x1e, 0x1e, 0x53, 0x4b, 0x4b, 0x4b, 0x55, 0x6f, 0x6f, 0x6f, 0x55, 0x66, 0x66, 0x66, 0x55, 0x42, 0x42, 0x42, 0x55, 0x1e, 0x1e, 0x1e, 0x54, 0x00, 0x00, 0x00, 0x54, 0x03, 0x03, 0x03, 0x4a, 0x00, 0x00, 0x00, 0x14, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x03, 0x03, 0x54, 0x06, 0x06, 0x06, 0x53, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x3a, 0x03, 0x03, 0x03, 0x4e, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x03, 0x03, 0x03, 0x4a, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x03, 0x03, 0x50, 0x03, 0x03, 0x03, 0x4a, 0x00, 0x00, 0x00, 0x05, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
};
 
struct fbtk_bitmap reload_g = {
.width = 24,
.height = 26,
.hot_x = 0,
.hot_y = 0,
.pixdata = reload_g_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/right_arrow.c
0,0 → 1,54
/* This file is auto-generated from framebuffer/res/icons/forward.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t right_arrow_pixdata[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x03, 0x01, 0xd2, 0x00, 0x00, 0x00, 0xff, 0x01, 0x02, 0x01, 0xf1, 0x00, 0x00, 0x00, 0x50, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0x2d, 0x5f, 0x2d, 0xff, 0x12, 0x26, 0x12, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x8f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x4d, 0xa3, 0x4d, 0xff, 0x60, 0xcb, 0x60, 0xff, 0x20, 0x44, 0x20, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x4d, 0xa3, 0x4d, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x39, 0x7a, 0x39, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x4d, 0xa3, 0x4d, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x53, 0xb0, 0x53, 0xff, 0x06, 0x0d, 0x06, 0xfe, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x70, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x4d, 0xa3, 0x4d, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x5f, 0xd7, 0x5f, 0xff, 0x53, 0xc8, 0x53, 0xff, 0x14, 0x35, 0x14, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x4d, 0xa3, 0x4d, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x5f, 0xd7, 0x5f, 0xff, 0x58, 0xd5, 0x58, 0xff, 0x50, 0xd3, 0x50, 0xff, 0x49, 0xd2, 0x49, 0xff, 0x21, 0x68, 0x21, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x02, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x4d, 0xa3, 0x4d, 0xff, 0x66, 0xd9, 0x66, 0xff, 0x5f, 0xd7, 0x5f, 0xff, 0x58, 0xd5, 0x58, 0xff, 0x50, 0xd3, 0x50, 0xff, 0x49, 0xd2, 0x49, 0xff, 0x42, 0xd0, 0x42, 0xff, 0x3a, 0xce, 0x3a, 0xff, 0x23, 0x8c, 0x23, 0xff, 0x02, 0x0b, 0x02, 0xfd, 0x00, 0x02, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x4d, 0xa3, 0x4d, 0xff, 0x5f, 0xd7, 0x5f, 0xff, 0x58, 0xd5, 0x58, 0xff, 0x50, 0xd3, 0x50, 0xff, 0x49, 0xd2, 0x49, 0xff, 0x42, 0xd0, 0x42, 0xff, 0x3a, 0xce, 0x3a, 0xff, 0x33, 0xcc, 0x33, 0xff, 0x2c, 0xca, 0x2c, 0xff, 0x20, 0xaf, 0x20, 0xff, 0x05, 0x25, 0x05, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x47, 0xa1, 0x47, 0xff, 0x58, 0xd5, 0x58, 0xff, 0x50, 0xd3, 0x50, 0xff, 0x49, 0xd2, 0x49, 0xff, 0x42, 0xd0, 0x42, 0xff, 0x3a, 0xce, 0x3a, 0xff, 0x33, 0xcc, 0x33, 0xff, 0x2c, 0xca, 0x2c, 0xff, 0x24, 0xc8, 0x24, 0xff, 0x1d, 0xc6, 0x1d, 0xff, 0x16, 0xc5, 0x16, 0xff, 0x05, 0x49, 0x05, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x02, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x42, 0xa0, 0x42, 0xff, 0x50, 0xd3, 0x50, 0xff, 0x49, 0xd2, 0x49, 0xff, 0x42, 0xd0, 0x42, 0xff, 0x3a, 0xce, 0x3a, 0xff, 0x33, 0xcc, 0x33, 0xff, 0x2c, 0xca, 0x2c, 0xff, 0x24, 0xc8, 0x24, 0xff, 0x1d, 0xc6, 0x1d, 0xff, 0x16, 0xc5, 0x16, 0xff, 0x0e, 0xc3, 0x0e, 0xff, 0x07, 0xc1, 0x07, 0xff, 0x00, 0x77, 0x00, 0xff, 0x00, 0x0a, 0x00, 0xfc, 0x00, 0x02, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x50, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x3c, 0x9e, 0x3c, 0xff, 0x49, 0xd2, 0x49, 0xff, 0x42, 0xd0, 0x42, 0xff, 0x3a, 0xce, 0x3a, 0xff, 0x33, 0xcc, 0x33, 0xff, 0x2c, 0xca, 0x2c, 0xff, 0x24, 0xc8, 0x24, 0xff, 0x1d, 0xc6, 0x1d, 0xff, 0x16, 0xc5, 0x16, 0xff, 0x0e, 0xc3, 0x0e, 0xff, 0x07, 0xc1, 0x07, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0x9b, 0x00, 0xff, 0x00, 0x22, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x37, 0x9e, 0x37, 0xff, 0x42, 0xd0, 0x42, 0xff, 0x3a, 0xce, 0x3a, 0xff, 0x33, 0xcc, 0x33, 0xff, 0x2c, 0xca, 0x2c, 0xff, 0x24, 0xc8, 0x24, 0xff, 0x1d, 0xc6, 0x1d, 0xff, 0x16, 0xc5, 0x16, 0xff, 0x0e, 0xc3, 0x0e, 0xff, 0x07, 0xc1, 0x07, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0x9b, 0x00, 0xff, 0x00, 0x22, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x32, 0x9c, 0x32, 0xff, 0x3a, 0xce, 0x3a, 0xff, 0x33, 0xcc, 0x33, 0xff, 0x2c, 0xca, 0x2c, 0xff, 0x24, 0xc8, 0x24, 0xff, 0x1d, 0xc6, 0x1d, 0xff, 0x16, 0xc5, 0x16, 0xff, 0x0e, 0xc3, 0x0e, 0xff, 0x07, 0xc1, 0x07, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0x77, 0x00, 0xff, 0x00, 0x0a, 0x00, 0xfc, 0x00, 0x02, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x50, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x2c, 0x9b, 0x2c, 0xff, 0x33, 0xcc, 0x33, 0xff, 0x2c, 0xca, 0x2c, 0xff, 0x24, 0xc8, 0x24, 0xff, 0x1d, 0xc6, 0x1d, 0xff, 0x16, 0xc5, 0x16, 0xff, 0x0e, 0xc3, 0x0e, 0xff, 0x07, 0xc1, 0x07, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0x54, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x02, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x26, 0x99, 0x26, 0xff, 0x2c, 0xca, 0x2c, 0xff, 0x24, 0xc8, 0x24, 0xff, 0x1d, 0xc6, 0x1d, 0xff, 0x16, 0xc5, 0x16, 0xff, 0x0e, 0xc3, 0x0e, 0xff, 0x07, 0xc1, 0x07, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xa7, 0x00, 0xff, 0x00, 0x24, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x21, 0x98, 0x21, 0xff, 0x24, 0xc8, 0x24, 0xff, 0x1d, 0xc6, 0x1d, 0xff, 0x16, 0xc5, 0x16, 0xff, 0x0e, 0xc3, 0x0e, 0xff, 0x07, 0xc1, 0x07, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0x83, 0x00, 0xff, 0x00, 0x0a, 0x00, 0xfd, 0x00, 0x02, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x1b, 0x96, 0x1b, 0xff, 0x1d, 0xc6, 0x1d, 0xff, 0x16, 0xc5, 0x16, 0xff, 0x0e, 0xc3, 0x0e, 0xff, 0x07, 0xc1, 0x07, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0x60, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x02, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x16, 0x95, 0x16, 0xff, 0x16, 0xc5, 0x16, 0xff, 0x0e, 0xc3, 0x0e, 0xff, 0x07, 0xc1, 0x07, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0xb3, 0x00, 0xff, 0x00, 0x30, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x11, 0x94, 0x11, 0xff, 0x0e, 0xc3, 0x0e, 0xff, 0x07, 0xc1, 0x07, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0x9b, 0x00, 0xff, 0x00, 0x0b, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x70, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x0b, 0x92, 0x0b, 0xff, 0x07, 0xc1, 0x07, 0xff, 0x00, 0xbf, 0x00, 0xff, 0x00, 0x6b, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x05, 0x91, 0x05, 0xff, 0x00, 0xb3, 0x00, 0xff, 0x00, 0x3c, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0x00, 0x54, 0x00, 0xff, 0x00, 0x22, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x8f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xff, 0x00, 0x02, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x50, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
};
 
struct fbtk_bitmap right_arrow = {
.width = 22,
.height = 26,
.hot_x = 0,
.hot_y = 0,
.pixdata = right_arrow_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/right_arrow_g.c
0,0 → 1,54
/* This file is auto-generated from framebuffer/res/icons/forward_g.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t right_arrow_g_pixdata[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x55, 0x03, 0x03, 0x03, 0x4e, 0x00, 0x00, 0x00, 0x15, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x55, 0x78, 0x78, 0x78, 0x55, 0x24, 0x24, 0x24, 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x28, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0x51, 0x51, 0x51, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x05, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0x7e, 0x7e, 0x7e, 0x55, 0x06, 0x06, 0x06, 0x54, 0x03, 0x03, 0x03, 0x4b, 0x00, 0x00, 0x00, 0x11, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xa2, 0xa2, 0xa2, 0x55, 0x18, 0x18, 0x18, 0x53, 0x03, 0x03, 0x03, 0x53, 0x00, 0x00, 0x00, 0x22, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xba, 0xba, 0xba, 0x55, 0x3c, 0x3c, 0x3c, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0x69, 0x69, 0x69, 0x55, 0x03, 0x03, 0x03, 0x55, 0x03, 0x03, 0x03, 0x47, 0x00, 0x00, 0x00, 0x0d, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0x93, 0x93, 0x93, 0x55, 0x12, 0x12, 0x12, 0x54, 0x03, 0x03, 0x03, 0x52, 0x00, 0x00, 0x00, 0x1b, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xae, 0xae, 0xae, 0x55, 0x30, 0x30, 0x30, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xba, 0xba, 0xba, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0x5a, 0x5a, 0x5a, 0x55, 0x00, 0x00, 0x00, 0x54, 0x03, 0x03, 0x03, 0x42, 0x00, 0x00, 0x00, 0x09, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xba, 0xba, 0xba, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0x81, 0x81, 0x81, 0x55, 0x09, 0x09, 0x09, 0x54, 0x03, 0x03, 0x03, 0x4f, 0x00, 0x00, 0x00, 0x16, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xba, 0xba, 0xba, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x9f, 0x9f, 0x9f, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x9f, 0x9f, 0x9f, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x19, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x7e, 0x7e, 0x7e, 0x55, 0x09, 0x09, 0x09, 0x54, 0x03, 0x03, 0x03, 0x4f, 0x00, 0x00, 0x00, 0x17, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb1, 0xb1, 0xb1, 0x55, 0x57, 0x57, 0x57, 0x55, 0x00, 0x00, 0x00, 0x54, 0x03, 0x03, 0x03, 0x43, 0x00, 0x00, 0x00, 0x09, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xa5, 0xa5, 0xa5, 0x55, 0x2d, 0x2d, 0x2d, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xb1, 0xb1, 0xb1, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x8a, 0x8a, 0x8a, 0x55, 0x0f, 0x0f, 0x0f, 0x54, 0x03, 0x03, 0x03, 0x52, 0x00, 0x00, 0x00, 0x1b, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xb1, 0xb1, 0xb1, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x63, 0x63, 0x63, 0x55, 0x03, 0x03, 0x03, 0x55, 0x03, 0x03, 0x03, 0x47, 0x00, 0x00, 0x00, 0x0d, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xb1, 0xb1, 0xb1, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xab, 0xab, 0xab, 0x55, 0x39, 0x39, 0x39, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xae, 0xae, 0xae, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x93, 0x93, 0x93, 0x55, 0x18, 0x18, 0x18, 0x54, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x22, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xae, 0xae, 0xae, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x6f, 0x6f, 0x6f, 0x55, 0x06, 0x06, 0x06, 0x54, 0x03, 0x03, 0x03, 0x4c, 0x00, 0x00, 0x00, 0x11, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0xae, 0xae, 0xae, 0x55, 0xb1, 0xb1, 0xb1, 0x55, 0x48, 0x48, 0x48, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x05, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x55, 0x6c, 0x6c, 0x6c, 0x55, 0x21, 0x21, 0x21, 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x55, 0x03, 0x03, 0x03, 0x4e, 0x00, 0x00, 0x00, 0x15, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
};
 
struct fbtk_bitmap right_arrow_g = {
.width = 22,
.height = 26,
.hot_x = 0,
.hot_y = 0,
.pixdata = right_arrow_g_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/scrolld.c
0,0 → 1,46
/* This file is auto-generated from framebuffer/res/icons/scrolld.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t scrolld_pixdata[] = {
0xea, 0xea, 0xea, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xd9, 0xd9, 0xd9, 0xff,
0xee, 0xee, 0xee, 0xff, 0xe1, 0xe1, 0xe1, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xb9, 0xb9, 0xb9, 0xff, 0x6b, 0x6b, 0x6b, 0xff, 0x93, 0x93, 0x93, 0xff, 0xbd, 0xbd, 0xbd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xbd, 0xbd, 0xbd, 0xff, 0x93, 0x93, 0x93, 0xff, 0x68, 0x68, 0x68, 0xff, 0xb8, 0xb8, 0xb8, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x61, 0x61, 0x61, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x3e, 0x3e, 0x3e, 0xff, 0x3e, 0x3e, 0x3e, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x63, 0x63, 0x63, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xb8, 0xb8, 0xb8, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x34, 0x34, 0x34, 0xff, 0xb8, 0xb8, 0xb8, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x6d, 0x6d, 0x6d, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x6d, 0x6d, 0x6d, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xc1, 0xc1, 0xc1, 0xff, 0x36, 0x36, 0x36, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x37, 0x37, 0x37, 0xff, 0xc1, 0xc1, 0xc1, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x78, 0x78, 0x78, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x78, 0x78, 0x78, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xc9, 0xc9, 0xc9, 0xff, 0x3a, 0x3a, 0x3a, 0xff, 0x3b, 0x3b, 0x3b, 0xff, 0xc9, 0xc9, 0xc9, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x83, 0x83, 0x83, 0xff, 0x83, 0x83, 0x83, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xd0, 0xd0, 0xd0, 0xff, 0xd0, 0xd0, 0xd0, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xd9, 0xd9, 0xd9, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xe2, 0xe2, 0xe2, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xd1, 0xd1, 0xd1, 0xff,
};
 
struct fbtk_bitmap scrolld = {
.width = 18,
.height = 18,
.hot_x = 0,
.hot_y = 0,
.pixdata = scrolld_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/scrolll.c
0,0 → 1,46
/* This file is auto-generated from framebuffer/res/icons/scrolll.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t scrolll_pixdata[] = {
0xea, 0xea, 0xea, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xd9, 0xd9, 0xd9, 0xff,
0xee, 0xee, 0xee, 0xff, 0xe1, 0xe1, 0xe1, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xbc, 0xbc, 0xbc, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xbc, 0xbc, 0xbc, 0xff, 0x61, 0x61, 0x61, 0xff, 0x68, 0x68, 0x68, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xc5, 0xc5, 0xc5, 0xff, 0x6d, 0x6d, 0x6d, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x93, 0x93, 0x93, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xcd, 0xcd, 0xcd, 0xff, 0x78, 0x78, 0x78, 0xff, 0x36, 0x36, 0x36, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0xbd, 0xbd, 0xbd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xd2, 0xd2, 0xd2, 0xff, 0x84, 0x84, 0x84, 0xff, 0x3a, 0x3a, 0x3a, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x3f, 0x3f, 0x3f, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xd1, 0xd1, 0xd1, 0xff, 0x81, 0x81, 0x81, 0xff, 0x38, 0x38, 0x38, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x3f, 0x3f, 0x3f, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xca, 0xca, 0xca, 0xff, 0x75, 0x75, 0x75, 0xff, 0x36, 0x36, 0x36, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0xbd, 0xbd, 0xbd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xc2, 0xc2, 0xc2, 0xff, 0x6b, 0x6b, 0x6b, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x93, 0x93, 0x93, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xb9, 0xb9, 0xb9, 0xff, 0x5f, 0x5f, 0x5f, 0xff, 0x68, 0x68, 0x68, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xb9, 0xb9, 0xb9, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xd9, 0xd9, 0xd9, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xe2, 0xe2, 0xe2, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xd1, 0xd1, 0xd1, 0xff,
};
 
struct fbtk_bitmap scrolll = {
.width = 18,
.height = 18,
.hot_x = 0,
.hot_y = 0,
.pixdata = scrolll_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/scrollr.c
0,0 → 1,46
/* This file is auto-generated from framebuffer/res/icons/scrollr.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t scrollr_pixdata[] = {
0xea, 0xea, 0xea, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xd9, 0xd9, 0xd9, 0xff,
0xee, 0xee, 0xee, 0xff, 0xe1, 0xe1, 0xe1, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xbc, 0xbc, 0xbc, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x68, 0x68, 0x68, 0xff, 0x61, 0x61, 0x61, 0xff, 0xbc, 0xbc, 0xbc, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x93, 0x93, 0x93, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x6d, 0x6d, 0x6d, 0xff, 0xc5, 0xc5, 0xc5, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xbd, 0xbd, 0xbd, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x36, 0x36, 0x36, 0xff, 0x78, 0x78, 0x78, 0xff, 0xcd, 0xcd, 0xcd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0x3f, 0x3f, 0x3f, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x3a, 0x3a, 0x3a, 0xff, 0x84, 0x84, 0x84, 0xff, 0xd2, 0xd2, 0xd2, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdc, 0xdc, 0xdc, 0xff, 0x3f, 0x3f, 0x3f, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x38, 0x38, 0x38, 0xff, 0x83, 0x83, 0x83, 0xff, 0xd2, 0xd2, 0xd2, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xbd, 0xbd, 0xbd, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x36, 0x36, 0x36, 0xff, 0x77, 0x77, 0x77, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x93, 0x93, 0x93, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x6c, 0x6c, 0x6c, 0xff, 0xc4, 0xc4, 0xc4, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x68, 0x68, 0x68, 0xff, 0x60, 0x60, 0x60, 0xff, 0xba, 0xba, 0xba, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xba, 0xba, 0xba, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xd9, 0xd9, 0xd9, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xe2, 0xe2, 0xe2, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xd1, 0xd1, 0xd1, 0xff,
};
 
struct fbtk_bitmap scrollr = {
.width = 18,
.height = 18,
.hot_x = 0,
.hot_y = 0,
.pixdata = scrollr_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/scrollu.c
0,0 → 1,46
/* This file is auto-generated from framebuffer/res/icons/scrollu.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t scrollu_pixdata[] = {
0xea, 0xea, 0xea, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xee, 0xee, 0xee, 0xff, 0xd9, 0xd9, 0xd9, 0xff,
0xee, 0xee, 0xee, 0xff, 0xe1, 0xe1, 0xe1, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xd0, 0xd0, 0xd0, 0xff, 0xd2, 0xd2, 0xd2, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x83, 0x83, 0x83, 0xff, 0x83, 0x83, 0x83, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xc9, 0xc9, 0xc9, 0xff, 0x3b, 0x3b, 0x3b, 0xff, 0x3b, 0x3b, 0x3b, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x78, 0x78, 0x78, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x78, 0x78, 0x78, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xc1, 0xc1, 0xc1, 0xff, 0x37, 0x37, 0x37, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x37, 0x37, 0x37, 0xff, 0xc4, 0xc4, 0xc4, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x6d, 0x6d, 0x6d, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x6d, 0x6d, 0x6d, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xb8, 0xb8, 0xb8, 0xff, 0x34, 0x34, 0x34, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x34, 0x34, 0x34, 0xff, 0xba, 0xba, 0xba, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0x63, 0x63, 0x63, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x3e, 0x3e, 0x3e, 0xff, 0x3e, 0x3e, 0x3e, 0xff, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0xff, 0x63, 0x63, 0x63, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xb8, 0xb8, 0xb8, 0xff, 0x68, 0x68, 0x68, 0xff, 0x93, 0x93, 0x93, 0xff, 0xbd, 0xbd, 0xbd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xbd, 0xbd, 0xbd, 0xff, 0x93, 0x93, 0x93, 0xff, 0x68, 0x68, 0x68, 0xff, 0xba, 0xba, 0xba, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xee, 0xee, 0xee, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xdb, 0xdb, 0xdb, 0xff, 0xd9, 0xd9, 0xd9, 0xff, 0xcc, 0xcc, 0xcc, 0xff,
0xe2, 0xe2, 0xe2, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0xd1, 0xd1, 0xd1, 0xff,
};
 
struct fbtk_bitmap scrollu = {
.width = 18,
.height = 18,
.hot_x = 0,
.hot_y = 0,
.pixdata = scrollu_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/stop_image.c
0,0 → 1,54
/* This file is auto-generated from framebuffer/res/icons/stop.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t stop_image_pixdata[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xff, 0x03, 0x01, 0x01, 0xf2, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x01, 0x01, 0xf2, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xff, 0x26, 0x12, 0x12, 0xfc, 0x26, 0x12, 0x12, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x25, 0x10, 0x10, 0xfc, 0x25, 0x0f, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xff, 0x26, 0x12, 0x12, 0xfc, 0xcb, 0x60, 0x60, 0xff, 0xcb, 0x60, 0x60, 0xff, 0x44, 0x20, 0x20, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xff, 0x42, 0x1c, 0x1c, 0xff, 0xc4, 0x51, 0x51, 0xff, 0xc2, 0x4e, 0x4e, 0xff, 0x24, 0x0e, 0x0e, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xff, 0x26, 0x12, 0x12, 0xfc, 0xcb, 0x60, 0x60, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0x5f, 0x2d, 0x2d, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xff, 0x5c, 0x27, 0x27, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xbf, 0x48, 0x48, 0xff, 0x23, 0x0d, 0x0d, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x01, 0x01, 0xf2, 0x26, 0x12, 0x12, 0xfc, 0xcb, 0x60, 0x60, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0x88, 0x40, 0x40, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xff, 0x84, 0x38, 0x38, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xbd, 0x44, 0x44, 0xff, 0x23, 0x0c, 0x0c, 0xfc, 0x02, 0x01, 0x01, 0xf2, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xff, 0x44, 0x20, 0x20, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xb0, 0x53, 0x53, 0xff, 0x0c, 0x06, 0x06, 0xfd, 0x03, 0x01, 0x01, 0xf2, 0x03, 0x01, 0x01, 0xf2, 0x0c, 0x05, 0x05, 0xfd, 0xab, 0x48, 0x48, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0x3f, 0x16, 0x16, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x5f, 0x2d, 0x2d, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xbc, 0x57, 0x57, 0xff, 0x32, 0x17, 0x17, 0xfb, 0x25, 0x10, 0x10, 0xfc, 0xb9, 0x4e, 0x4e, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0x58, 0x1f, 0x1f, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xff, 0x88, 0x40, 0x40, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd7, 0x63, 0x63, 0xff, 0xd6, 0x60, 0x60, 0xff, 0xd4, 0x5d, 0x5d, 0xff, 0xd3, 0x59, 0x59, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0x7e, 0x2c, 0x2c, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, 0x01, 0xd2, 0x00, 0x00, 0x00, 0xff, 0xb0, 0x53, 0x53, 0xff, 0xd9, 0x66, 0x66, 0xff, 0xd7, 0x63, 0x63, 0xff, 0xd6, 0x60, 0x60, 0xff, 0xd4, 0x5d, 0x5d, 0xff, 0xd3, 0x59, 0x59, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0xa3, 0x39, 0x39, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0xf0, 0x0d, 0x06, 0x06, 0xfe, 0xbc, 0x57, 0x57, 0xff, 0xd6, 0x60, 0x60, 0xff, 0xd4, 0x5d, 0x5d, 0xff, 0xd3, 0x59, 0x59, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0xb0, 0x3d, 0x3d, 0xff, 0x0b, 0x04, 0x04, 0xfd, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03, 0x01, 0x01, 0xf2, 0x26, 0x11, 0x11, 0xfc, 0xd4, 0x5d, 0x5d, 0xff, 0xd3, 0x59, 0x59, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0xc9, 0x46, 0x46, 0xff, 0x2f, 0x10, 0x10, 0xfb, 0x02, 0x01, 0x01, 0xf2, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03, 0x01, 0x01, 0xf2, 0x32, 0x16, 0x16, 0xfb, 0xd3, 0x59, 0x59, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0xc9, 0x46, 0x46, 0xff, 0xc7, 0x43, 0x43, 0xff, 0x23, 0x0b, 0x0b, 0xfc, 0x02, 0x01, 0x01, 0xf2, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0xf0, 0x0c, 0x05, 0x05, 0xfd, 0xb9, 0x4e, 0x4e, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0xc9, 0x46, 0x46, 0xff, 0xc7, 0x43, 0x43, 0xff, 0xc6, 0x40, 0x40, 0xff, 0xac, 0x35, 0x35, 0xff, 0x0b, 0x03, 0x03, 0xfd, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xab, 0x48, 0x48, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0xc9, 0x46, 0x46, 0xff, 0xc7, 0x43, 0x43, 0xff, 0xc6, 0x40, 0x40, 0xff, 0xc4, 0x3d, 0x3d, 0xff, 0xc2, 0x39, 0x39, 0xff, 0x9d, 0x2c, 0x2c, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xff, 0x84, 0x38, 0x38, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0xc9, 0x46, 0x46, 0xff, 0xc7, 0x43, 0x43, 0xff, 0xc6, 0x40, 0x40, 0xff, 0xc4, 0x3d, 0x3d, 0xff, 0xc2, 0x39, 0x39, 0xff, 0xc1, 0x36, 0x36, 0xff, 0xbf, 0x33, 0x33, 0xff, 0x77, 0x20, 0x20, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x5c, 0x27, 0x27, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0xb0, 0x3d, 0x3d, 0xff, 0x23, 0x0c, 0x0c, 0xfc, 0x2f, 0x0f, 0x0f, 0xfb, 0xac, 0x35, 0x35, 0xff, 0xc2, 0x39, 0x39, 0xff, 0xc1, 0x36, 0x36, 0xff, 0xbf, 0x33, 0x33, 0xff, 0xbf, 0x33, 0x33, 0xff, 0xbf, 0x33, 0x33, 0xff, 0x54, 0x16, 0x16, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xff, 0x42, 0x1c, 0x1c, 0xff, 0xd1, 0x56, 0x56, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0xa3, 0x39, 0x39, 0xff, 0x0b, 0x04, 0x04, 0xfd, 0x02, 0x01, 0x01, 0xf2, 0x02, 0x01, 0x01, 0xf2, 0x0b, 0x03, 0x03, 0xfe, 0x9d, 0x2c, 0x2c, 0xff, 0xbf, 0x33, 0x33, 0xff, 0xbf, 0x33, 0x33, 0xff, 0xbf, 0x33, 0x33, 0xff, 0xbf, 0x33, 0x33, 0xff, 0xbf, 0x33, 0x33, 0xff, 0x3c, 0x10, 0x10, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x01, 0x01, 0xf2, 0x25, 0x10, 0x10, 0xfc, 0xc4, 0x51, 0x51, 0xff, 0xcf, 0x53, 0x53, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0x7e, 0x2c, 0x2c, 0xff, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xff, 0x77, 0x20, 0x20, 0xff, 0xbf, 0x33, 0x33, 0xff, 0xbf, 0x33, 0x33, 0xff, 0xbf, 0x33, 0x33, 0xff, 0xbf, 0x33, 0x33, 0xff, 0xb3, 0x30, 0x30, 0xff, 0x22, 0x09, 0x09, 0xfc, 0x02, 0x01, 0x01, 0xf2, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xff, 0x25, 0x0f, 0x0f, 0xfc, 0xc2, 0x4e, 0x4e, 0xff, 0xce, 0x50, 0x50, 0xff, 0xcc, 0x4d, 0x4d, 0xff, 0xca, 0x49, 0x49, 0xff, 0x58, 0x1f, 0x1f, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x01, 0x01, 0xd2, 0x00, 0x00, 0x00, 0xff, 0x54, 0x16, 0x16, 0xff, 0xbf, 0x33, 0x33, 0xff, 0xbf, 0x33, 0x33, 0xff, 0xbf, 0x33, 0x33, 0xff, 0xb3, 0x30, 0x30, 0xff, 0x22, 0x09, 0x09, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xff, 0x24, 0x0e, 0x0e, 0xfc, 0xbf, 0x48, 0x48, 0xff, 0xbd, 0x44, 0x44, 0xff, 0x3f, 0x16, 0x16, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xff, 0x3c, 0x10, 0x10, 0xff, 0xb3, 0x30, 0x30, 0xff, 0xb3, 0x30, 0x30, 0xff, 0x22, 0x09, 0x09, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xff, 0x23, 0x0d, 0x0d, 0xfc, 0x23, 0x0c, 0x0c, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x22, 0x09, 0x09, 0xfc, 0x22, 0x09, 0x09, 0xfc, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xff, 0x02, 0x01, 0x01, 0xf2, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x01, 0x01, 0xf2, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
};
 
struct fbtk_bitmap stop_image = {
.width = 26,
.height = 26,
.hot_x = 0,
.hot_y = 0,
.pixdata = stop_image_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/stop_image_g.c
0,0 → 1,54
/* This file is auto-generated from framebuffer/res/icons/stop_g.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t stop_image_g_pixdata[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x03, 0x03, 0x53, 0x03, 0x03, 0x03, 0x51, 0x00, 0x00, 0x00, 0x17, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x17, 0x03, 0x03, 0x03, 0x51, 0x03, 0x03, 0x03, 0x54, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x03, 0x03, 0x53, 0x2d, 0x2d, 0x2d, 0x54, 0x2a, 0x2a, 0x2a, 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x25, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x54, 0x27, 0x27, 0x27, 0x54, 0x2a, 0x2a, 0x2a, 0x54, 0x03, 0x03, 0x03, 0x54, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x03, 0x03, 0x53, 0x2d, 0x2d, 0x2d, 0x54, 0xc3, 0xc3, 0xc3, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0x48, 0x48, 0x48, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x55, 0x45, 0x45, 0x45, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0x2a, 0x2a, 0x2a, 0x54, 0x03, 0x03, 0x03, 0x54, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0x03, 0x03, 0x53, 0x2d, 0x2d, 0x2d, 0x54, 0xc3, 0xc3, 0xc3, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0x69, 0x69, 0x69, 0x55, 0x00, 0x00, 0x00, 0x54, 0x03, 0x03, 0x03, 0x40, 0x00, 0x00, 0x00, 0x06, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x03, 0x03, 0x40, 0x00, 0x00, 0x00, 0x54, 0x63, 0x63, 0x63, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0x2a, 0x2a, 0x2a, 0x54, 0x03, 0x03, 0x03, 0x54, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0x03, 0x03, 0x51, 0x2d, 0x2d, 0x2d, 0x54, 0xc6, 0xc6, 0xc6, 0x55, 0xcc, 0xcc, 0xcc, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0x87, 0x87, 0x87, 0x55, 0x06, 0x06, 0x06, 0x54, 0x03, 0x03, 0x03, 0x4a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0d, 0x03, 0x03, 0x03, 0x4a, 0x06, 0x06, 0x06, 0x54, 0x84, 0x84, 0x84, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x27, 0x27, 0x27, 0x54, 0x03, 0x03, 0x03, 0x51, 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x54, 0x4b, 0x4b, 0x4b, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0x9f, 0x9f, 0x9f, 0x55, 0x12, 0x12, 0x12, 0x54, 0x03, 0x03, 0x03, 0x51, 0x03, 0x03, 0x03, 0x51, 0x12, 0x12, 0x12, 0x54, 0x9c, 0x9c, 0x9c, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0x45, 0x45, 0x45, 0x55, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x17, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x55, 0x6c, 0x6c, 0x6c, 0x55, 0xc9, 0xc9, 0xc9, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xb1, 0xb1, 0xb1, 0x55, 0x36, 0x36, 0x36, 0x54, 0x30, 0x30, 0x30, 0x54, 0xae, 0xae, 0xae, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0x63, 0x63, 0x63, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x25, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x54, 0x8a, 0x8a, 0x8a, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0x81, 0x81, 0x81, 0x55, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x32, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x40, 0x06, 0x06, 0x06, 0x54, 0xa2, 0xa2, 0xa2, 0x55, 0xc6, 0xc6, 0xc6, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0x99, 0x99, 0x99, 0x55, 0x06, 0x06, 0x06, 0x54, 0x03, 0x03, 0x03, 0x40, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x03, 0x03, 0x4a, 0x15, 0x15, 0x15, 0x54, 0xb4, 0xb4, 0xb4, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xab, 0xab, 0xab, 0x55, 0x12, 0x12, 0x12, 0x53, 0x03, 0x03, 0x03, 0x4a, 0x00, 0x00, 0x00, 0x06, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x03, 0x03, 0x03, 0x51, 0x39, 0x39, 0x39, 0x55, 0xc3, 0xc3, 0xc3, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0x37, 0x37, 0x37, 0x53, 0x03, 0x03, 0x03, 0x51, 0x00, 0x00, 0x00, 0x0d, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x03, 0x03, 0x03, 0x51, 0x3a, 0x3a, 0x3a, 0x53, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0x34, 0x34, 0x34, 0x53, 0x03, 0x03, 0x03, 0x50, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x03, 0x03, 0x4a, 0x15, 0x15, 0x15, 0x54, 0xb1, 0xb1, 0xb1, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xa8, 0xa8, 0xa8, 0x55, 0x12, 0x12, 0x12, 0x54, 0x03, 0x03, 0x03, 0x49, 0x00, 0x00, 0x00, 0x05, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x40, 0x06, 0x06, 0x06, 0x54, 0x9f, 0x9f, 0x9f, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x96, 0x96, 0x96, 0x55, 0x06, 0x06, 0x06, 0x54, 0x04, 0x04, 0x04, 0x3f, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x54, 0x84, 0x84, 0x84, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xba, 0xba, 0xba, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x7b, 0x7b, 0x7b, 0x55, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x55, 0x66, 0x66, 0x66, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xa8, 0xa8, 0xa8, 0x55, 0x30, 0x30, 0x30, 0x54, 0x36, 0x36, 0x36, 0x54, 0xa8, 0xa8, 0xa8, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0x60, 0x60, 0x60, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x23, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x54, 0x45, 0x45, 0x45, 0x54, 0xc0, 0xc0, 0xc0, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0x99, 0x99, 0x99, 0x55, 0x12, 0x12, 0x12, 0x54, 0x03, 0x03, 0x03, 0x51, 0x03, 0x03, 0x03, 0x52, 0x12, 0x12, 0x12, 0x53, 0x96, 0x96, 0x96, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0x42, 0x42, 0x42, 0x55, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x16, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x03, 0x03, 0x03, 0x51, 0x2a, 0x2a, 0x2a, 0x54, 0xba, 0xba, 0xba, 0x55, 0xc0, 0xc0, 0xc0, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0x81, 0x81, 0x81, 0x55, 0x06, 0x06, 0x06, 0x54, 0x03, 0x03, 0x03, 0x4a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x03, 0x03, 0x4a, 0x06, 0x06, 0x06, 0x54, 0x7b, 0x7b, 0x7b, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xae, 0xae, 0xae, 0x55, 0x27, 0x27, 0x27, 0x54, 0x03, 0x03, 0x03, 0x50, 0x00, 0x00, 0x00, 0x06, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x03, 0x03, 0x03, 0x54, 0x2d, 0x2d, 0x2d, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0xbd, 0xbd, 0xbd, 0x55, 0x60, 0x60, 0x60, 0x55, 0x00, 0x00, 0x00, 0x54, 0x03, 0x03, 0x03, 0x40, 0x00, 0x00, 0x00, 0x06, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0x03, 0x03, 0x41, 0x00, 0x00, 0x00, 0x54, 0x60, 0x60, 0x60, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xb4, 0xb4, 0xb4, 0x55, 0xab, 0xab, 0xab, 0x55, 0x2a, 0x2a, 0x2a, 0x55, 0x03, 0x03, 0x03, 0x54, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x03, 0x03, 0x54, 0x2a, 0x2a, 0x2a, 0x54, 0xb4, 0xb4, 0xb4, 0x55, 0xb7, 0xb7, 0xb7, 0x55, 0x42, 0x42, 0x42, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x55, 0x42, 0x42, 0x42, 0x55, 0xae, 0xae, 0xae, 0x55, 0xab, 0xab, 0xab, 0x55, 0x2a, 0x2a, 0x2a, 0x55, 0x03, 0x03, 0x03, 0x54, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x03, 0x03, 0x54, 0x2a, 0x2a, 0x2a, 0x54, 0x27, 0x27, 0x27, 0x54, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x25, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x54, 0x27, 0x27, 0x27, 0x54, 0x2a, 0x2a, 0x2a, 0x55, 0x03, 0x03, 0x03, 0x54, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x03, 0x03, 0x54, 0x03, 0x03, 0x03, 0x51, 0x00, 0x00, 0x00, 0x17, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x03, 0x03, 0x52, 0x03, 0x03, 0x03, 0x54, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
};
 
struct fbtk_bitmap stop_image_g = {
.width = 26,
.height = 26,
.hot_x = 0,
.hot_y = 0,
.pixdata = stop_image_g_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/throbber0.c
0,0 → 1,52
/* This file is auto-generated from framebuffer/res/throbber/throbber0.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t throbber0_pixdata[] = {
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x18, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x18, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x1a, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x07, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x15, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x18, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x08, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x1a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x2a, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x09, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x1f, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x10,
0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x1f, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x0e,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x08, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x01,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x17, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x28, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x1b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x09, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x05, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x15, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x1b, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x16, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x14, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
};
 
struct fbtk_bitmap throbber0 = {
.width = 24,
.height = 24,
.hot_x = 0,
.hot_y = 0,
.pixdata = throbber0_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/throbber1.c
0,0 → 1,52
/* This file is auto-generated from framebuffer/res/throbber/throbber1.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t throbber1_pixdata[] = {
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x06, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0xcd, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x1c, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1c, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x5a, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x1c, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x0b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x18, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x54, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x0a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x0b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x50, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x41, 0xdf, 0xdf, 0xdf, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x1e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x61, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x19,
0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x61, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x16,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x19, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x02,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x48, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x3e, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x0b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x49, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x12, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x0e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x29, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x4a, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x16, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x06, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x2b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x28, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x05, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
};
 
struct fbtk_bitmap throbber1 = {
.width = 24,
.height = 24,
.hot_x = 0,
.hot_y = 0,
.pixdata = throbber1_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/throbber2.c
0,0 → 1,52
/* This file is auto-generated from framebuffer/res/throbber/throbber2.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t throbber2_pixdata[] = {
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x05, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x0e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x5e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x5e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x50, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x19, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x0e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x0a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x52, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x4b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x22, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x0a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x46, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x31, 0xdf, 0xdf, 0xdf, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x1b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x55, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x13,
0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x55, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x11,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x16, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x3f, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x2e, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x0a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x3e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x0e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x0c, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x3f, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x12, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x05, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x22, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x20, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
};
 
struct fbtk_bitmap throbber2 = {
.width = 24,
.height = 24,
.hot_x = 0,
.hot_y = 0,
.pixdata = throbber2_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/throbber3.c
0,0 → 1,52
/* This file is auto-generated from framebuffer/res/throbber/throbber3.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t throbber3_pixdata[] = {
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x05, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x0d, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x54, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x54, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x45, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x16, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x0d, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x08, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x4a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x40, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0x1f, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x08, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x3c, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xa3, 0xdf, 0xdf, 0xdf, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x17, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x49, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x40,
0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x49, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x38,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x13, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0x04,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x36, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x9b, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x08, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x34, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x0b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x0a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x18, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x35, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0e, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x18, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
};
 
struct fbtk_bitmap throbber3 = {
.width = 24,
.height = 24,
.hot_x = 0,
.hot_y = 0,
.pixdata = throbber3_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/throbber4.c
0,0 → 1,52
/* This file is auto-generated from framebuffer/res/throbber/throbber4.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t throbber4_pixdata[] = {
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x0b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x4b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x4b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x3b, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x14, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x0b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x07, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x41, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x38, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x1b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x07, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x32, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x93, 0xdf, 0xdf, 0xdf, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x13, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0x07,
0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x3e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x39,
0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x3c, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x32,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x10, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x04,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x2d, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x8c, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x06, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x29, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0x24, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x08, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x50, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x2a, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x0b, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x0c, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x56, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0x50, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x0a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
};
 
struct fbtk_bitmap throbber4 = {
.width = 24,
.height = 24,
.hot_x = 0,
.hot_y = 0,
.pixdata = throbber4_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/throbber5.c
0,0 → 1,52
/* This file is auto-generated from framebuffer/res/throbber/throbber5.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t throbber5_pixdata[] = {
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x0a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x42, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x42, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x31, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x11, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x0a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x06, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x39, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x2f, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x18, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x06, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x28, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x83, 0xdf, 0xdf, 0xdf, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x0f, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x06,
0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x31, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x33,
0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x30, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x2d,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x0d, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x03,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x24, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x7c, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x05, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x1f, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x20, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x06, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x48, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1f, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x24, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x0b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x4d, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0x48, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x09, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
};
 
struct fbtk_bitmap throbber5 = {
.width = 24,
.height = 24,
.hot_x = 0,
.hot_y = 0,
.pixdata = throbber5_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/throbber6.c
0,0 → 1,52
/* This file is auto-generated from framebuffer/res/throbber/throbber6.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t throbber6_pixdata[] = {
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x08, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x38, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x38, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x28, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0e, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x08, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x05, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x31, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x25, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x14, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x05, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x1e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x73, 0xdf, 0xdf, 0xdf, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x0b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x06,
0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x25, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x2d,
0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x24, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x27,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x09, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x03,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x1b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x6d, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x10, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0x68, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x1d, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0x14, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x40, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x6a, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x20, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0x0a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x45, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x40, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x08, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2b, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
};
 
struct fbtk_bitmap throbber6 = {
.width = 24,
.height = 24,
.hot_x = 0,
.hot_y = 0,
.pixdata = throbber6_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/throbber7.c
0,0 → 1,52
/* This file is auto-generated from framebuffer/res/throbber/throbber7.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t throbber7_pixdata[] = {
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x07, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x2f, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x2f, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1e, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x0b, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x07, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x29, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x1c, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x11, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x04, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x64, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x62, 0xdf, 0xdf, 0xdf, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x26, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x05,
0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7c, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x26,
0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x21,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x20, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x02,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x5a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x5d, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x0e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x5d, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x19, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x12, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x38, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x5f, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x1d, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x08, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x3c, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x38, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x07, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x26, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
};
 
struct fbtk_bitmap throbber7 = {
.width = 24,
.height = 24,
.hot_x = 0,
.hot_y = 0,
.pixdata = throbber7_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/imgs/throbber8.c
0,0 → 1,52
/* This file is auto-generated from framebuffer/res/throbber/throbber8.png
*
* Do not edit this file directly.
*/
 
#include <sys/types.h>
 
#include <stdint.h>
 
#include <stdbool.h>
 
#include <libnsfb.h>
 
#include "desktop/plot_style.h"
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
 
static uint8_t throbber8_pixdata[] = {
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x06, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x25, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x25, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x64, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x08, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x06, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0x0c, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x21, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0x5e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x0e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x0c, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0x5a, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x51, 0xdf, 0xdf, 0xdf, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x22, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x6f, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x20,
0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x6e, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x1c,
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x1d, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x02,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x51, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x4d, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x0d, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x02, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x53, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x16, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x10, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x30, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x54, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x19, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x07, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x33, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x30, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x06, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x03, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x22, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00, 0xdf, 0xdf, 0xdf, 0x00,
};
 
struct fbtk_bitmap throbber8 = {
.width = 24,
.height = 24,
.hot_x = 0,
.hot_y = 0,
.pixdata = throbber8_pixdata,
};
 
/programs/network/netsurf/netsurf/framebuffer/localhistory.c
0,0 → 1,188
/*
* Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <limits.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
 
#include <libnsfb.h>
#include <libnsfb_plot.h>
#include <libnsfb_event.h>
 
#include "desktop/browser_private.h"
#include "desktop/gui.h"
#include "desktop/plotters.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
#include "utils/log.h"
#include "utils/url.h"
#include "utils/messages.h"
#include "utils/utils.h"
#include "desktop/textinput.h"
#include "render/form.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
#include "framebuffer/framebuffer.h"
#include "framebuffer/schedule.h"
#include "framebuffer/findfile.h"
#include "framebuffer/image_data.h"
#include "framebuffer/font.h"
 
#include "content/urldb.h"
#include "desktop/history_core.h"
#include "content/fetch.h"
 
static int
localhistory_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
struct gui_localhistory *glh = cbi->context;
nsfb_bbox_t rbox;
 
struct redraw_context ctx = {
.interactive = true,
.background_images = true,
.plot = &fb_plotters
};
 
rbox.x0 = fbtk_get_absx(widget);
rbox.y0 = fbtk_get_absy(widget);
 
rbox.x1 = rbox.x0 + fbtk_get_width(widget);
rbox.y1 = rbox.y0 + fbtk_get_height(widget);
 
nsfb_claim(fbtk_get_nsfb(widget), &rbox);
 
nsfb_plot_rectangle_fill(fbtk_get_nsfb(widget), &rbox, 0xffffffff);
 
history_redraw_rectangle(glh->bw->history,
glh->scrollx,
glh->scrolly,
fbtk_get_width(widget) + glh->scrollx,
fbtk_get_height(widget) + glh->scrolly,
0, 0, &ctx);
 
nsfb_update(fbtk_get_nsfb(widget), &rbox);
 
return 0;
}
 
static int
localhistory_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
struct gui_localhistory *glh = cbi->context;
 
if (cbi->event->type != NSFB_EVENT_KEY_UP)
return 0;
 
history_click(glh->bw, glh->bw->history, cbi->x, cbi->y, false);
 
fbtk_set_mapping(glh->window, false);
 
return 1;
}
 
struct gui_localhistory *
fb_create_localhistory(struct browser_window *bw,
fbtk_widget_t *parent,
int furniture_width)
{
LOG(("init local hist.."));
struct gui_localhistory *glh;
LOG(("LH calloc."));
glh = calloc(1, sizeof(struct gui_localhistory));
 
 
if (glh == NULL)
return NULL;
 
glh->bw = bw;
 
LOG(("conatiner.."));
/* container window */
LOG(("fbtk window"));
glh->window = fbtk_create_window(parent, 0, 0, 0, 0, 0);
 
LOG(("hist user"));
glh->history = fbtk_create_user(glh->window, 0, 0, -furniture_width, -furniture_width, glh);
LOG(("hist handlers..."));
 
fbtk_set_handler(glh->history, FBTK_CBT_REDRAW, localhistory_redraw, glh);
fbtk_set_handler(glh->history, FBTK_CBT_CLICK, localhistory_click, glh);
/*
fbtk_set_handler(gw->localhistory, FBTK_CBT_INPUT, fb_browser_window_input, gw);
fbtk_set_handler(gw->localhistory, FBTK_CBT_POINTERMOVE, fb_browser_window_move, bw);
*/
 
/* create horizontal scrollbar */
LOG(("init hor scroll"));
glh->hscroll = fbtk_create_hscroll(glh->window,
0,
fbtk_get_height(glh->window) - furniture_width,
fbtk_get_width(glh->window) - furniture_width,
furniture_width,
FB_SCROLL_COLOUR,
FB_FRAME_COLOUR,
NULL,
NULL);
 
LOG(("init ver scroll"));
glh->vscroll = fbtk_create_vscroll(glh->window,
fbtk_get_width(glh->window) - furniture_width,
0,
furniture_width,
fbtk_get_height(glh->window) - furniture_width,
FB_SCROLL_COLOUR,
FB_FRAME_COLOUR,
NULL,
NULL);
 
LOG(("init fill"));
fbtk_create_fill(glh->window,
fbtk_get_width(glh->window) - furniture_width,
fbtk_get_height(glh->window) - furniture_width,
furniture_width,
furniture_width,
FB_FRAME_COLOUR);
 
LOG(("fine!"));
return glh;
}
 
void
fb_localhistory_map(struct gui_localhistory * glh)
{
fbtk_set_zorder(glh->window, INT_MIN);
fbtk_set_mapping(glh->window, true);
}
/programs/network/netsurf/netsurf/framebuffer/login.c
0,0 → 1,25
/*
* Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include "desktop/401login.h"
 
void gui_401login_open(nsurl *url, const char *realm,
nserror (*cb)(bool proceed, void *pw), void *cbpw)
{
cb(false, cbpw);
}
/programs/network/netsurf/netsurf/framebuffer/make.fb
0,0 → 1,30
 
CFLAGS += -Dnsframebuffer
 
#resource path
CFLAGS += '-DNETSURF_FB_RESPATH="$(NETSURF_FB_RESPATH)"'
CFLAGS += -O2 -DNETSURF_HOMEPAGE=about:blank -DFB_USE_FREETYPE
NETSURF_FB_FRONTEND := sdl
NETSURF_FB_FONTLIB := internal
 
NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
 
# Default resource install path
NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
 
# Default framebuffer search path
NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
 
# freetype compiled in font serch path
NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
OBJS := gui.o framebuffer.o tree.o schedule.o \
thumbnail.o misc.o bitmap.o filetype.o login.o findfile.o \
localhistory.o system_colour.o clipboard.o font_freetype.o \
nsfont_bold.o nsfont_italic_bold.o nsfont_italic.o nsfont_regular.o
 
 
OUTFILE = TEST.o
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include
include $(MENUETDEV)/makefiles/Makefile_for_o_lib
 
/programs/network/netsurf/netsurf/framebuffer/misc.c
0,0 → 1,77
/*
* Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
 
#include "desktop/cookies.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
#include "utils/url.h"
 
void warn_user(const char *warning, const char *detail)
{
LOG(("%s %s", warning, detail));
}
 
void die(const char *error)
{
LOG(("%s", error));
exit(1);
}
 
/**
* Return the filename part of a full path
*
* \param path full path and filename
* \return filename (will be freed with free())
*/
char *filename_from_path(char *path)
{
char *leafname;
 
leafname = strrchr(path, '/');
if (!leafname)
leafname = path;
else
leafname += 1;
 
return strdup(leafname);
}
 
/**
* Add a path component/filename to an existing path
*
* \param path buffer containing path + free space
* \param length length of buffer "path"
* \param newpart string containing path component to add to path
* \return true on success
*/
 
bool path_add_part(char *path, int length, const char *newpart)
{
if(path[strlen(path) - 1] != '/')
strncat(path, "/", length);
 
strncat(path, newpart, length);
 
return true;
}
/programs/network/netsurf/netsurf/framebuffer/nsfont_bold.c
0,0 → 1,556
/*
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright Tim Tyler
* Copyright Michael Drake <tlsa@netsurf-browser.org>
*
* This font is based on the "Default" font with Zap 1.47 [TEST], which
* was created for Zap by Tim Tyler. It was converted to a plain text
* format and many glyphs added for use in the NetSurf project.
*
* Plain text font data:
* http://source.netsurf-browser.org/?p=art.git;a=blob_plain;f=fonts/netsurf/glyph_data;hb=HEAD
*
* Zap: http://zap.tartarus.org/
* NetSurf: http://www.netsurf-browser.org/
*
* Thanks to Tim Tyler for the original font and his permission to use it.
* Thanks to James Aylett for helping track down Tim.
* Thanks to Christian Ludlam for helping with Zap font info.
*
* Please contact Michael Drake if you want to contribute gylphs to
* this font.
*/
 
/* Don't edit this file, it was generated from the plain text source data. */
 
#include "desktop/plotters.h"
#include "utils/utf8.h"
 
#include "framebuffer/font_internal.h"
 
#define FONTDATAMAX 4096
 
static const uint32_t fontdata_bold[FONTDATAMAX] = {
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xE4, 0xAC, 0xA4, 0xA4, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEC, 0xA2, 0xA4, 0xA8, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEC, 0xA2, 0xAC, 0xA2, 0xEC, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEA, 0xAA, 0xAE, 0xA2, 0xE2, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xA8, 0xAE, 0xA2, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xE6, 0xA8, 0xAE, 0xAA, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xA2, 0xA4, 0xA4, 0xE4, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xAA, 0xAE, 0xAA, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xAA, 0xAE, 0xA2, 0xE2, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xE4, 0xAA, 0xAE, 0xAA, 0xEA, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEC, 0xAA, 0xAC, 0xAA, 0xEC, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xE4, 0xAA, 0xA8, 0xAA, 0xE4, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEC, 0xAA, 0xAA, 0xAA, 0xEC, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xA8, 0xAC, 0xA8, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xA8, 0xAC, 0xA8, 0xE8, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xCA, 0x4A, 0x4A, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x44, 0xCC, 0x44, 0x44, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4C, 0xC2, 0x44, 0x48, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4C, 0xC2, 0x4C, 0x42, 0xEC, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4A, 0xCA, 0x4E, 0x42, 0xE2, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xC8, 0x4E, 0x42, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x46, 0xC8, 0x4E, 0x4A, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xC2, 0x44, 0x44, 0xE4, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xCA, 0x4E, 0x4A, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xCA, 0x4E, 0x42, 0xE2, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x44, 0xCA, 0x4E, 0x4A, 0xEA, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4C, 0xCA, 0x4C, 0x4A, 0xEC, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x44, 0xCA, 0x48, 0x4A, 0xE4, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4C, 0xCA, 0x4A, 0x4A, 0xEC, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xC8, 0x4C, 0x48, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xC8, 0x4C, 0x48, 0xE8, 0x00, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
0x1C, 0x00, 0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00,
0x00, 0x00, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x6C, 0x6C, 0xFE, 0xFE, 0xFE, 0x6C, 0x6C,
0xFE, 0xFE, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00,
0x00, 0x10, 0x7C, 0xFE, 0xF6, 0xF0, 0xF8, 0x7C,
0x3E, 0x1E, 0xDE, 0xFE, 0x7C, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xE0, 0xE6, 0xEE, 0x1C,
0x38, 0x70, 0xEE, 0xCE, 0x0E, 0x00, 0x00, 0x00,
0x00, 0x70, 0xF8, 0xF8, 0xF8, 0xF8, 0x76, 0xFE,
0xFE, 0xEC, 0xEE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x06, 0x0C, 0x1C, 0x38, 0x38, 0x70, 0x70, 0x70,
0x70, 0x70, 0x38, 0x38, 0x1C, 0x0C, 0x06, 0x00,
0x60, 0x30, 0x38, 0x1C, 0x1C, 0x0E, 0x0E, 0x0E,
0x0E, 0x0E, 0x1C, 0x1C, 0x38, 0x30, 0x60, 0x00,
0x00, 0x00, 0x00, 0x10, 0x54, 0xFE, 0x7C, 0x38,
0x7C, 0xFE, 0x54, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0xFE,
0xFE, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x78, 0x70, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE,
0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x1E, 0x3C,
0x78, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x38, 0x7C, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0x7C, 0x38, 0x00, 0x00, 0x00,
0x00, 0x18, 0x38, 0x78, 0x78, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0x0E, 0x0E, 0x7E, 0xFC,
0xE0, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0x0E, 0x0E, 0x3C, 0x3C,
0x0E, 0x0E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x04, 0x0C, 0x1C, 0x3C, 0x7C, 0x6C, 0xEC,
0xFE, 0xFE, 0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFE, 0xE0, 0xE0, 0xFC, 0xFE, 0x0E,
0x0E, 0x0E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFC, 0xE0, 0xE0, 0xFC, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFE, 0x0E, 0x0E, 0x1C, 0x1C, 0x1C,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0xEE, 0xFE, 0x7C, 0xFE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0xEE, 0xEE, 0xFE, 0x7E,
0x0E, 0x0E, 0x0E, 0x7C, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x00,
0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x00,
0x00, 0x18, 0x38, 0x38, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x0E, 0x1C, 0x38, 0x70,
0x70, 0x38, 0x1C, 0x0E, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00,
0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x60, 0x70, 0x38, 0x1C, 0x0E,
0x0E, 0x1C, 0x38, 0x70, 0x60, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0x0E, 0x0E, 0x3E, 0x7C,
0x70, 0x00, 0x70, 0x70, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0xEE, 0xEE, 0xFE, 0xFE,
0xEC, 0xE0, 0xE0, 0xFC, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0xEE, 0xEE, 0xEE, 0xFE,
0xFE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0xFC, 0xFE, 0xEE, 0xEE, 0xEE, 0xFC, 0xFC,
0xEE, 0xEE, 0xEE, 0xFE, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0xEE, 0xE0, 0xE0, 0xE0,
0xE0, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0xF8, 0xFC, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFC, 0xF8, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFE, 0xE0, 0xE0, 0xE0, 0xF8, 0xF8,
0xE0, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFE, 0xE0, 0xE0, 0xE0, 0xF8, 0xF8,
0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0xEE, 0xE0, 0xE0, 0xFE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xFE, 0xFE,
0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFE, 0x38, 0x38, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E,
0x0E, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0xE0, 0xE6, 0xEE, 0xFE, 0xFC, 0xF8, 0xF0,
0xF8, 0xFC, 0xFE, 0xEE, 0xE6, 0x00, 0x00, 0x00,
0x00, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
0xE0, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xFE, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0xCE, 0xEE, 0xEE, 0xFE, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xEE, 0xEE, 0xE6, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0xFC, 0xFE, 0xEE, 0xEE, 0xEE, 0xEE, 0xFE,
0xFC, 0xE0, 0xE0, 0xE0, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
0xEE, 0xFE, 0xFE, 0xFE, 0x7E, 0x06, 0x00, 0x00,
0x00, 0xFC, 0xFE, 0xEE, 0xEE, 0xEE, 0xFE, 0xFC,
0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0xE0, 0xE0, 0xFC, 0x7E,
0x0E, 0x0E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFE, 0x38, 0x38, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
0x6C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
0xFE, 0xFE, 0xFE, 0xEE, 0x44, 0x00, 0x00, 0x00,
0x00, 0xEE, 0xEE, 0xEE, 0xEE, 0x7C, 0x38, 0x38,
0x7C, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x7C, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFE, 0x0E, 0x0E, 0x1C, 0x38, 0x38,
0x70, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x3E, 0x38, 0x38, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0x3E, 0x3E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0xE0, 0xF0, 0x78,
0x3C, 0x1E, 0x0E, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFC, 0xFC, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C,
0x1C, 0x1C, 0x1C, 0xFC, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x7C, 0xEE, 0xC6, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x30, 0x38, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0x0E,
0x7E, 0xFE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0xE0, 0xE0, 0xE0, 0xE0, 0xFC, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xFE, 0xEE,
0xE0, 0xE0, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x0E, 0x0E, 0x0E, 0x7E, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xFE, 0xEE,
0xFE, 0xFE, 0xE0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7E, 0x70, 0x70, 0x70, 0xF8, 0xF8,
0x70, 0x70, 0x70, 0x70, 0x70, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x0E, 0x7E, 0x7C,
0x00, 0x00, 0xE0, 0xE0, 0xE0, 0xFC, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x38, 0x00, 0x78, 0x78, 0x38,
0x38, 0x38, 0x38, 0x7C, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1C, 0x1C, 0x00, 0x3C, 0x3C, 0x1C,
0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x7C, 0x78,
0x00, 0xE0, 0xE0, 0xE0, 0xE6, 0xEE, 0xFE, 0xFC,
0xF8, 0xFC, 0xFE, 0xEE, 0xE6, 0x00, 0x00, 0x00,
0x00, 0x78, 0x78, 0x38, 0x38, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xFE,
0xFE, 0xFE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0xFC, 0xE0, 0xE0, 0xE0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x0E, 0x0F, 0x0F,
0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xFE, 0xE0,
0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFE, 0xE0,
0xFC, 0x7E, 0x0E, 0xFE, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x10, 0x30, 0x70, 0x70, 0xFC, 0xFC, 0x70,
0x70, 0x70, 0x70, 0x7E, 0x3E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xEE, 0xEE,
0xFE, 0xFE, 0xFE, 0xEE, 0x44, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xEE, 0xEE,
0x7C, 0x7C, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xFE, 0x7E, 0x0E, 0x0E, 0xFE, 0xFC,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x1E,
0x3C, 0x78, 0xF0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3E, 0x38, 0x38, 0x38, 0xF0, 0xF0,
0x38, 0x38, 0x38, 0x3E, 0x1E, 0x00, 0x00, 0x00,
0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x00,
0x00, 0xF0, 0xF8, 0x38, 0x38, 0x38, 0x1E, 0x1E,
0x38, 0x38, 0x38, 0xF8, 0xF0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x66, 0xFE, 0xFE, 0xCC, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0x28, 0x4C, 0x48, 0x48, 0x00, 0xFE,
0x00, 0x38, 0x7C, 0xEE, 0xE0, 0xFC, 0xE0, 0xF8,
0xE0, 0xE0, 0xEE, 0x7C, 0x38, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x38, 0x18, 0x30, 0x00,
0x00, 0x3E, 0x7E, 0x70, 0x70, 0x70, 0xF8, 0xF8,
0x70, 0x70, 0x70, 0x70, 0x70, 0xF0, 0xE0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xEE, 0xEE, 0x66, 0xCC, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xDB, 0xDB, 0xDB, 0x00, 0x00, 0x00,
0x00, 0x38, 0x38, 0x38, 0x38, 0xFE, 0xFE, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00,
0x00, 0x38, 0x38, 0x38, 0xFE, 0xFE, 0x38, 0xFE,
0xFE, 0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00,
0x00, 0x7C, 0xEE, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xCE, 0x1C,
0x38, 0x70, 0xE0, 0xDB, 0x1B, 0x00, 0x00, 0x00,
0xEE, 0x7C, 0x00, 0x7C, 0xFE, 0xEE, 0xE0, 0xFC,
0x7E, 0x0E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0E, 0x1C,
0x38, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x00, 0x00,
0x00, 0x7F, 0xFF, 0xEE, 0xEE, 0xEE, 0xEF, 0xEF,
0xEE, 0xEE, 0xEE, 0xFF, 0x7F, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0xEE, 0x7C, 0x00, 0xFE, 0xFE, 0x0E, 0x1E, 0x3C,
0x78, 0xF0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x30, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x36, 0x6C, 0x6C, 0x6C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x36, 0x36, 0x36, 0x6C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E,
0x7E, 0x7E, 0x7E, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7B, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xF1, 0xFB, 0x5F, 0x55, 0x51, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xEE, 0x7C, 0x38, 0x00, 0x7E, 0xFE, 0xE0,
0xFC, 0x7E, 0x0E, 0xFE, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x70, 0x38,
0x1C, 0x0E, 0x1C, 0x38, 0x70, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFA,
0xDE, 0xDE, 0xFC, 0xFE, 0x6E, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0xEE, 0x7C, 0x38, 0x00, 0xFE, 0xFE, 0x1E,
0x3C, 0x78, 0xF0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0xEE, 0x00, 0xEE, 0xEE, 0xEE, 0xEE, 0x7C,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x00,
0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x00,
0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0xFE, 0xD6,
0xD0, 0xD0, 0xD6, 0xFE, 0x7C, 0x10, 0x10, 0x00,
0x00, 0x3C, 0x7E, 0x76, 0x70, 0xFC, 0xFC, 0xFC,
0x70, 0x76, 0xFE, 0xFE, 0xDC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xEE, 0xEE, 0x7C, 0xFE,
0xFE, 0xFE, 0xFE, 0x7C, 0xEE, 0xEE, 0x00, 0x00,
0x00, 0x00, 0xEE, 0xEE, 0xEE, 0x7C, 0x38, 0xFE,
0x38, 0xFE, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x38, 0x38, 0x38, 0x00,
0x00, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x3C, 0x7C, 0x7C, 0x70, 0x3C, 0x7E, 0x66,
0x7E, 0x3C, 0x0E, 0x3E, 0x3E, 0x3C, 0x00, 0x00,
0x00, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3C, 0x7E, 0xC3, 0x99, 0xBD, 0xA5, 0xA1,
0xA5, 0xBD, 0x99, 0xC3, 0x7E, 0x3C, 0x00, 0x00,
0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7C, 0x00, 0xFC,
0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E,
0x7C, 0xF8, 0xF8, 0x7C, 0x3E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x06, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3C, 0x7E, 0xC3, 0xB9, 0xBD, 0xA5, 0xB9,
0xB9, 0xA5, 0xA5, 0xC3, 0x7E, 0x3C, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x78, 0xFC, 0xCC, 0xFC, 0x78, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x38, 0xFE, 0xFE, 0xFE, 0x38,
0x38, 0x00, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x00, 0xF0, 0xF8, 0x18, 0x78, 0xF0, 0xC0,
0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xF0, 0xF8, 0x18, 0x30, 0x18, 0xF8,
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x70, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0xFC, 0xE0, 0xE0, 0xC0,
0x00, 0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B,
0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38,
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x1C, 0x0C, 0x1C, 0x18, 0x00, 0x00,
0x00, 0x00, 0x60, 0xE0, 0x60, 0x60, 0x60, 0xF0,
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x70, 0xF8, 0x88, 0xF8, 0x70, 0x00, 0xF8,
0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8,
0x6C, 0x36, 0x36, 0x6C, 0xD8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0xE0, 0x62, 0x66, 0xFE, 0x1C,
0x38, 0x76, 0xEE, 0xD6, 0x3E, 0x3E, 0x06, 0x00,
0x00, 0x00, 0x60, 0xE0, 0x62, 0x66, 0xFE, 0x1C,
0x38, 0x70, 0xFC, 0xC6, 0x0C, 0x18, 0x1E, 0x00,
0x00, 0x00, 0xE0, 0x30, 0x62, 0x36, 0xEE, 0x1C,
0x3A, 0x76, 0xEE, 0xD6, 0x3E, 0x3E, 0x06, 0x00,
0x00, 0x00, 0x1C, 0x1C, 0x1C, 0x00, 0x1C, 0x1C,
0x7C, 0xF8, 0xE0, 0xEE, 0xEE, 0xFE, 0x7C, 0x00,
0x00, 0xE0, 0x70, 0x00, 0x10, 0x38, 0x7C, 0xEE,
0xFE, 0xFE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1C, 0x00, 0x10, 0x38, 0x7C, 0xEE,
0xFE, 0xFE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0xC6, 0x10, 0x38, 0x7C, 0xEE,
0xFE, 0xFE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x76, 0xDC, 0x00, 0x10, 0x38, 0x7C, 0xEE,
0xFE, 0xFE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0xEE, 0xEE, 0x10, 0x38, 0x7C, 0xEE, 0xFE,
0xFE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x38, 0x38, 0x7C, 0xEE, 0xFE,
0xFE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x1F, 0x3F, 0x7F, 0xFE, 0xEE, 0xFF, 0xFF,
0xFE, 0xEE, 0xEF, 0xEF, 0xEF, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0xE0, 0xE0, 0xE0, 0xE0,
0xE0, 0xE0, 0xEE, 0xFE, 0x7C, 0x0E, 0x6E, 0x7C,
0x00, 0x70, 0x38, 0x00, 0xFE, 0xFE, 0xE0, 0xE0,
0xF8, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x38, 0x00, 0xFE, 0xFE, 0xE0, 0xE0,
0xF8, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xEE, 0x00, 0xFE, 0xFE, 0xE0, 0xE0,
0xF8, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0xEE, 0xEE, 0x00, 0xFE, 0xFE, 0xE0, 0xE0, 0xF8,
0xF8, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x70, 0x38, 0x00, 0x38, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x38, 0x00, 0x38, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x38, 0x38, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0xEE, 0xEE, 0x00, 0x38, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0xF8, 0xFC, 0xEE, 0xEE, 0xEE, 0xFE,
0xEE, 0xEE, 0xEE, 0xFC, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x76, 0xDC, 0x00, 0xEE, 0xEE, 0xEE, 0xF6,
0xFE, 0xDE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x70, 0x38, 0x00, 0x7C, 0xFE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x38, 0x00, 0x7C, 0xFE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xEE, 0x00, 0x7C, 0xFE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x76, 0xDC, 0x00, 0x7C, 0xFE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0xEE, 0xEE, 0x00, 0x7C, 0xFE, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xEE, 0x7C,
0x38, 0x38, 0x7C, 0xEE, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x7A, 0xFC, 0xEE, 0xEE, 0xEE, 0xFE, 0xFE,
0xFE, 0xEE, 0xEE, 0xFE, 0x7C, 0x80, 0x00, 0x00,
0x00, 0x70, 0x38, 0x00, 0xEE, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x38, 0x00, 0xEE, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xEE, 0x00, 0xEE, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0xEE, 0xEE, 0x00, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x38, 0x00, 0xEE, 0xEE, 0xEE, 0xEE,
0x7C, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0xE0, 0xE0, 0xFC, 0xFE, 0xEE, 0xEE,
0xEE, 0xFE, 0xFC, 0xE0, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xEE, 0xEE, 0xEE, 0xFE, 0xFC,
0xEE, 0xEE, 0xEE, 0xFE, 0xFC, 0xE0, 0xC0, 0x00,
0x00, 0x00, 0x70, 0x38, 0x00, 0x7C, 0x7E, 0x0E,
0x7E, 0xFE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1C, 0x38, 0x00, 0x7C, 0x7E, 0x0E,
0x7E, 0xFE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x38, 0x7C, 0xEE, 0x00, 0x7C, 0x7E, 0x0E,
0x7E, 0xFE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x76, 0xDC, 0x00, 0x7C, 0x7E, 0x0E,
0x7E, 0xFE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0xEE, 0xEE, 0x00, 0x7C, 0x7E, 0x0E,
0x7E, 0xFE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x38, 0x00, 0x7C, 0x7E, 0x0E,
0x7E, 0xFE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x74, 0x7E, 0x7E, 0x1A,
0x7E, 0xFE, 0xD8, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xFE,
0xEE, 0xE0, 0xEE, 0xFE, 0x7C, 0x1C, 0x7E, 0x7C,
0x00, 0x00, 0x70, 0x38, 0x00, 0x7C, 0xFE, 0xEE,
0xFE, 0xFE, 0xE0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x70, 0x00, 0x7C, 0xFE, 0xEE,
0xFE, 0xFE, 0xE0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x38, 0x7C, 0xEE, 0x00, 0x7C, 0xFE, 0xEE,
0xFE, 0xFE, 0xE0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0xEE, 0xEE, 0x00, 0x7C, 0xFE, 0xEE,
0xFE, 0xFE, 0xE0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x70, 0x38, 0x00, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1C, 0x38, 0x00, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x38, 0x7C, 0xEE, 0x00, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0xEE, 0xEE, 0x00, 0x38, 0x38, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0xEC, 0x7C, 0xF8, 0xFC, 0x7E, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x76, 0xFE, 0xDC, 0x00, 0xFC, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x00, 0xE0, 0x70, 0x00, 0x7C, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x70, 0x00, 0x7C, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x38, 0x7C, 0xEE, 0x00, 0x7C, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x76, 0xFE, 0xDC, 0x00, 0x7C, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0xEE, 0xEE, 0x00, 0x7C, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0xFE,
0xFE, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x7C, 0xFE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x80, 0x00, 0x00,
0x00, 0x00, 0xE0, 0x70, 0x00, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x70, 0x00, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x38, 0x7C, 0xEE, 0x00, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0xEE, 0xEE, 0x00, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1C, 0x38, 0x00, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x0E, 0xFE, 0xFC,
0x00, 0x00, 0xE0, 0xE0, 0xFC, 0xFE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xEE, 0xFE, 0xFC, 0xE0, 0xE0,
0x00, 0x00, 0xEE, 0xEE, 0x00, 0xEE, 0xEE, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x0E, 0xFE, 0xFC,
};
 
const struct fb_font_desc font_bold = {
.name = "NetSurf Bold",
.width = 8,
.height = 16,
.encoding = "CP1252",
.data = fontdata_bold,
};
/programs/network/netsurf/netsurf/framebuffer/nsfont_italic.c
0,0 → 1,556
/*
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright Tim Tyler
* Copyright Michael Drake <tlsa@netsurf-browser.org>
*
* This font is based on the "Default" font with Zap 1.47 [TEST], which
* was created for Zap by Tim Tyler. It was converted to a plain text
* format and many glyphs added for use in the NetSurf project.
*
* Plain text font data:
* http://source.netsurf-browser.org/?p=art.git;a=blob_plain;f=fonts/netsurf/glyph_data;hb=HEAD
*
* Zap: http://zap.tartarus.org/
* NetSurf: http://www.netsurf-browser.org/
*
* Thanks to Tim Tyler for the original font and his permission to use it.
* Thanks to James Aylett for helping track down Tim.
* Thanks to Christian Ludlam for helping with Zap font info.
*
* Please contact Michael Drake if you want to contribute gylphs to
* this font.
*/
 
/* Don't edit this file, it was generated from the plain text source data. */
 
#include "desktop/plotters.h"
#include "utils/utf8.h"
 
#include "framebuffer/font_internal.h"
 
#define FONTDATAMAX 4096
 
static const uint32_t fontdata_italic[FONTDATAMAX] = {
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xE4, 0xAC, 0xA4, 0xA4, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEC, 0xA2, 0xA4, 0xA8, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEC, 0xA2, 0xAC, 0xA2, 0xEC, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEA, 0xAA, 0xAE, 0xA2, 0xE2, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xA8, 0xAE, 0xA2, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xE6, 0xA8, 0xAE, 0xAA, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xA2, 0xA4, 0xA4, 0xE4, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xAA, 0xAE, 0xAA, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xAA, 0xAE, 0xA2, 0xE2, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xE4, 0xAA, 0xAE, 0xAA, 0xEA, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEC, 0xAA, 0xAC, 0xAA, 0xEC, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xE4, 0xAA, 0xA8, 0xAA, 0xE4, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEC, 0xAA, 0xAA, 0xAA, 0xEC, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xA8, 0xAC, 0xA8, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xA8, 0xAC, 0xA8, 0xE8, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xCA, 0x4A, 0x4A, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x44, 0xCC, 0x44, 0x44, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4C, 0xC2, 0x44, 0x48, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4C, 0xC2, 0x4C, 0x42, 0xEC, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4A, 0xCA, 0x4E, 0x42, 0xE2, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xC8, 0x4E, 0x42, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x46, 0xC8, 0x4E, 0x4A, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xC2, 0x44, 0x44, 0xE4, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xCA, 0x4E, 0x4A, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xCA, 0x4E, 0x42, 0xE2, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x44, 0xCA, 0x4E, 0x4A, 0xEA, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4C, 0xCA, 0x4C, 0x4A, 0xEC, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x44, 0xCA, 0x48, 0x4A, 0xE4, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4C, 0xCA, 0x4A, 0x4A, 0xEC, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xC8, 0x4C, 0x48, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xC8, 0x4C, 0x48, 0xE8, 0x00, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x06, 0x06, 0x06, 0x06, 0x0C, 0x0C, 0x0C,
0x0C, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1B, 0x1B, 0x36, 0x36, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1B, 0x1B, 0x1B, 0x7F, 0x7F, 0x36, 0x36,
0xFF, 0xFF, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00,
0x00, 0x04, 0x3E, 0x7F, 0x6B, 0x68, 0x78, 0x3C,
0x1E, 0x16, 0xD6, 0xFE, 0x7C, 0x20, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xCE, 0x1C,
0x38, 0x70, 0xE6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x3E, 0x36, 0x36, 0x3C, 0x39, 0x7F,
0x6E, 0xCC, 0xCC, 0xFE, 0x7A, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x06, 0x0C, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x06, 0x0E, 0x1C, 0x38, 0x30, 0x60, 0x60, 0xC0,
0xC0, 0xC0, 0xC0, 0xC0, 0xE0, 0x70, 0x30, 0x00,
0x18, 0x1C, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06,
0x0C, 0x0C, 0x18, 0x38, 0x70, 0xE0, 0xC0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x1C, 0x7F,
0xFE, 0x38, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E,
0xFC, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x38, 0x70, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFC,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0E, 0x1C,
0x38, 0x70, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x33, 0x67, 0x6E, 0x76,
0xE6, 0xCC, 0xCC, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x06, 0x0E, 0x1E, 0x3C, 0x0C, 0x0C, 0x18,
0x18, 0x18, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x03, 0x07, 0x1E, 0x7C,
0x60, 0xC0, 0xC0, 0xFC, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x03, 0x06, 0x1E, 0x1E,
0x06, 0x06, 0xCC, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x01, 0x03, 0x07, 0x0F, 0x1E, 0x36, 0x7F,
0x7F, 0x0C, 0x0C, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x1F, 0x1F, 0x30, 0x30, 0x7C, 0x7E, 0x06,
0x06, 0x06, 0xCE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x0F, 0x1F, 0x38, 0x30, 0x60, 0x7C, 0x7E,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x3F, 0x7F, 0x63, 0x03, 0x06, 0x06, 0x0C,
0x0C, 0x18, 0x18, 0x30, 0x30, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x33, 0x33, 0x1E, 0x7C,
0x66, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x63, 0x63, 0x7E, 0x3E,
0x06, 0x0C, 0x1C, 0xF8, 0xF0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00,
0x00, 0x00, 0x18, 0x38, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x0E, 0x1C, 0x38, 0x70, 0x70,
0x70, 0x38, 0x1C, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3E, 0x7C, 0x00, 0x00,
0x7C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x0C, 0x0C, 0x06, 0x0E,
0x1C, 0x38, 0x70, 0x60, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x33, 0x03, 0x07, 0x0E,
0x1C, 0x18, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x63, 0x6F, 0x6B, 0x6B,
0xCF, 0xCE, 0xC0, 0xFC, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x33, 0x66, 0x7E, 0x7E,
0x66, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x3F, 0x33, 0x63, 0x63, 0x7E, 0x7C,
0x66, 0xC6, 0xC6, 0xFE, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x30, 0x60, 0x60, 0x60,
0x60, 0xC0, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x3F, 0x33, 0x63, 0x63, 0x63, 0x63,
0xC3, 0xC6, 0xCE, 0xFC, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x3F, 0x3F, 0x30, 0x30, 0x60, 0x7C, 0x7C,
0x60, 0xC0, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x3F, 0x3F, 0x30, 0x30, 0x60, 0x7C, 0x7C,
0x60, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x30, 0x60, 0x60, 0x6E,
0x6E, 0xC6, 0xCE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x33, 0x33, 0x33, 0x63, 0x66, 0x7E, 0x7E,
0xC6, 0xC6, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00,
0x00, 0x3F, 0x3F, 0x0C, 0x0C, 0x18, 0x18, 0x18,
0x18, 0x30, 0x30, 0xFC, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x03, 0x03, 0x03, 0x03, 0x06, 0x06, 0x06,
0x06, 0x0C, 0xCC, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x30, 0x30, 0x33, 0x36, 0x7C, 0x78, 0x70,
0x78, 0xF8, 0xDC, 0xCE, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x30, 0x30, 0x30, 0x30, 0x60, 0x60, 0x60,
0x60, 0xC0, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x33, 0x33, 0x3F, 0x3F, 0x7F, 0x6B, 0x66,
0x66, 0xC6, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00,
0x00, 0x33, 0x33, 0x3B, 0x3B, 0x7B, 0x7E, 0x6E,
0x6E, 0xCE, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x33, 0x63, 0x66, 0x66,
0xC6, 0xCC, 0xCC, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x3F, 0x33, 0x33, 0x67, 0x7E, 0x7C,
0x60, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x33, 0x63, 0x66, 0x66,
0xC6, 0xF6, 0xDC, 0xF8, 0x7C, 0x0C, 0x00, 0x00,
0x00, 0x3E, 0x3F, 0x33, 0x33, 0x63, 0x7E, 0x7C,
0x6E, 0xC6, 0xC6, 0xCC, 0xCC, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x60, 0x60, 0x7C, 0x3E,
0x06, 0x06, 0xCE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x7F, 0x7F, 0x18, 0x18, 0x30, 0x30, 0x30,
0x30, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00,
0x00, 0x33, 0x33, 0x33, 0x33, 0x63, 0x66, 0x66,
0x66, 0xC6, 0xCC, 0xFC, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x33, 0x33, 0x33, 0x33, 0x63, 0x63, 0x66,
0x66, 0x6C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x33, 0x33, 0x33, 0x33, 0x63, 0x63, 0x6B,
0x6B, 0xFE, 0xFE, 0xEE, 0x44, 0x00, 0x00, 0x00,
0x00, 0x63, 0x63, 0x63, 0x77, 0x3E, 0x1C, 0x38,
0x7C, 0xEE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x18,
0x18, 0x30, 0x30, 0x60, 0x60, 0x00, 0x00, 0x00,
0x00, 0x7F, 0x7F, 0x03, 0x07, 0x0E, 0x0C, 0x18,
0x38, 0x70, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x0F, 0x0F, 0x0C, 0x0C, 0x18, 0x18, 0x18,
0x18, 0x30, 0x30, 0x3E, 0x3E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0x70,
0x38, 0x1C, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1F, 0x1F, 0x03, 0x03, 0x06, 0x06, 0x06,
0x06, 0x0C, 0x0C, 0x7C, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x04, 0x0E, 0x1F, 0x3B, 0x63, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00,
0x00, 0x00, 0x00, 0x0C, 0x0E, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3E, 0x06,
0x7E, 0xFC, 0xCC, 0xFC, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x18, 0x18, 0x30, 0x30, 0x3E, 0x7F, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66,
0xC0, 0xC0, 0xCC, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x03, 0x03, 0x03, 0x06, 0x3E, 0x7E, 0x66,
0xC6, 0xCC, 0xCC, 0xFC, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66,
0xFE, 0xFC, 0xC0, 0xFC, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x07, 0x0F, 0x0C, 0x18, 0x7E, 0x7E, 0x30,
0x30, 0x30, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7F, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7E, 0x0C, 0xFC, 0xF8,
0x00, 0x00, 0x30, 0x30, 0x30, 0x6E, 0x7F, 0x73,
0x63, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x06, 0x00, 0x1C, 0x3C, 0x0C,
0x0C, 0x18, 0x18, 0x7C, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x03, 0x00, 0x0E, 0x1E, 0x06,
0x06, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0xF8, 0xF0,
0x00, 0x30, 0x30, 0x30, 0x33, 0x67, 0x6E, 0x7C,
0x7C, 0xDC, 0xCE, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x0E, 0x06, 0x06, 0x0C, 0x0C, 0x0C,
0x0C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x7F, 0x7F,
0x6B, 0xD6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x7E, 0x76,
0x66, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66,
0x66, 0xCC, 0xCC, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x3F, 0x33,
0x63, 0x66, 0x66, 0xFE, 0xFC, 0xC0, 0xC0, 0xC0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7F, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7C, 0x0C, 0x0E, 0x0E,
0x00, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x70,
0x60, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7F, 0x60,
0x7C, 0x3E, 0x06, 0xFE, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x06, 0x06, 0x0C, 0x0C, 0x3F, 0x3F, 0x18,
0x18, 0x30, 0x30, 0x3E, 0x1C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x66,
0x66, 0x66, 0xCC, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
0xCC, 0xCC, 0xF8, 0x70, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63,
0x6B, 0xDE, 0xFE, 0xFE, 0x6C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x77,
0x3E, 0x7C, 0xEE, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7E, 0x0C, 0xFC, 0xF8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x07,
0x1E, 0x78, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x07, 0x0E, 0x0C, 0x0C, 0x18, 0x70, 0x70,
0x18, 0x18, 0x30, 0x38, 0x1C, 0x00, 0x00, 0x00,
0x06, 0x06, 0x06, 0x06, 0x0C, 0x0C, 0x0C, 0x0C,
0x18, 0x18, 0x18, 0x18, 0x30, 0x30, 0x30, 0x00,
0x00, 0x38, 0x1C, 0x0C, 0x18, 0x18, 0x0E, 0x0E,
0x18, 0x30, 0x30, 0x70, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1D, 0x3F, 0x37, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0x28, 0x4C, 0x48, 0x48, 0x00, 0xFE,
0x00, 0x06, 0x0F, 0x1B, 0x18, 0x7E, 0x30, 0x7C,
0x60, 0x60, 0x6C, 0x3C, 0x30, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0x10, 0x20, 0x00,
0x00, 0x07, 0x0F, 0x0C, 0x18, 0x7E, 0x7E, 0x30,
0x30, 0x30, 0x60, 0x60, 0x60, 0xC0, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x66, 0x66, 0x44, 0x88, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xDB, 0xDB, 0x00, 0x00, 0x00,
0x00, 0x06, 0x06, 0x06, 0x1F, 0x3F, 0x0C, 0x0C,
0x0C, 0x18, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00,
0x00, 0x06, 0x06, 0x06, 0x1F, 0x3F, 0x0C, 0x3F,
0x3F, 0x18, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00,
0x00, 0x3E, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x63, 0x06,
0x0C, 0x30, 0x60, 0xDB, 0x9B, 0x00, 0x00, 0x00,
0x63, 0x3E, 0x00, 0x1E, 0x3F, 0x33, 0x60, 0x7C,
0x3E, 0x06, 0xCE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0E,
0x1C, 0x30, 0x38, 0x1C, 0x0C, 0x00, 0x00, 0x00,
0x00, 0x1F, 0x3F, 0x33, 0x33, 0x66, 0x67, 0x67,
0x66, 0xCC, 0xCC, 0xFF, 0x7F, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x63, 0x3E, 0x00, 0x7F, 0x7F, 0x03, 0x07, 0x0E,
0x18, 0x70, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x08, 0x10, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0C, 0x04, 0x08, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x09, 0x12, 0x1B, 0x36, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1B, 0x1B, 0x09, 0x12, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x3F,
0x3F, 0x7E, 0x7E, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x19, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFB, 0xFF, 0x55, 0xA2, 0xA2, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x63, 0x36, 0x1C, 0x00, 0x3F, 0x7F, 0x60,
0x7C, 0x3E, 0x06, 0xFE, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1C,
0x0E, 0x0C, 0x1C, 0x38, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x7F, 0x6D,
0x6F, 0xDE, 0xD8, 0xFE, 0x6E, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x63, 0x36, 0x1C, 0x00, 0x7F, 0x7F, 0x07,
0x1E, 0x78, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x33, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x3C,
0x18, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00,
0x0C, 0x18, 0x18, 0x18, 0x18, 0x30, 0x30, 0x00,
0x00, 0x00, 0x00, 0x04, 0x04, 0x3E, 0x7F, 0x6B,
0x68, 0xD0, 0xD6, 0xFE, 0x7C, 0x20, 0x20, 0x00,
0x00, 0x0F, 0x1F, 0x19, 0x18, 0x30, 0x7C, 0x7C,
0x30, 0x60, 0xE6, 0xFE, 0xDC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x19, 0x33, 0x1E, 0x3F,
0x33, 0x66, 0x7E, 0x3C, 0x66, 0xCC, 0x00, 0x00,
0x00, 0x00, 0x19, 0x19, 0x19, 0x1E, 0x0C, 0x3F,
0x0C, 0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x06, 0x0C, 0x0C, 0x00,
0x00, 0x18, 0x18, 0x30, 0x30, 0x00, 0x00, 0x00,
0x00, 0x07, 0x0E, 0x18, 0x18, 0x3C, 0x7E, 0x66,
0x7E, 0x3C, 0x18, 0x18, 0x70, 0xE0, 0x00, 0x00,
0x00, 0x00, 0x33, 0x66, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1F, 0x21, 0x21, 0x4D, 0x51, 0x51,
0x91, 0xA1, 0x9A, 0x82, 0x7C, 0x38, 0x00, 0x00,
0x00, 0x1C, 0x02, 0x1E, 0x22, 0x3C, 0x00, 0x7C,
0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B,
0x36, 0xD8, 0xD8, 0x6C, 0x36, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1E, 0x3E, 0x06, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1F, 0x21, 0x49, 0x55, 0x55, 0x59,
0x99, 0xA5, 0xA5, 0x82, 0x7E, 0x78, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x3F, 0x3C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x06, 0x3F, 0x3F, 0x0C,
0x0C, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3C, 0x3E, 0x06, 0x3C, 0x78, 0x60,
0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3C, 0x3E, 0x06, 0x18, 0x0C, 0x7C,
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x0C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33,
0x33, 0x66, 0x66, 0x7E, 0x7C, 0xC0, 0xC0, 0x80,
0x00, 0x00, 0x00, 0x3F, 0x6F, 0xDB, 0xDB, 0x7B,
0x1B, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C,
0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x1C, 0x0C, 0x1C, 0x30, 0x00, 0x00,
0x00, 0x00, 0x18, 0x38, 0x18, 0x30, 0x30, 0x78,
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x1E, 0x22, 0x3C, 0x18, 0x00, 0x3C,
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C,
0x36, 0x36, 0x36, 0x6C, 0xD8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0x30, 0x10, 0x23, 0x76, 0x0C,
0x18, 0x64, 0xCC, 0x94, 0x3E, 0x08, 0x08, 0x00,
0x00, 0x00, 0x10, 0x30, 0x10, 0x23, 0x76, 0x0C,
0x18, 0x60, 0xDC, 0x82, 0x1C, 0x20, 0x3C, 0x00,
0x00, 0x00, 0x38, 0x04, 0x18, 0x0B, 0x76, 0x0C,
0x18, 0x64, 0xCC, 0x96, 0x3E, 0x08, 0x08, 0x00,
0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C,
0x3C, 0x70, 0xC0, 0xC6, 0xC6, 0xFC, 0x78, 0x00,
0x00, 0x18, 0x0C, 0x00, 0x04, 0x1C, 0x36, 0x63,
0x7F, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x03, 0x06, 0x00, 0x04, 0x1C, 0x36, 0x63,
0x7F, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1B, 0x11, 0x04, 0x1C, 0x36, 0x63,
0x7F, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x1D, 0x37, 0x00, 0x04, 0x1C, 0x36, 0x63,
0x7F, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x1B, 0x1B, 0x04, 0x0E, 0x36, 0x63, 0x7F,
0x7F, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x11, 0x0E, 0x0E, 0x36, 0x63, 0x7F,
0x7F, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x07, 0x0F, 0x1F, 0x3B, 0x66, 0x7F, 0x7F,
0x66, 0xCC, 0xCC, 0xCF, 0xCF, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x33, 0x30, 0x60, 0x60, 0x60,
0x60, 0xC0, 0xC6, 0xFE, 0x7C, 0x1C, 0xCC, 0x78,
0x00, 0x0C, 0x06, 0x00, 0x3F, 0x7F, 0x60, 0x78,
0x78, 0xC0, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x03, 0x06, 0x00, 0x3F, 0x7F, 0x60, 0x78,
0x78, 0xC0, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1B, 0x00, 0x3F, 0x7F, 0x60, 0x78,
0x78, 0xC0, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x1B, 0x1B, 0x00, 0x3F, 0x3F, 0x60, 0x60, 0x78,
0x78, 0xC0, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x06, 0x00, 0x1F, 0x1F, 0x0C, 0x0C,
0x0C, 0x18, 0x18, 0x7C, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x03, 0x06, 0x00, 0x1F, 0x1F, 0x0C, 0x0C,
0x0C, 0x18, 0x18, 0x7C, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x06, 0x09, 0x1F, 0x1F, 0x0C, 0x0C, 0x0C,
0x0C, 0x18, 0x18, 0x7C, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x1B, 0x1B, 0x00, 0x1F, 0x1F, 0x0C, 0x0C,
0x0C, 0x18, 0x18, 0x7C, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1E, 0x1F, 0x1B, 0x33, 0x33, 0x7B,
0x33, 0x66, 0x6E, 0x7C, 0x78, 0x00, 0x00, 0x00,
0x00, 0x1D, 0x37, 0x00, 0x31, 0x63, 0x73, 0x7B,
0x7F, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x06, 0x00, 0x3E, 0x7F, 0x63, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x03, 0x06, 0x00, 0x3E, 0x7F, 0x63, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1B, 0x00, 0x3E, 0x7F, 0x63, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x1D, 0x37, 0x00, 0x3E, 0x7F, 0x63, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x1B, 0x1B, 0x00, 0x3E, 0x7F, 0x63, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x77, 0x3E,
0x1C, 0x38, 0x7C, 0xEE, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x1D, 0x3E, 0x37, 0x6B, 0x6B, 0x6B, 0xD6,
0xD6, 0xD6, 0xEE, 0x7C, 0xB8, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x06, 0x00, 0x33, 0x33, 0x63, 0x66,
0x66, 0xC6, 0xCE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x03, 0x06, 0x00, 0x33, 0x33, 0x63, 0x66,
0x66, 0xC6, 0xCE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1B, 0x00, 0x33, 0x33, 0x63, 0x66,
0x66, 0xC6, 0xCE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x1B, 0x1B, 0x00, 0x33, 0x33, 0x63, 0x63, 0x63,
0x66, 0xC6, 0xCE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x06, 0x0C, 0x00, 0x33, 0x33, 0x66, 0x6E,
0x7C, 0x38, 0x30, 0x60, 0x60, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x1F, 0x3F, 0x33, 0x33,
0x3F, 0x7C, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1F, 0x1B, 0x1B, 0x33, 0x3F, 0x3E,
0x33, 0x66, 0x66, 0x7E, 0x7C, 0xC0, 0x80, 0x00,
0x00, 0x00, 0x0C, 0x06, 0x00, 0x3F, 0x7F, 0x63,
0x63, 0xCE, 0xCE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x0C, 0x00, 0x3F, 0x7F, 0x63,
0x63, 0xC6, 0xCE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x04, 0x0E, 0x1B, 0x00, 0x3F, 0x7F, 0x63,
0x63, 0xC6, 0xCE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1D, 0x37, 0x00, 0x3F, 0x7F, 0x63,
0x63, 0xC6, 0xCE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1B, 0x1B, 0x00, 0x3F, 0x7F, 0x63,
0x63, 0xC6, 0xCE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1B, 0x0E, 0x00, 0x3E, 0x7F, 0x63,
0x63, 0xC6, 0xCE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x3F, 0x0D,
0x1F, 0x7E, 0xD8, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7F,
0x63, 0xC0, 0xC6, 0xFE, 0x7C, 0x30, 0xF8, 0xF0,
0x00, 0x00, 0x0C, 0x06, 0x00, 0x3E, 0x7F, 0x63,
0x7F, 0xFE, 0xC0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x0C, 0x00, 0x3E, 0x7F, 0x63,
0x7F, 0xFE, 0xC0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x04, 0x0E, 0x1B, 0x00, 0x3E, 0x7F, 0x63,
0x7F, 0xFE, 0xC0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1B, 0x1B, 0x00, 0x3E, 0x7F, 0x63,
0x7F, 0xFE, 0xC0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0C, 0x06, 0x00, 0x0C, 0x0C, 0x0C,
0x0C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x06, 0x00, 0x0C, 0x0C, 0x0C,
0x0C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x06, 0x0F, 0x19, 0x00, 0x0C, 0x0C, 0x0C,
0x0C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1B, 0x1B, 0x00, 0x0C, 0x0C, 0x0C,
0x0C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x1B, 0x1F, 0x3E, 0x37, 0x3E, 0x7F, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x1D, 0x3F, 0x37, 0x00, 0x7E, 0x7F, 0x63,
0x63, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x0C, 0x00, 0x3E, 0x7F, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x0C, 0x00, 0x3E, 0x7F, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x04, 0x0E, 0x1B, 0x00, 0x3E, 0x7F, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x1D, 0x3F, 0x37, 0x00, 0x3E, 0x7F, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1B, 0x1B, 0x00, 0x3E, 0x7F, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x3F,
0x7E, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7F, 0x67,
0x6B, 0xD6, 0xE6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x0C, 0x00, 0x63, 0x63, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x0C, 0x00, 0x63, 0x63, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x04, 0x0E, 0x1B, 0x00, 0x63, 0x63, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1B, 0x1B, 0x00, 0x63, 0x63, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x06, 0x00, 0x63, 0x63, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7E, 0x0C, 0xF8, 0xF0,
0x00, 0x00, 0x18, 0x18, 0x18, 0x3E, 0x3F, 0x33,
0x33, 0x66, 0x66, 0x7E, 0x7C, 0xC0, 0xC0, 0xC0,
0x00, 0x00, 0x00, 0x1B, 0x00, 0x63, 0x63, 0x63,
0x63, 0xC6, 0xC6, 0xFE, 0x7E, 0x0C, 0xF8, 0xF0,
};
 
const struct fb_font_desc font_italic = {
.name = "NetSurf Italic",
.width = 8,
.height = 16,
.encoding = "CP1252",
.data = fontdata_italic,
};
/programs/network/netsurf/netsurf/framebuffer/nsfont_italic_bold.c
0,0 → 1,556
/*
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright Tim Tyler
* Copyright Michael Drake <tlsa@netsurf-browser.org>
*
* This font is based on the "Default" font with Zap 1.47 [TEST], which
* was created for Zap by Tim Tyler. It was converted to a plain text
* format and many glyphs added for use in the NetSurf project.
*
* Plain text font data:
* http://source.netsurf-browser.org/?p=art.git;a=blob_plain;f=fonts/netsurf/glyph_data;hb=HEAD
*
* Zap: http://zap.tartarus.org/
* NetSurf: http://www.netsurf-browser.org/
*
* Thanks to Tim Tyler for the original font and his permission to use it.
* Thanks to James Aylett for helping track down Tim.
* Thanks to Christian Ludlam for helping with Zap font info.
*
* Please contact Michael Drake if you want to contribute gylphs to
* this font.
*/
 
/* Don't edit this file, it was generated from the plain text source data. */
 
#include "desktop/plotters.h"
#include "utils/utf8.h"
 
#include "framebuffer/font_internal.h"
 
#define FONTDATAMAX 4096
 
static const uint32_t fontdata_italic_bold[FONTDATAMAX] = {
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xE4, 0xAC, 0xA4, 0xA4, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEC, 0xA2, 0xA4, 0xA8, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEC, 0xA2, 0xAC, 0xA2, 0xEC, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEA, 0xAA, 0xAE, 0xA2, 0xE2, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xA8, 0xAE, 0xA2, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xE6, 0xA8, 0xAE, 0xAA, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xA2, 0xA4, 0xA4, 0xE4, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xAA, 0xAE, 0xAA, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xAA, 0xAE, 0xA2, 0xE2, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xE4, 0xAA, 0xAE, 0xAA, 0xEA, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEC, 0xAA, 0xAC, 0xAA, 0xEC, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xE4, 0xAA, 0xA8, 0xAA, 0xE4, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEC, 0xAA, 0xAA, 0xAA, 0xEC, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xA8, 0xAC, 0xA8, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0xA8, 0xAC, 0xA8, 0xE8, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xCA, 0x4A, 0x4A, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x44, 0xCC, 0x44, 0x44, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4C, 0xC2, 0x44, 0x48, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4C, 0xC2, 0x4C, 0x42, 0xEC, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4A, 0xCA, 0x4E, 0x42, 0xE2, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xC8, 0x4E, 0x42, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x46, 0xC8, 0x4E, 0x4A, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xC2, 0x44, 0x44, 0xE4, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xCA, 0x4E, 0x4A, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xCA, 0x4E, 0x42, 0xE2, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x44, 0xCA, 0x4E, 0x4A, 0xEA, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4C, 0xCA, 0x4C, 0x4A, 0xEC, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x44, 0xCA, 0x48, 0x4A, 0xE4, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4C, 0xCA, 0x4A, 0x4A, 0xEC, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xC8, 0x4C, 0x48, 0xEE, 0x00, 0xFE,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0x4E, 0xC8, 0x4C, 0x48, 0xE8, 0x00, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x0E, 0x0E, 0x0E, 0x1C, 0x1C, 0x1C,
0x1C, 0x00, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x77, 0x77, 0x77, 0x77, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x36, 0x36, 0x7F, 0x7F, 0x7F, 0x36, 0x6C,
0xFE, 0xFE, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00,
0x00, 0x08, 0x3E, 0x7F, 0x7B, 0x78, 0x7C, 0x7C,
0x3E, 0x1E, 0xDE, 0xFE, 0x7C, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x70, 0x73, 0x77, 0x0E,
0x3C, 0x70, 0xEE, 0xCE, 0x0E, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x3E, 0x7E, 0x7C, 0x7C, 0x3B, 0xFE,
0xFE, 0xEC, 0xEE, 0xFE, 0x74, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x06, 0x0E, 0x1C, 0x1C, 0x38, 0x38, 0x70,
0x70, 0x70, 0x38, 0x38, 0x1C, 0x0C, 0x06, 0x00,
0x60, 0x30, 0x38, 0x1C, 0x1C, 0x0E, 0x0E, 0x0E,
0x1C, 0x1C, 0x38, 0x38, 0x70, 0x60, 0xC0, 0x00,
0x00, 0x00, 0x00, 0x08, 0x2A, 0x7F, 0x3E, 0x18,
0x7C, 0xFE, 0x54, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x7E,
0x7E, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x78, 0x70, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE,
0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x3C,
0x78, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x3E, 0x77, 0x77, 0x77, 0x77, 0xEE,
0xEE, 0xEE, 0xEE, 0x7C, 0x38, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x1C, 0x3C, 0x3C, 0x1C, 0x1C, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x07, 0x07, 0x3E, 0x7C,
0xE0, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x07, 0x07, 0x1E, 0x3C,
0x0E, 0x0E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0x76, 0xEC,
0xFE, 0xFE, 0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00,
0x00, 0x7F, 0x7F, 0x70, 0x70, 0x7C, 0x7E, 0x0E,
0x0E, 0x0E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7E, 0x70, 0x70, 0x7C, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x7F, 0x7F, 0x07, 0x07, 0x0E, 0x0E, 0x1C,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x77, 0x7F, 0x3E, 0x7E,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x77, 0x77, 0x7F, 0x3E,
0x0E, 0x0E, 0x0E, 0x7C, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00,
0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00,
0x00, 0x18, 0x38, 0x38, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x07, 0x0E, 0x1C, 0x70,
0x70, 0x38, 0x1C, 0x0E, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x00,
0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0x38, 0x1C, 0x0E, 0x0E,
0x0E, 0x1C, 0x38, 0x70, 0x60, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x07, 0x07, 0x1E, 0x7C,
0x70, 0x00, 0x70, 0x70, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x77, 0x77, 0x7F, 0xFE,
0xEC, 0xE0, 0xE0, 0xFC, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x77, 0x77, 0x76, 0xFE,
0xFE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x7E, 0x7F, 0x77, 0x77, 0x77, 0x7E, 0xFC,
0xEE, 0xEE, 0xEE, 0xFE, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x77, 0x70, 0x70, 0xE0,
0xE0, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x7C, 0x7E, 0x77, 0x77, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFC, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x7F, 0x7F, 0x70, 0x70, 0x70, 0x7C, 0xF8,
0xE0, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x7F, 0x7F, 0x70, 0x70, 0x70, 0x7C, 0xF8,
0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x77, 0x70, 0x70, 0xFE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x7E, 0xFE,
0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x7F, 0x7F, 0x1C, 0x1C, 0x1C, 0x1C, 0x38,
0x38, 0x38, 0x38, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x0E,
0x0E, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x70, 0x70, 0x72, 0x77, 0x7F, 0x7E, 0xF8,
0xF8, 0xFC, 0xFE, 0xEE, 0xE6, 0x00, 0x00, 0x00,
0x00, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0xE0,
0xE0, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x63, 0x77, 0x7F, 0x7F, 0x7F, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x67, 0x77, 0x77, 0x7F, 0x7F, 0x7E, 0xFE,
0xFE, 0xFE, 0xEE, 0xEE, 0xE6, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x77, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x7E, 0x7F, 0x77, 0x77, 0x77, 0x77, 0xFE,
0xFC, 0xE0, 0xE0, 0xE0, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x77, 0x77, 0x76, 0xEE,
0xEE, 0xFE, 0xFE, 0xFE, 0x7E, 0x06, 0x00, 0x00,
0x00, 0x7E, 0x7F, 0x77, 0x77, 0x77, 0x7E, 0xFC,
0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x70, 0x70, 0x7C, 0x3E,
0x0E, 0x0E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x7F, 0x7F, 0x1C, 0x1C, 0x1C, 0x1C, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x76, 0xEE,
0x6C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x76, 0xEE,
0xFE, 0xFE, 0xFE, 0xEE, 0x44, 0x00, 0x00, 0x00,
0x00, 0x77, 0x77, 0x77, 0x77, 0x3E, 0x1C, 0x38,
0x7C, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x77, 0x77, 0x77, 0x77, 0x77, 0x3E, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x7F, 0x7F, 0x07, 0x07, 0x0E, 0x1C, 0x38,
0x70, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x1F, 0x1F, 0x1C, 0x1C, 0x1C, 0x1C, 0x38,
0x38, 0x38, 0x38, 0x3E, 0x3E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x70, 0x78, 0x38,
0x1C, 0x1E, 0x0E, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7E, 0x7E, 0x0E, 0x0E, 0x0E, 0x0E, 0x1C,
0x1C, 0x1C, 0x1C, 0xFC, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x08, 0x1C, 0x3E, 0x77, 0x63, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x18, 0x1C, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3E, 0x0E,
0x3E, 0x7E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x38, 0x38, 0x38, 0x70, 0x7C, 0x7E, 0x6E,
0xEE, 0xEE, 0xEE, 0xFC, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0xEE,
0xE0, 0xE0, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x07, 0x07, 0x07, 0x07, 0x3F, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0xEE,
0xFE, 0xFC, 0xE0, 0xFC, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x1F, 0x3F, 0x38, 0x38, 0x70, 0x7C, 0x7C,
0x70, 0xE0, 0xE0, 0xE0, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x1C, 0xFC, 0xF8,
0x00, 0x00, 0x70, 0x70, 0x70, 0x7C, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x0E, 0x00, 0x1E, 0x3E, 0x1C,
0x1C, 0x38, 0x38, 0x7C, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x0E, 0x00, 0x1E, 0x3E, 0x0E,
0x1C, 0x1C, 0x1C, 0x1C, 0x38, 0x38, 0xF8, 0xF0,
0x00, 0x38, 0x38, 0x38, 0x3A, 0x7F, 0x7E, 0x7C,
0x70, 0xF8, 0xFC, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x3C, 0x3C, 0x1C, 0x1C, 0x38, 0x38, 0x38,
0x38, 0x70, 0x70, 0x70, 0x70, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x7E, 0xFE,
0xFE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xFC, 0xF8, 0xE0, 0xE0, 0xE0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xFC, 0x7C, 0x1C, 0x1E, 0x1E,
0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x7E, 0x70,
0x70, 0xE0, 0xE0, 0xE0, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x3E, 0x70,
0x7C, 0x3E, 0x0E, 0x7C, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x38, 0x38, 0x38, 0x70, 0x7C, 0x7C, 0x70,
0xE0, 0xE0, 0xE0, 0xFC, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x76, 0xEE,
0xFE, 0xFE, 0xFE, 0xEE, 0x44, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x76, 0x7E,
0x38, 0x7C, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xFE, 0x7E, 0x1C, 0x1C, 0xFC, 0xF8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7E, 0x1E,
0x3C, 0x78, 0xF0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x0F, 0x1F, 0x1C, 0x1C, 0x1C, 0x78, 0xF0,
0x38, 0x38, 0x38, 0x3E, 0x1E, 0x00, 0x00, 0x00,
0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x00,
0x00, 0x78, 0x7C, 0x1C, 0x1C, 0x1C, 0x0F, 0x1E,
0x38, 0x38, 0x38, 0xF8, 0xF0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x33, 0x7F, 0x7F, 0x66, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7F, 0x00, 0x77, 0x55, 0x55, 0x55, 0x77,
0x00, 0xEE, 0x28, 0x4C, 0x48, 0x48, 0x00, 0xFE,
0x00, 0x06, 0x1F, 0x3B, 0x70, 0xFE, 0x70, 0xF8,
0xE0, 0xE0, 0xEE, 0xFC, 0x70, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x38, 0x30, 0x60, 0x00,
0x00, 0x1F, 0x3F, 0x38, 0x38, 0x70, 0x7C, 0x7C,
0x70, 0xE0, 0xE0, 0xE0, 0xE0, 0xC0, 0xC0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xEE, 0xEE, 0xCC, 0x98, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xDB, 0xDB, 0xDB, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x7F, 0x7F, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00,
0x00, 0x1C, 0x1C, 0x1C, 0x7F, 0x7F, 0x1C, 0xFE,
0xFE, 0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00,
0x00, 0x3E, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x67, 0x1C,
0x38, 0x70, 0xE0, 0xDB, 0x1B, 0x00, 0x00, 0x00,
0x77, 0x3E, 0x00, 0x3E, 0x7F, 0x77, 0x70, 0x7C,
0x3E, 0x0E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x1C,
0x38, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x00, 0x00,
0x00, 0x3F, 0x7F, 0x77, 0x77, 0x77, 0x77, 0xEF,
0xEE, 0xEE, 0xEE, 0xFF, 0x7F, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x77, 0x3E, 0x00, 0x7F, 0x7F, 0x07, 0x0E, 0x1C,
0x38, 0x70, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1B, 0x36, 0x36, 0x36, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x36, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x7E,
0x7E, 0x7E, 0x7E, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3B, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x79, 0x7F, 0x2F, 0x29, 0x29, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x77, 0x3E, 0x1C, 0x00, 0x1F, 0x3E, 0x70,
0x7C, 0x3E, 0x0E, 0x7C, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x38, 0x38,
0x1C, 0x0E, 0x1C, 0x38, 0x70, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x7F, 0xFA,
0xDE, 0xDE, 0xFC, 0xFE, 0x6E, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x77, 0x3E, 0x1C, 0x00, 0x7F, 0x7E, 0x1E,
0x3C, 0x78, 0xF0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x3B, 0x00, 0x77, 0x77, 0x77, 0x77, 0x3E,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00,
0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x00,
0x00, 0x00, 0x00, 0x08, 0x08, 0x3E, 0x7F, 0xD6,
0xD0, 0xD0, 0xD6, 0xFE, 0x7C, 0x10, 0x10, 0x00,
0x00, 0x1E, 0x3F, 0x3B, 0x38, 0x7E, 0x7E, 0xFC,
0x70, 0x76, 0xFE, 0xFE, 0xDC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x3E, 0xFE,
0xFE, 0xFE, 0xFE, 0x7C, 0xEE, 0xEE, 0x00, 0x00,
0x00, 0x00, 0x77, 0x77, 0x77, 0x3E, 0x1C, 0xFE,
0x38, 0xFE, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x00,
0x00, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3E, 0x3E, 0x38, 0x1E, 0x3F, 0x66,
0x7E, 0x3C, 0x0E, 0x3E, 0x3E, 0x3C, 0x00, 0x00,
0x00, 0x77, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x61, 0x4D, 0x5D, 0x51, 0xA1,
0xA5, 0xBD, 0x99, 0xC3, 0x7E, 0x3C, 0x00, 0x00,
0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, 0xFC,
0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E,
0x7C, 0xF8, 0xF8, 0x7C, 0x3E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x03, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3F, 0x61, 0x59, 0x5D, 0x55, 0xB9,
0xB9, 0xA5, 0xA5, 0xC3, 0x7E, 0x3C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3C, 0x7E, 0x66, 0x7E, 0x3C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1C, 0x1C, 0x7F, 0x7F, 0x7F, 0x38,
0x38, 0x00, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x78, 0x7C, 0x0C, 0x3C, 0x78, 0xC0,
0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x78, 0x7C, 0x0C, 0x18, 0x0C, 0xF8,
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1C, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0xFC, 0xE0, 0xE0, 0xC0,
0x00, 0x00, 0x00, 0x3F, 0x6D, 0x6D, 0x6D, 0x7A,
0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x38,
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x1C, 0x0C, 0x1C, 0x18, 0x00, 0x00,
0x00, 0x00, 0x30, 0x70, 0x30, 0x30, 0x30, 0xF0,
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x38, 0x7C, 0x44, 0x7C, 0x38, 0x00, 0xF8,
0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8,
0x6C, 0x36, 0x36, 0x6C, 0xD8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x70, 0x31, 0x33, 0x7F, 0x1C,
0x38, 0x76, 0xEE, 0xD6, 0x3E, 0x3E, 0x06, 0x00,
0x00, 0x00, 0x30, 0x70, 0x31, 0x33, 0x7F, 0x1C,
0x38, 0x70, 0xFC, 0xC6, 0x0C, 0x18, 0x1E, 0x00,
0x00, 0x00, 0x70, 0x18, 0x31, 0x1B, 0x77, 0x1C,
0x3A, 0x76, 0xEE, 0xD6, 0x3E, 0x3E, 0x06, 0x00,
0x00, 0x00, 0x0E, 0x0E, 0x0E, 0x00, 0x0E, 0x1C,
0x7C, 0xF8, 0xE0, 0xEE, 0xEE, 0xFE, 0x7C, 0x00,
0x00, 0x70, 0x38, 0x00, 0x08, 0x1C, 0x3E, 0xEE,
0xFE, 0xFE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x07, 0x0E, 0x00, 0x08, 0x1C, 0x3E, 0xEE,
0xFE, 0xFE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x36, 0x63, 0x08, 0x1C, 0x3E, 0xEE,
0xFE, 0xFE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x3B, 0x6E, 0x00, 0x08, 0x1C, 0x3E, 0xEE,
0xFE, 0xFE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x77, 0x77, 0x08, 0x1C, 0x3E, 0x76, 0xFE,
0xFE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x36, 0x1C, 0x1C, 0x3E, 0x76, 0xFE,
0xFE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x0F, 0x1F, 0x3F, 0x7F, 0x77, 0x7F, 0xFF,
0xFE, 0xEE, 0xEF, 0xEF, 0xEF, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x70, 0x70, 0x70, 0xE0,
0xE0, 0xE0, 0xEE, 0xFE, 0x7C, 0x0E, 0x6E, 0x7C,
0x00, 0x38, 0x1C, 0x00, 0x7F, 0x7F, 0x70, 0xE0,
0xF8, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1C, 0x00, 0x7F, 0x7F, 0x70, 0xE0,
0xF8, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x77, 0x00, 0x7F, 0x7F, 0x70, 0xE0,
0xF8, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x77, 0x77, 0x00, 0x7F, 0x7F, 0x70, 0x70, 0xF8,
0xF8, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x38, 0x1C, 0x00, 0x1C, 0x1C, 0x1C, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1C, 0x00, 0x1C, 0x1C, 0x1C, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x36, 0x1C, 0x1C, 0x1C, 0x1C, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x77, 0x77, 0x00, 0x1C, 0x1C, 0x1C, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0x7E, 0x77, 0x77, 0x76, 0xFE,
0xEE, 0xEE, 0xEE, 0xFC, 0xF8, 0x00, 0x00, 0x00,
0x00, 0x3B, 0x6E, 0x00, 0x77, 0x77, 0x76, 0xF6,
0xFE, 0xDE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x38, 0x1C, 0x00, 0x3E, 0x7F, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1C, 0x00, 0x3E, 0x7F, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x77, 0x00, 0x3E, 0x7F, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x3B, 0x6E, 0x00, 0x3E, 0x7F, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x77, 0x77, 0x00, 0x3E, 0x7F, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x76, 0x7C,
0x38, 0x38, 0x7C, 0xEE, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x3D, 0x7E, 0x77, 0x77, 0x77, 0x7E, 0xFE,
0xFE, 0xEE, 0xEE, 0xFE, 0x7C, 0x80, 0x00, 0x00,
0x00, 0x38, 0x1C, 0x00, 0x77, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1C, 0x00, 0x77, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x77, 0x00, 0x77, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x77, 0x77, 0x00, 0x77, 0x77, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1C, 0x00, 0x77, 0x77, 0x76, 0xEE,
0x7C, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x70, 0x70, 0x7E, 0x7F, 0x76, 0xEE,
0xEE, 0xFE, 0xFC, 0xE0, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x7F, 0x77, 0x77, 0x77, 0x7E, 0xFC,
0xEE, 0xEE, 0xEE, 0xFE, 0xFC, 0xE0, 0xC0, 0x00,
0x00, 0x00, 0x70, 0x38, 0x00, 0x3C, 0x3E, 0x0E,
0x3E, 0x7E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1C, 0x38, 0x00, 0x3C, 0x3E, 0x0E,
0x3E, 0x7E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x38, 0x7C, 0xEE, 0x00, 0x3C, 0x3E, 0x0E,
0x3E, 0x7E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x76, 0xDC, 0x00, 0x3C, 0x3E, 0x0E,
0x3E, 0x7E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0xEE, 0xEE, 0x00, 0x3C, 0x3E, 0x0E,
0x3E, 0x7E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x38, 0x00, 0x3C, 0x3E, 0x0E,
0x3E, 0x7E, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3A, 0x3F, 0x3F, 0x1A,
0x7E, 0xFE, 0xD8, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0xFE,
0xEE, 0xE0, 0xEE, 0xFE, 0x7C, 0x1C, 0x7E, 0x7C,
0x00, 0x00, 0x38, 0x1C, 0x00, 0x3E, 0x7F, 0xEE,
0xFE, 0xFE, 0xE0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1C, 0x38, 0x00, 0x3E, 0x7F, 0xEE,
0xFE, 0xFE, 0xE0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x3E, 0x77, 0x00, 0x3E, 0x7F, 0xEE,
0xFE, 0xFE, 0xE0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x77, 0x77, 0x00, 0x3E, 0x7F, 0xEE,
0xFE, 0xFE, 0xE0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x1C, 0x00, 0x1C, 0x1C, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x1C, 0x00, 0x1C, 0x1C, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x3E, 0x77, 0x00, 0x1C, 0x1C, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x77, 0x77, 0x00, 0x1C, 0x1C, 0x38,
0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x76, 0x3E, 0x7C, 0x7E, 0x3F, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x3B, 0x7F, 0x6E, 0x00, 0x7E, 0x7F, 0xEE,
0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00, 0x00,
0x00, 0x00, 0x70, 0x38, 0x00, 0x3C, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1C, 0x38, 0x00, 0x3C, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x3E, 0x77, 0x00, 0x3C, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x3B, 0x7F, 0x6E, 0x00, 0x3C, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x77, 0x77, 0x00, 0x3C, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0xFE,
0xFE, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x3E, 0x7E, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7C, 0x80, 0x00, 0x00,
0x00, 0x00, 0x70, 0x38, 0x00, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1C, 0x38, 0x00, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x1C, 0x3E, 0x77, 0x00, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x77, 0x77, 0x00, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x1C, 0x00, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x0E, 0xFE, 0xFC,
0x00, 0x00, 0x70, 0x70, 0x7E, 0x7F, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xEE, 0xFE, 0xFC, 0xE0, 0xE0,
0x00, 0x00, 0x77, 0x77, 0x00, 0x77, 0x76, 0xEE,
0xEE, 0xEE, 0xEE, 0xFE, 0x7E, 0x0E, 0xFE, 0xFC,
};
 
const struct fb_font_desc font_italic_bold = {
.name = "NetSurf Italic Bold",
.width = 8,
.height = 16,
.encoding = "CP1252",
.data = fontdata_italic_bold,
};
/programs/network/netsurf/netsurf/framebuffer/nsfont_regular.c
0,0 → 1,556
/*
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright Tim Tyler
* Copyright Michael Drake <tlsa@netsurf-browser.org>
*
* This font is based on the "Default" font with Zap 1.47 [TEST], which
* was created for Zap by Tim Tyler. It was converted to a plain text
* format and many glyphs added for use in the NetSurf project.
*
* Plain text font data:
* http://source.netsurf-browser.org/?p=art.git;a=blob_plain;f=fonts/netsurf/glyph_data;hb=HEAD
*
* Zap: http://zap.tartarus.org/
* NetSurf: http://www.netsurf-browser.org/
*
* Thanks to Tim Tyler for the original font and his permission to use it.
* Thanks to James Aylett for helping track down Tim.
* Thanks to Christian Ludlam for helping with Zap font info.
*
* Please contact Michael Drake if you want to contribute gylphs to
* this font.
*/
 
/* Don't edit this file, it was generated from the plain text source data. */
 
#include "desktop/plotters.h"
#include "utils/utf8.h"
 
#include "framebuffer/font_internal.h"
 
#define FONTDATAMAX 4096
 
static const uint32_t fontdata_regular[FONTDATAMAX] = {
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xE4, 0xAC, 0xA4, 0xA4, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEC, 0xA2, 0xA4, 0xA8, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEC, 0xA2, 0xAC, 0xA2, 0xEC, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEA, 0xAA, 0xAE, 0xA2, 0xE2, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xA8, 0xAE, 0xA2, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xE6, 0xA8, 0xAE, 0xAA, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xA2, 0xA4, 0xA4, 0xE4, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xAA, 0xAE, 0xAA, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xAA, 0xAE, 0xA2, 0xE2, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xE4, 0xAA, 0xAE, 0xAA, 0xEA, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEC, 0xAA, 0xAC, 0xAA, 0xEC, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xE4, 0xAA, 0xA8, 0xAA, 0xE4, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEC, 0xAA, 0xAA, 0xAA, 0xEC, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xA8, 0xAC, 0xA8, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0xA8, 0xAC, 0xA8, 0xE8, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xCA, 0x4A, 0x4A, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x44, 0xCC, 0x44, 0x44, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4C, 0xC2, 0x44, 0x48, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4C, 0xC2, 0x4C, 0x42, 0xEC, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4A, 0xCA, 0x4E, 0x42, 0xE2, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xC8, 0x4E, 0x42, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x46, 0xC8, 0x4E, 0x4A, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xC2, 0x44, 0x44, 0xE4, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xCA, 0x4E, 0x4A, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xCA, 0x4E, 0x42, 0xE2, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x44, 0xCA, 0x4E, 0x4A, 0xEA, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4C, 0xCA, 0x4C, 0x4A, 0xEC, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x44, 0xCA, 0x48, 0x4A, 0xE4, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4C, 0xCA, 0x4A, 0x4A, 0xEC, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xC8, 0x4C, 0x48, 0xEE, 0x00, 0xFE,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0x4E, 0xC8, 0x4C, 0x48, 0xE8, 0x00, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x6C, 0x6C, 0x6C, 0xFE, 0xFE, 0x6C, 0x6C,
0xFE, 0xFE, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00,
0x00, 0x10, 0x7C, 0xFE, 0xD6, 0xD0, 0xF0, 0x7C,
0x1E, 0x16, 0xD6, 0xFE, 0x7C, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xCE, 0x1C,
0x38, 0x70, 0xE6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x70, 0xF8, 0xD8, 0xD8, 0xF8, 0x72, 0xFE,
0xDE, 0xCC, 0xCC, 0xFE, 0x7A, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x06, 0x0E, 0x1C, 0x18, 0x38, 0x30, 0x30, 0x30,
0x30, 0x38, 0x18, 0x1C, 0x0E, 0x06, 0x00, 0x00,
0x60, 0x70, 0x38, 0x18, 0x1C, 0x0C, 0x0C, 0x0C,
0x0C, 0x1C, 0x18, 0x38, 0x70, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x6C, 0x6C, 0x38, 0xFE,
0xFE, 0x38, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x7E,
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0E, 0x1C,
0x38, 0x70, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0xCE, 0xCE, 0xD6, 0xD6,
0xE6, 0xE6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x18, 0x38, 0x78, 0x78, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0x06, 0x06, 0x3E, 0x7C,
0xE0, 0xC0, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0x06, 0x06, 0x3C, 0x3C,
0x06, 0x06, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x04, 0x0C, 0x1C, 0x3C, 0x7C, 0xEC, 0xFE,
0xFE, 0x0C, 0x0C, 0x0C, 0x0C, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFE, 0xC0, 0xC0, 0xC0, 0xFC, 0xFE,
0x06, 0x06, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x3C, 0x7C, 0xE0, 0xC0, 0xC0, 0xFC, 0xFE,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFE, 0xC6, 0x0E, 0x0C, 0x1C, 0x18,
0x38, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0xC6, 0xC6, 0x7C, 0x7C,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0xC6, 0xC6, 0xFE, 0x7E,
0x06, 0x06, 0x0E, 0x7C, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
0x00, 0x18, 0x18, 0x38, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x0E, 0x1C, 0x38, 0x70, 0x70,
0x38, 0x1C, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00,
0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x70, 0x38, 0x1C, 0x0E, 0x0E,
0x1C, 0x38, 0x70, 0x60, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0xC6, 0x06, 0x1E, 0x3C,
0x30, 0x30, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0xCE, 0xDE, 0xD6, 0xD6,
0xDE, 0xCC, 0xC0, 0xFC, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0xC6, 0xC6, 0xFE, 0xFE,
0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0xFC, 0xFE, 0xC6, 0xC6, 0xC6, 0xFC, 0xFC,
0xC6, 0xC6, 0xC6, 0xFE, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0xC0, 0xC0, 0xC0, 0xC0,
0xC0, 0xC0, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0xF8, 0xFC, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xCE, 0xFC, 0xF8, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFE, 0xC0, 0xC0, 0xC0, 0xF8, 0xF8,
0xC0, 0xC0, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFE, 0xC0, 0xC0, 0xC0, 0xF8, 0xF8,
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0xC0, 0xC0, 0xDE, 0xDE,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xFE,
0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
0x0C, 0x0C, 0xCC, 0xFC, 0x78, 0x00, 0x00, 0x00,
0x00, 0xC0, 0xC6, 0xCE, 0xDC, 0xF8, 0xF0, 0xE0,
0xF0, 0xF8, 0xDC, 0xCE, 0xC6, 0x00, 0x00, 0x00,
0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
0xC0, 0xC0, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0xC6, 0xC6, 0xEE, 0xFE, 0xFE, 0xFE, 0xD6,
0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0xC6, 0xC6, 0xE6, 0xE6, 0xF6, 0xF6, 0xDE,
0xDE, 0xCE, 0xCE, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0xFC, 0xFE, 0xC6, 0xC6, 0xC6, 0xFE, 0xFC,
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
0xC6, 0xD6, 0xDE, 0xFE, 0x7C, 0x06, 0x00, 0x00,
0x00, 0xFC, 0xFE, 0xC6, 0xC6, 0xC6, 0xFC, 0xFC,
0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0xC0, 0xC0, 0xFC, 0x7E,
0x06, 0x06, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xEE,
0x6C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6,
0xD6, 0xFE, 0xFE, 0xEE, 0x44, 0x00, 0x00, 0x00,
0x00, 0xC6, 0xC6, 0xC6, 0xEE, 0x7C, 0x38, 0x38,
0x7C, 0xEE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xEE, 0x7C, 0x38,
0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xFE, 0x0E, 0x0C, 0x1C, 0x18, 0x38,
0x30, 0x70, 0x60, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x3E, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x3E, 0x3E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0x70,
0x38, 0x1C, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7C, 0x7C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
0x0C, 0x0C, 0x0C, 0x7C, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x7C, 0xEE, 0xC6, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x30, 0x30, 0x18, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0x06,
0x7E, 0xFE, 0xC6, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xFC, 0xFE, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xFE, 0xC6,
0xC0, 0xC0, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x06, 0x06, 0x06, 0x06, 0x7E, 0xFE, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xFE, 0xC6,
0xFE, 0xFE, 0xC0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x3E, 0x30, 0x30, 0x30, 0x78, 0x78,
0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFE, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7E, 0x06, 0x7E, 0x7C,
0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xDC, 0xFE, 0xE6,
0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x38, 0x18,
0x18, 0x18, 0x18, 0x3C, 0x3C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0C, 0x0C, 0x00, 0x1C, 0x1C, 0x0C,
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x7C, 0x78,
0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC6, 0xCE, 0xDC,
0xF8, 0xF8, 0xDC, 0xCE, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xFE,
0xD6, 0xD6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xFE, 0xE6,
0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xFE, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFE, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0xFC, 0xC0, 0xC0, 0xC0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFE, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7E, 0x06, 0x07, 0x07,
0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xFE, 0xE0,
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFE, 0xC0,
0xFC, 0x7C, 0x06, 0xFE, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x10, 0x30, 0x30, 0x30, 0x7C, 0xFC, 0x30,
0x30, 0x30, 0x30, 0x3E, 0x1E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xCE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6,
0xC6, 0xEE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6,
0xD6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xEE,
0x7C, 0x7C, 0xEE, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7E, 0x06, 0xFE, 0xFC,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x0E,
0x3C, 0x78, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1E, 0x18, 0x18, 0x18, 0x70, 0x70,
0x18, 0x18, 0x18, 0x1E, 0x0E, 0x00, 0x00, 0x00,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
0x00, 0x70, 0x78, 0x18, 0x18, 0x18, 0x0E, 0x0E,
0x18, 0x18, 0x18, 0x78, 0x70, 0x00, 0x00, 0x00,
0x00, 0x00, 0x76, 0xFE, 0xDC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFE, 0x00, 0xEE, 0xAA, 0xAA, 0xAA, 0xEE,
0x00, 0xEE, 0x28, 0x4C, 0x48, 0x48, 0x00, 0xFE,
0x00, 0x18, 0x3C, 0x66, 0x60, 0xFC, 0x60, 0xF8,
0x60, 0x60, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00,
0x00, 0x1E, 0x3E, 0x30, 0x30, 0x30, 0x78, 0x78,
0x30, 0x30, 0x30, 0x30, 0x30, 0xF0, 0x60, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x66, 0x66, 0x22, 0x44, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xDB, 0xDB, 0x00, 0x00, 0x00,
0x00, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
0x00, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x7E,
0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
0x00, 0x7C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C,
0x18, 0x30, 0x60, 0xDB, 0x9B, 0x00, 0x00, 0x00,
0xC6, 0x7C, 0x00, 0x7C, 0xFE, 0xC6, 0xC0, 0xFC,
0x7E, 0x06, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1C,
0x38, 0x30, 0x38, 0x1C, 0x0C, 0x00, 0x00, 0x00,
0x00, 0x7F, 0xFF, 0xCC, 0xCC, 0xCC, 0xCF, 0xCF,
0xCC, 0xCC, 0xCC, 0xFF, 0x7F, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0xC6, 0x7C, 0x00, 0xFE, 0xFE, 0x06, 0x0C, 0x18,
0x30, 0x60, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0x20, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x24, 0x48, 0x6C, 0x6C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x36, 0x36, 0x12, 0x24, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E,
0x7E, 0x7E, 0x7E, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x32, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xF1, 0xFB, 0x5F, 0x55, 0x51, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xC6, 0x6C, 0x38, 0x00, 0x7E, 0xFE, 0xC0,
0xFC, 0x7C, 0x06, 0xFE, 0xFC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x38,
0x1C, 0x0C, 0x1C, 0x38, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xDA,
0xDE, 0xDE, 0xD8, 0xFE, 0x6E, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x38, 0x6C, 0x54, 0xF6, 0xEE,
0x6C, 0x7C, 0x28, 0x38, 0x10, 0x00, 0x00, 0x00,
0x00, 0xC6, 0x6C, 0x38, 0x00, 0xFE, 0xFE, 0x0E,
0x3C, 0x78, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x6C, 0x00, 0xC6, 0xC6, 0xC6, 0xEE, 0x7C,
0x38, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0xFE, 0xD6,
0xD0, 0xD0, 0xD6, 0xFE, 0x7C, 0x10, 0x10, 0x00,
0x00, 0x3C, 0x7E, 0x66, 0x60, 0x60, 0xF8, 0xF8,
0x60, 0x60, 0xE6, 0xFE, 0xDC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x7E,
0x66, 0x66, 0x7E, 0x3C, 0x66, 0x66, 0x00, 0x00,
0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E,
0x18, 0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x3C, 0x7C, 0x60, 0x60, 0x3C, 0x7E, 0x66,
0x7E, 0x3C, 0x06, 0x06, 0x3E, 0x3C, 0x00, 0x00,
0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3C, 0x7E, 0xC3, 0x99, 0xBD, 0xA5, 0xA1,
0xA5, 0xBD, 0x99, 0xC3, 0x7E, 0x3C, 0x00, 0x00,
0x00, 0x70, 0x08, 0x78, 0x88, 0x78, 0x00, 0xF8,
0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36,
0x6C, 0xD8, 0xD8, 0x6C, 0x36, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7E, 0x7E, 0x06, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3C, 0x7E, 0xC3, 0xB9, 0xBD, 0xA5, 0xB9,
0xB9, 0xA5, 0xA5, 0xC3, 0x7E, 0x3C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x78, 0xFC, 0xCC, 0xFC, 0x78, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x7E, 0x18,
0x18, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xF0, 0xF8, 0x18, 0x78, 0xF0, 0xC0,
0xF8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xF0, 0xF8, 0x18, 0x30, 0x18, 0xF8,
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66,
0x66, 0x66, 0x66, 0x7E, 0x7C, 0x60, 0x60, 0xC0,
0x00, 0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B,
0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x1C, 0x0C, 0x1C, 0x18, 0x00, 0x00,
0x00, 0x00, 0x60, 0xE0, 0x60, 0x60, 0x60, 0xF0,
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x70, 0xF8, 0x88, 0xF8, 0x70, 0x00, 0xF8,
0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8,
0x6C, 0x36, 0x36, 0x6C, 0xD8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x40, 0xC0, 0x42, 0x46, 0xEC, 0x18,
0x30, 0x64, 0xCC, 0x94, 0x3E, 0x04, 0x04, 0x00,
0x00, 0x00, 0x40, 0xC0, 0x42, 0x46, 0xEC, 0x18,
0x30, 0x60, 0xDC, 0x82, 0x0C, 0x10, 0x1E, 0x00,
0x00, 0x00, 0xE0, 0x10, 0x62, 0x16, 0xEC, 0x18,
0x30, 0x64, 0xCC, 0x96, 0x3E, 0x04, 0x04, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18,
0x78, 0xF0, 0xC0, 0xC6, 0xC6, 0xFE, 0x7C, 0x00,
0x00, 0x60, 0x30, 0x00, 0x10, 0x38, 0x6C, 0xC6,
0xFE, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x18, 0x00, 0x10, 0x38, 0x6C, 0xC6,
0xFE, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x44, 0x10, 0x38, 0x6C, 0xC6,
0xFE, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x76, 0xDC, 0x00, 0x10, 0x38, 0x6C, 0xC6,
0xFE, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x6C, 0x6C, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xFE,
0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x38, 0x44, 0x38, 0x38, 0x6C, 0xC6, 0xFE,
0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x1F, 0x3F, 0x7C, 0xEC, 0xCC, 0xFE, 0xFE,
0xCC, 0xCC, 0xCC, 0xCF, 0xCF, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xFE, 0xC6, 0xC0, 0xC0, 0xC0, 0xC0,
0xC0, 0xC0, 0xC6, 0xFE, 0x7C, 0x0E, 0x66, 0x3C,
0x00, 0x30, 0x18, 0x00, 0xFE, 0xFE, 0xC0, 0xF0,
0xF0, 0xC0, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x18, 0x00, 0xFE, 0xFE, 0xC0, 0xF0,
0xF0, 0xC0, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x00, 0xFE, 0xFE, 0xC0, 0xF0,
0xF0, 0xC0, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x6C, 0x6C, 0x00, 0xFE, 0xFE, 0xC0, 0xC0, 0xF0,
0xF0, 0xC0, 0xC0, 0xFE, 0xFE, 0x00, 0x00, 0x00,
0x00, 0x30, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x18, 0x24, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x66, 0x66, 0x00, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x78, 0x7C, 0x6E, 0x66, 0x66, 0xF6,
0x66, 0x66, 0x6E, 0x7C, 0x78, 0x00, 0x00, 0x00,
0x00, 0x76, 0xDC, 0x00, 0xC6, 0xC6, 0xE6, 0xF6,
0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x30, 0x18, 0x00, 0x7C, 0xFE, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x18, 0x00, 0x7C, 0xFE, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x00, 0x7C, 0xFE, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x76, 0xDC, 0x00, 0x7C, 0xFE, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x6C, 0x00, 0x7C, 0xFE, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xEE, 0x7C,
0x38, 0x38, 0x7C, 0xEE, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x7E, 0xFE, 0xC6, 0xC6, 0xCE, 0xCE, 0xD6,
0xD6, 0xE6, 0xE6, 0xFE, 0x7C, 0x80, 0x00, 0x00,
0x00, 0x30, 0x18, 0x00, 0xC6, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x18, 0x00, 0xC6, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x00, 0xC6, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x6C, 0x6C, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x18, 0x00, 0x66, 0x66, 0x66, 0x7E,
0x3C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x60, 0x7C, 0x7E, 0x66, 0x66,
0x7E, 0x7C, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00,
0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x7C,
0x66, 0x66, 0x66, 0x7E, 0x7C, 0xE0, 0xC0, 0x00,
0x00, 0x00, 0x30, 0x18, 0x00, 0x7E, 0xFE, 0xC6,
0xC6, 0xCE, 0xCE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x30, 0x00, 0x7E, 0xFE, 0xC6,
0xC6, 0xC6, 0xCE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x6C, 0x00, 0x7E, 0xFE, 0xC6,
0xC6, 0xC6, 0xCE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x00, 0x76, 0xDC, 0x00, 0x7E, 0xFE, 0xC6,
0xC6, 0xC6, 0xCE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x00, 0x6C, 0x6C, 0x00, 0x7E, 0xFE, 0xC6,
0xC6, 0xC6, 0xCE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x38, 0x00, 0x7E, 0xFE, 0xC6,
0xC6, 0xC6, 0xCE, 0xFE, 0x76, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x7E, 0x1A,
0x3E, 0x7E, 0xD8, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xFE,
0xC6, 0xC0, 0xC6, 0xFE, 0x7C, 0x18, 0x7C, 0x78,
0x00, 0x00, 0x30, 0x18, 0x00, 0x7C, 0xFE, 0xC6,
0xFE, 0xFE, 0xC0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x30, 0x00, 0x7C, 0xFE, 0xC6,
0xFE, 0xFE, 0xC0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xFE, 0xC6,
0xFE, 0xFE, 0xC0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x6C, 0x6C, 0x00, 0x7C, 0xFE, 0xC6,
0xFE, 0xFE, 0xC0, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x18, 0x00, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0C, 0x18, 0x00, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x18, 0x3C, 0x66, 0x00, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x66, 0x66, 0x00, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x6C, 0x7C, 0xF8, 0xDC, 0x7C, 0xFE, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x76, 0xFE, 0xDC, 0x00, 0xFC, 0xFE, 0xC6,
0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x30, 0x00, 0x7C, 0xFE, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x30, 0x00, 0x7C, 0xFE, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xFE, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x76, 0xFE, 0xDC, 0x00, 0x7C, 0xFE, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x6C, 0x6C, 0x00, 0x7C, 0xFE, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E,
0x7E, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x7C, 0xFE, 0xCE,
0xD6, 0xD6, 0xE6, 0xFE, 0x7C, 0x80, 0x00, 0x00,
0x00, 0x00, 0x60, 0x30, 0x00, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x30, 0x00, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x6C, 0x00, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x6C, 0x6C, 0x00, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0C, 0x18, 0x00, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7E, 0x06, 0xFC, 0xF8,
0x00, 0x00, 0x60, 0x60, 0x60, 0x7C, 0x7E, 0x66,
0x66, 0x66, 0x66, 0x7E, 0x7C, 0x60, 0x60, 0x60,
0x00, 0x00, 0x6C, 0x6C, 0x00, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xFE, 0x7E, 0x06, 0xFE, 0xFC,
};
 
const struct fb_font_desc font_regular = {
.name = "NetSurf Regular",
.width = 8,
.height = 16,
.encoding = "CP1252",
.data = fontdata_regular,
};
/programs/network/netsurf/netsurf/framebuffer/options.h
0,0 → 1,110
/*
* Copyright 2008, 2010 Daniel Silverstone <dsilvers@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef _NETSURF_DESKTOP_OPTIONS_INCLUDING_
#error "Frontend options header cannot be included directly"
#endif
 
#ifndef _NETSURF_FRAMEBUFFER_OPTIONS_H_
#define _NETSURF_FRAMEBUFFER_OPTIONS_H_
 
#define NSOPTION_EXTRA_DEFINE \
/* surface options */ \
int fb_depth; \
int fb_refresh; \
char *fb_device; \
char *fb_input_devpath; \
char *fb_input_glob; \
\
/* toolkit options */ \
int fb_furniture_size; /**< toolkit furniture size */ \
int fb_toolbar_size; /**< toolbar furniture size */ \
char *fb_toolbar_layout; /**< toolbar layout */ \
bool fb_osk; /**< enable on screen keyboard */ \
\
/* font options */ \
bool fb_font_monochrome; /**< render font monochrome */ \
int fb_font_cachesize; /**< size of font glyph cache in kilobytes. */ \
\
char *fb_face_sans_serif; /**< default sans face */ \
char *fb_face_sans_serif_bold; /**< bold sans face */ \
char *fb_face_sans_serif_italic; /**< bold sans face */ \
char *fb_face_sans_serif_italic_bold; /**< bold sans face */ \
\
char *fb_face_serif; /**< serif face */ \
char *fb_face_serif_bold; /**< bold serif face */ \
\
char *fb_face_monospace; /**< monospace face */ \
char *fb_face_monospace_bold; /**< bold monospace face */ \
\
char *fb_face_cursive; /**< cursive face */ \
char *fb_face_fantasy /**< fantasy face */
 
#define NSOPTION_EXTRA_DEFAULTS \
.fb_depth = 32, \
.fb_refresh = 70, \
.fb_device = NULL, \
.fb_input_devpath = NULL, \
.fb_input_glob = NULL, \
.fb_furniture_size = 18, \
.fb_toolbar_size = 30, \
.fb_toolbar_layout = NULL, \
.fb_osk = false, \
.fb_font_monochrome = false, \
.fb_font_cachesize = 2048, \
.fb_face_sans_serif = NULL, \
.fb_face_sans_serif_bold = NULL, \
.fb_face_sans_serif_italic = NULL, \
.fb_face_sans_serif_italic_bold = NULL, \
.fb_face_serif = NULL, \
.fb_face_serif_bold = NULL, \
.fb_face_monospace = NULL, \
.fb_face_monospace_bold = NULL, \
.fb_face_cursive = NULL, \
.fb_face_fantasy = NULL
 
#define NSOPTION_EXTRA_TABLE \
{ "fb_depth", OPTION_INTEGER, &nsoptions.fb_depth }, \
{ "fb_refresh", OPTION_INTEGER, &nsoptions.fb_refresh }, \
{ "fb_device", OPTION_STRING, &nsoptions.fb_device }, \
{ "fb_input_devpath", OPTION_STRING, &nsoptions.fb_input_devpath }, \
{ "fb_input_glob", OPTION_STRING, &nsoptions.fb_input_glob }, \
{ "fb_furniture_size", OPTION_INTEGER, &nsoptions.fb_furniture_size }, \
{ "fb_toolbar_size", OPTION_INTEGER, &nsoptions.fb_toolbar_size }, \
{ "fb_toolbar_layout", OPTION_STRING, &nsoptions.fb_toolbar_layout }, \
{ "fb_osk", OPTION_BOOL, &nsoptions.fb_osk }, \
{ "fb_font_monochrome", OPTION_BOOL, &nsoptions.fb_font_monochrome }, \
{ "fb_font_cachesize", OPTION_INTEGER, &nsoptions.fb_font_cachesize }, \
{ "fb_face_sans_serif", OPTION_STRING, &nsoptions.fb_face_sans_serif }, \
{ "fb_face_sans_serif_bold", OPTION_STRING, &nsoptions.fb_face_sans_serif_bold }, \
{ "fb_face_sans_serif_italic", OPTION_STRING, &nsoptions.fb_face_sans_serif_italic }, \
{ "fb_face_sans_serif_italic_bold", OPTION_STRING, &nsoptions.fb_face_sans_serif_italic_bold }, \
{ "fb_face_serif", OPTION_STRING, &nsoptions.fb_face_serif }, \
{ "fb_serif_bold", OPTION_STRING, &nsoptions.fb_face_serif_bold }, \
{ "fb_face_monospace", OPTION_STRING, &nsoptions.fb_face_monospace }, \
{ "fb_face_monospace_bold", OPTION_STRING, &nsoptions.fb_face_monospace_bold }, \
{ "fb_face_cursive", OPTION_STRING, &nsoptions.fb_face_cursive }, \
{ "fb_face_fantasy", OPTION_STRING, &nsoptions.fb_face_fantasy }
 
#endif
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/res/adblock.css
0,0 → 1,0
link ../../!NetSurf/Resources/AdBlock,f79
Property changes:
Added: svn:special
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/credits.html
0,0 → 1,0
link ../../!NetSurf/Resources/en/credits.html,faf
Property changes:
Added: svn:special
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/default.css
0,0 → 1,0
link ../../!NetSurf/Resources/CSS,f79
Property changes:
Added: svn:special
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/favicon.png
0,0 → 1,0
link ../../gtk/res/favicon.png
Property changes:
Added: svn:special
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/back.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/back_g.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/forward.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/forward_g.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/history.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/history_g.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/home.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/home_g.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/osk.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/reload.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/reload_g.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/scrolld.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/scrolll.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/scrollr.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/scrollu.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/stop.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/icons/stop_g.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/internal.css
0,0 → 1,0
link ../../!NetSurf/Resources/internal.css,f79
Property changes:
Added: svn:special
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/licence.html
0,0 → 1,0
link ../../!NetSurf/Resources/en/licence.html,faf
Property changes:
Added: svn:special
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/messages
0,0 → 1,0
link ../../!NetSurf/Resources/en/Messages
Property changes:
Added: svn:special
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/netsurf.png
0,0 → 1,0
link ../../!NetSurf/Resources/netsurf.png,b60
Property changes:
Added: svn:special
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/caret.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/cross.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/default.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/help.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/left-right.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/lu-rd.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/menu.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/move.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/no_drop.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/not_allowed.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/point.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/progress.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/ru-ld.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/up-down.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/pointers/wait.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/quirks.css
0,0 → 1,0
link ../../!NetSurf/Resources/Quirks,f79
Property changes:
Added: svn:special
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/throbber
0,0 → 1,0
link ../../gtk/res/throbber
Property changes:
Added: svn:special
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/res/welcome.html
0,0 → 1,0
link ../../!NetSurf/Resources/en/welcome.html,faf
Property changes:
Added: svn:special
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/framebuffer/schedule.c
0,0 → 1,219
/*
* Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
 
#include "utils/schedule.h"
#include "framebuffer/schedule.h"
 
#include "utils/log.h"
 
/* linked list of scheduled callbacks */
static struct nscallback *schedule_list = NULL;
 
/**
* scheduled callback.
*/
struct nscallback
{
struct nscallback *next;
struct timeval tv;
void (*callback)(void *p);
void *p;
};
 
 
/**
* Schedule a callback.
*
* \param tival interval before the callback should be made / cs
* \param callback callback function
* \param p user parameter, passed to callback function
*
* The callback function will be called as soon as possible after t cs have
* passed.
*/
 
void schedule(int cs_ival, void (*callback)(void *p), void *p)
{
struct nscallback *nscb;
struct timeval tv;
 
tv.tv_sec = cs_ival / 100; /* cs to seconds */
tv.tv_usec = (cs_ival % 100) * 10000; /* remainder to microseconds */
 
nscb = calloc(1, sizeof(struct nscallback));
 
gettimeofday(&nscb->tv, NULL);
timeradd(&nscb->tv, &tv, &nscb->tv);
 
nscb->callback = callback;
nscb->p = p;
 
/* add to list front */
nscb->next = schedule_list;
schedule_list = nscb;
}
 
/**
* Unschedule a callback.
*
* \param callback callback function
* \param p user parameter, passed to callback function
*
* All scheduled callbacks matching both callback and p are removed.
*/
 
void schedule_remove(void (*callback)(void *p), void *p)
{
struct nscallback *cur_nscb;
struct nscallback *prev_nscb;
struct nscallback *unlnk_nscb;
 
if (schedule_list == NULL)
return;
 
LOG(("removing %p, %p", callback, p));
 
cur_nscb = schedule_list;
prev_nscb = NULL;
 
while (cur_nscb != NULL) {
if ((cur_nscb->callback == callback) &&
(cur_nscb->p == p)) {
/* item to remove */
 
LOG(("callback entry %p removing %p(%p)",
cur_nscb, cur_nscb->callback, cur_nscb->p));
 
/* remove callback */
unlnk_nscb = cur_nscb;
cur_nscb = unlnk_nscb->next;
 
if (prev_nscb == NULL) {
schedule_list = cur_nscb;
} else {
prev_nscb->next = cur_nscb;
}
free (unlnk_nscb);
} else {
/* move to next element */
prev_nscb = cur_nscb;
cur_nscb = prev_nscb->next;
}
}
}
 
/**
* Process scheduled callbacks up to current time.
*
* @return The number of milliseconds untill the next scheduled event
* or -1 for no event.
*/
int
schedule_run(void)
{
struct timeval tv;
struct timeval nexttime;
struct timeval rettime;
struct nscallback *cur_nscb;
struct nscallback *prev_nscb;
struct nscallback *unlnk_nscb;
 
if (schedule_list == NULL)
return -1;
 
/* reset enumeration to the start of the list */
cur_nscb = schedule_list;
prev_nscb = NULL;
nexttime = cur_nscb->tv;
 
gettimeofday(&tv, NULL);
 
while (cur_nscb != NULL) {
if (timercmp(&tv, &cur_nscb->tv, 0)) {
/* scheduled time */
 
/* remove callback */
unlnk_nscb = cur_nscb;
 
if (prev_nscb == NULL) {
schedule_list = unlnk_nscb->next;
} else {
prev_nscb->next = unlnk_nscb->next;
}
 
unlnk_nscb->callback(unlnk_nscb->p);
 
free(unlnk_nscb);
 
/* need to deal with callback modifying the list. */
if (schedule_list == NULL)
return -1; /* no more callbacks scheduled */
/* reset enumeration to the start of the list */
cur_nscb = schedule_list;
prev_nscb = NULL;
nexttime = cur_nscb->tv;
} else {
/* if the time to the event is sooner than the
* currently recorded soonest event record it
*/
if (timercmp(&nexttime, &cur_nscb->tv, 0)) {
nexttime = cur_nscb->tv;
}
/* move to next element */
prev_nscb = cur_nscb;
cur_nscb = prev_nscb->next;
}
}
 
/* make rettime relative to now */
timersub(&nexttime, &tv, &rettime);
 
/*LOG(("returning time to next event as %ldms",(rettime.tv_sec * 1000) + (rettime.tv_usec / 1000))); */
/* return next event time in milliseconds (24days max wait) */
return (rettime.tv_sec * 1000) + (rettime.tv_usec / 1000);
}
 
void list_schedule(void)
{
struct timeval tv;
struct nscallback *cur_nscb;
 
gettimeofday(&tv, NULL);
 
LOG(("schedule list at %ld:%ld", tv.tv_sec, tv.tv_usec));
 
cur_nscb = schedule_list;
 
while (cur_nscb != NULL) {
LOG(("Schedule %p at %ld:%ld",
cur_nscb, cur_nscb->tv.tv_sec, cur_nscb->tv.tv_usec));
cur_nscb = cur_nscb->next;
}
}
 
 
/*
* Local Variables:
* c-basic-offset:8
* End:
*/
/programs/network/netsurf/netsurf/framebuffer/schedule.h
0,0 → 1,25
/*
* Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef FRAMEBUFFER_SCHEDULE_H
#define FRAMEBUFFER_SCHEDULE_H
 
int schedule_run(void);
void list_schedule(void);
 
#endif
/programs/network/netsurf/netsurf/framebuffer/system_colour.c
0,0 → 1,282
/*
* Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* System colour handling
*
*/
 
#include "utils/utils.h"
#include "utils/log.h"
#include "desktop/gui.h"
#include "desktop/options.h"
 
struct gui_system_colour_ctx {
const char *name;
int length;
css_color colour;
colour *option_colour;
lwc_string *lwcstr;
};
 
static struct gui_system_colour_ctx colour_list[] = {
{
"ActiveBorder",
SLEN("ActiveBorder"),
0xff000000,
&nsoption_colour(sys_colour_ActiveBorder),
NULL
}, {
"ActiveCaption",
SLEN("ActiveCaption"),
0xffdddddd,
&nsoption_colour(sys_colour_ActiveCaption),
NULL
}, {
"AppWorkspace",
SLEN("AppWorkspace"),
0xffeeeeee,
&nsoption_colour(sys_colour_AppWorkspace),
NULL
}, {
"Background",
SLEN("Background"),
0xff0000aa,
&nsoption_colour(sys_colour_Background),
NULL
}, {
"ButtonFace",
SLEN("ButtonFace"),
0xffaaaaaa,
&nsoption_colour(sys_colour_ButtonFace),
NULL
}, {
"ButtonHighlight",
SLEN("ButtonHighlight"),
0xffdddddd,
&nsoption_colour(sys_colour_ButtonHighlight),
NULL
}, {
"ButtonShadow",
SLEN("ButtonShadow"),
0xffbbbbbb,
&nsoption_colour(sys_colour_ButtonShadow),
NULL
}, {
"ButtonText",
SLEN("ButtonText"),
0xff000000,
&nsoption_colour(sys_colour_ButtonText),
NULL
}, {
"CaptionText",
SLEN("CaptionText"),
0xff000000,
&nsoption_colour(sys_colour_CaptionText),
NULL
}, {
"GrayText",
SLEN("GrayText"),
0xffcccccc,
&nsoption_colour(sys_colour_GrayText),
NULL
}, {
"Highlight",
SLEN("Highlight"),
0xff0000ee,
&nsoption_colour(sys_colour_Highlight),
NULL
}, {
"HighlightText",
SLEN("HighlightText"),
0xff000000,
&nsoption_colour(sys_colour_HighlightText),
NULL
}, {
"InactiveBorder",
SLEN("InactiveBorder"),
0xffffffff,
&nsoption_colour(sys_colour_InactiveBorder),
NULL
}, {
"InactiveCaption",
SLEN("InactiveCaption"),
0xffffffff,
&nsoption_colour(sys_colour_InactiveCaption),
NULL
}, {
"InactiveCaptionText",
SLEN("InactiveCaptionText"),
0xffcccccc,
&nsoption_colour(sys_colour_InactiveCaptionText),
NULL
}, {
"InfoBackground",
SLEN("InfoBackground"),
0xffaaaaaa,
&nsoption_colour(sys_colour_InfoBackground),
NULL
}, {
"InfoText",
SLEN("InfoText"),
0xff000000,
&nsoption_colour(sys_colour_InfoText),
NULL
}, {
"Menu",
SLEN("Menu"),
0xffaaaaaa,
&nsoption_colour(sys_colour_Menu),
NULL
}, {
"MenuText",
SLEN("MenuText"),
0xff000000,
&nsoption_colour(sys_colour_MenuText),
NULL
}, {
"Scrollbar",
SLEN("Scrollbar"),
0xffaaaaaa,
&nsoption_colour(sys_colour_Scrollbar),
NULL
}, {
"ThreeDDarkShadow",
SLEN("ThreeDDarkShadow"),
0xff555555,
&nsoption_colour(sys_colour_ThreeDDarkShadow),
NULL
}, {
"ThreeDFace",
SLEN("ThreeDFace"),
0xffdddddd,
&nsoption_colour(sys_colour_ThreeDFace),
NULL
}, {
"ThreeDHighlight",
SLEN("ThreeDHighlight"),
0xffaaaaaa,
&nsoption_colour(sys_colour_ThreeDHighlight),
NULL
}, {
"ThreeDLightShadow",
SLEN("ThreeDLightShadow"),
0xff999999,
&nsoption_colour(sys_colour_ThreeDLightShadow),
NULL
}, {
"ThreeDShadow",
SLEN("ThreeDShadow"),
0xff777777,
&nsoption_colour(sys_colour_ThreeDShadow),
NULL
}, {
"Window",
SLEN("Window"),
0xffaaaaaa,
&nsoption_colour(sys_colour_Window),
NULL
}, {
"WindowFrame",
SLEN("WindowFrame"),
0xff000000,
&nsoption_colour(sys_colour_WindowFrame),
NULL
}, {
 
"WindowText",
SLEN("WindowText"),
0xff000000,
&nsoption_colour(sys_colour_WindowText),
NULL
},
 
};
 
#define colour_list_len (sizeof(colour_list) / sizeof(struct gui_system_colour_ctx))
 
static struct gui_system_colour_ctx *gui_system_colour_pw = NULL;
 
 
bool gui_system_colour_init(void)
{
unsigned int ccount;
 
if (gui_system_colour_pw != NULL)
return false;
 
/* Intern colour strings */
for (ccount = 0; ccount < colour_list_len; ccount++) {
if (lwc_intern_string(colour_list[ccount].name,
colour_list[ccount].length,
&(colour_list[ccount].lwcstr)) != lwc_error_ok) {
return false;
}
}
 
/* pull in options if set (ie not transparent) */
for (ccount = 0; ccount < colour_list_len; ccount++) {
if (*(colour_list[ccount].option_colour) != 0) {
colour_list[ccount].colour = *(colour_list[ccount].option_colour);
}
}
 
gui_system_colour_pw = colour_list;
 
return true;
}
 
void gui_system_colour_finalize(void)
{
unsigned int ccount;
 
for (ccount = 0; ccount < colour_list_len; ccount++) {
lwc_string_unref(colour_list[ccount].lwcstr);
}
}
 
colour gui_system_colour_char(const char *name)
{
colour ret = 0xff00000;
unsigned int ccount;
 
for (ccount = 0; ccount < colour_list_len; ccount++) {
if (strcmp(name, colour_list[ccount].name) == 0) {
ret = colour_list[ccount].colour;
break;
}
}
return ret;
}
 
css_error gui_system_colour(void *pw, lwc_string *name, css_color *colour)
{
unsigned int ccount;
bool match;
 
for (ccount = 0; ccount < colour_list_len; ccount++) {
if (lwc_string_caseless_isequal(name,
colour_list[ccount].lwcstr,
&match) == lwc_error_ok && match) {
*colour = colour_list[ccount].colour;
return CSS_OK;
}
}
 
return CSS_INVALID;
}
/programs/network/netsurf/netsurf/framebuffer/thumbnail.c
0,0 → 1,99
/*
* Copyright 2008 Chris Young <chris@unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdbool.h>
 
#include <libnsfb.h>
#include <libnsfb_plot.h>
 
#include "utils/log.h"
#include "desktop/thumbnail.h"
#include "content/urldb.h"
 
#include "framebuffer/gui.h"
#include "framebuffer/fbtk.h"
#include "framebuffer/framebuffer.h"
 
bool
thumbnail_create(struct hlcache_handle *content,
struct bitmap *bitmap,
nsurl *url)
{
nsfb_t *tbm = (nsfb_t *)bitmap; /* target bitmap */
nsfb_t *bm; /* temporary bitmap */
nsfb_t *current; /* current main fb */
int width, height; /* target bitmap width height */
int cwidth, cheight;/* content width /height */
nsfb_bbox_t loc;
 
struct redraw_context ctx = {
.interactive = false,
.background_images = true,
.plot = &fb_plotters
};
 
 
nsfb_get_geometry(tbm, &width, &height, NULL);
 
LOG(("width %d, height %d", width, height));
 
/* Calculate size of buffer to render the content into */
/* We get the width from the content width, unless it exceeds 1024,
* in which case we use 1024. This means we never create excessively
* large render buffers for huge contents, which would eat memory and
* cripple performance. */
cwidth = min(content_get_width(content), 1024);
/* The height is set in proportion with the width, according to the
* aspect ratio of the required thumbnail. */
cheight = ((cwidth * height) + (width / 2)) / width;
 
/* create temporary surface */
bm = nsfb_new(NSFB_SURFACE_RAM);
if (bm == NULL) {
return false;
}
 
nsfb_set_geometry(bm, cwidth, cheight, NSFB_FMT_XBGR8888);
 
if (nsfb_init(bm) == -1) {
nsfb_free(bm);
return false;
}
 
current = framebuffer_set_surface(bm);
 
/* render the content into temporary surface */
thumbnail_redraw(content, cwidth, cheight, &ctx);
 
framebuffer_set_surface(current);
 
loc.x0 = 0;
loc.y0 = 0;
loc.x1 = width;
loc.y1 = height;
 
nsfb_plot_copy(bm, NULL, tbm, &loc);
 
nsfb_free(bm);
 
/* register the thumbnail with the URL */
if (url != NULL)
urldb_set_thumbnail(url, bitmap);
 
return true;
}
/programs/network/netsurf/netsurf/framebuffer/tree.c
0,0 → 1,45
/*
* Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include "desktop/tree.h"
#include "desktop/tree_url_node.h"
 
const char tree_directory_icon_name[] = "directory.png";
const char tree_content_icon_name[] = "content.png";
 
 
 
/**
* Translates a content_type to the name of a respective icon
*
* \param content_type content type
* \param buffer buffer for the icon name
*/
void tree_icon_name_from_content_type(char *buffer, content_type type)
{
// TODO: design/acquire icons
switch (type) {
case CONTENT_HTML:
case CONTENT_TEXTPLAIN:
case CONTENT_CSS:
case CONTENT_IMAGE:
default:
sprintf(buffer, tree_content_icon_name);
break;
}
}
/programs/network/netsurf/netsurf/image/bitmap.h
0,0 → 1,87
/*
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Generic bitmap handling (interface).
*
* This interface wraps the native platform-specific image format, so that
* portable image convertors can be written.
*
* Bitmaps are required to be 32bpp with components in the order RR GG BB AA.
*
* For example, an opaque 1x1 pixel image would yield the following bitmap
* data:
*
* Red : 0xff 0x00 0x00 0x00
* Green: 0x00 0xff 0x00 0x00
* Blue : 0x00 0x00 0xff 0x00
*
* Any attempt to read pixels by casting bitmap data to uint32_t or similar
* will need to cater for the order of bytes in a word being different on
* big and little endian systems. To avoid confusion, it is recommended
* that pixel data is loaded as follows:
*
* uint32_t read_pixel(const uint8_t *bmp)
* {
* // red green blue alpha
* return bmp[0] | (bmp[1] << 8) | (bmp[2] << 16) | (bmp[3] << 24);
* }
*
* and *not* as follows:
*
* uint32_t read_pixel(const uint8_t *bmp)
* {
* return *((uint32_t *) bmp);
* }
*/
 
#ifndef _NETSURF_IMAGE_BITMAP_H_
#define _NETSURF_IMAGE_BITMAP_H_
 
#include <stdbool.h>
#include <stdlib.h>
 
#define BITMAP_NEW 0
#define BITMAP_OPAQUE (1 << 0) /** image is opaque */
#define BITMAP_MODIFIED (1 << 1) /** buffer has been modified */
#define BITMAP_PERSISTENT (1 << 2) /** retain between sessions */
#define BITMAP_CLEAR_MEMORY (1 << 3) /** memory should be wiped */
#define BITMAP_READY (1 << 4) /** fully initialised */
 
#define BITMAP_SAVE_FULL_ALPHA (1 << 0) /** save with full alpha channel (if not opaque) */
 
struct content;
 
/** An opaque image. */
struct bitmap;
 
void *bitmap_create(int width, int height, unsigned int state);
void bitmap_set_opaque(void *bitmap, bool opaque);
bool bitmap_test_opaque(void *bitmap);
bool bitmap_get_opaque(void *bitmap);
unsigned char *bitmap_get_buffer(void *bitmap);
size_t bitmap_get_rowstride(void *bitmap);
size_t bitmap_get_bpp(void *bitmap);
void bitmap_destroy(void *bitmap);
bool bitmap_save(void *bitmap, const char *path, unsigned flags);
void bitmap_modified(void *bitmap);
 
int bitmap_get_width(void *bitmap);
int bitmap_get_height(void *bitmap);
 
#endif
/programs/network/netsurf/netsurf/image/bmp.c
0,0 → 1,289
/*
* Copyright 2006 Richard Wilson <info@tinct.net>
* Copyright 2008 Sean Fox <dyntryx@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/bmp (implementation)
*/
 
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <libnsbmp.h>
 
#include "utils/config.h"
#include "content/content_protected.h"
#include "content/hlcache.h"
#include "desktop/plotters.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
 
#include "image/bitmap.h"
#include "image/bmp.h"
 
typedef struct nsbmp_content {
struct content base;
 
bmp_image *bmp; /** BMP image data */
 
struct bitmap *bitmap; /**< Created NetSurf bitmap */
} nsbmp_content;
 
static nserror nsbmp_create_bmp_data(nsbmp_content *bmp)
{
union content_msg_data msg_data;
 
bmp->bmp = calloc(sizeof(struct bmp_image), 1);
if (bmp->bmp == NULL) {
msg_data.error = messages_get("NoMemory");
content_broadcast(&bmp->base, CONTENT_MSG_ERROR, msg_data);
return NSERROR_NOMEM;
}
 
bmp_create(bmp->bmp, &bmp_bitmap_callbacks);
 
return NSERROR_OK;
}
 
 
static nserror nsbmp_create(const content_handler *handler,
lwc_string *imime_type, const struct http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
nsbmp_content *bmp;
nserror error;
 
bmp = calloc(1, sizeof(nsbmp_content));
if (bmp == NULL)
return NSERROR_NOMEM;
 
error = content__init(&bmp->base, handler, imime_type, params,
llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(bmp);
return error;
}
 
error = nsbmp_create_bmp_data(bmp);
if (error != NSERROR_OK) {
free(bmp);
return error;
}
 
*c = (struct content *) bmp;
 
return NSERROR_OK;
}
 
/**
* Callback for libnsbmp; forwards the call to bitmap_create()
*
* \param width width of image in pixels
* \param height width of image in pixels
* \param state a flag word indicating the initial state
* \return an opaque struct bitmap, or NULL on memory exhaustion
*/
static void *nsbmp_bitmap_create(int width, int height, unsigned int bmp_state)
{
unsigned int bitmap_state = BITMAP_NEW;
 
/* set bitmap state based on bmp state */
bitmap_state |= (bmp_state & BMP_OPAQUE) ? BITMAP_OPAQUE : 0;
bitmap_state |= (bmp_state & BMP_CLEAR_MEMORY) ?
BITMAP_CLEAR_MEMORY : 0;
 
/* return the created bitmap */
return bitmap_create(width, height, bitmap_state);
}
 
/* The Bitmap callbacks function table;
* necessary for interaction with nsbmplib.
*/
bmp_bitmap_callback_vt bmp_bitmap_callbacks = {
.bitmap_create = nsbmp_bitmap_create,
.bitmap_destroy = bitmap_destroy,
.bitmap_get_buffer = bitmap_get_buffer,
.bitmap_get_bpp = bitmap_get_bpp
};
 
static bool nsbmp_convert(struct content *c)
{
nsbmp_content *bmp = (nsbmp_content *) c;
bmp_result res;
union content_msg_data msg_data;
uint32_t swidth;
const char *data;
unsigned long size;
char *title;
 
/* set the bmp data */
data = content__get_source_data(c, &size);
 
/* analyse the BMP */
res = bmp_analyse(bmp->bmp, size, (unsigned char *) data);
switch (res) {
case BMP_OK:
break;
case BMP_INSUFFICIENT_MEMORY:
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
case BMP_INSUFFICIENT_DATA:
case BMP_DATA_ERROR:
msg_data.error = messages_get("BadBMP");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
/* Store our content width and description */
c->width = bmp->bmp->width;
c->height = bmp->bmp->height;
swidth = bmp->bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bmp->bitmap) *
bmp->bmp->width;
c->size += (swidth * bmp->bmp->height) + 16 + 44;
 
/* set title text */
title = messages_get_buff("BMPTitle",
nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
c->width, c->height);
if (title != NULL) {
content__set_title(c, title);
free(title);
}
 
/* exit as a success */
bmp->bitmap = bmp->bmp->bitmap;
bitmap_modified(bmp->bitmap);
 
content_set_ready(c);
content_set_done(c);
 
/* Done: update status bar */
content_set_status(c, "");
return true;
}
 
static bool nsbmp_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
nsbmp_content *bmp = (nsbmp_content *) c;
bitmap_flags_t flags = BITMAPF_NONE;
 
if (bmp->bmp->decoded == false)
if (bmp_decode(bmp->bmp) != BMP_OK)
return false;
 
bmp->bitmap = bmp->bmp->bitmap;
 
if (data->repeat_x)
flags |= BITMAPF_REPEAT_X;
if (data->repeat_y)
flags |= BITMAPF_REPEAT_Y;
 
return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
bmp->bitmap, data->background_colour, flags);
}
 
 
static void nsbmp_destroy(struct content *c)
{
nsbmp_content *bmp = (nsbmp_content *) c;
 
bmp_finalise(bmp->bmp);
free(bmp->bmp);
}
 
 
static nserror nsbmp_clone(const struct content *old, struct content **newc)
{
nsbmp_content *new_bmp;
nserror error;
 
new_bmp = calloc(1, sizeof(nsbmp_content));
if (new_bmp == NULL)
return NSERROR_NOMEM;
 
error = content__clone(old, &new_bmp->base);
if (error != NSERROR_OK) {
content_destroy(&new_bmp->base);
return error;
}
 
/* We "clone" the old content by replaying creation and conversion */
error = nsbmp_create_bmp_data(new_bmp);
if (error != NSERROR_OK) {
content_destroy(&new_bmp->base);
return error;
}
 
if (old->status == CONTENT_STATUS_READY ||
old->status == CONTENT_STATUS_DONE) {
if (nsbmp_convert(&new_bmp->base) == false) {
content_destroy(&new_bmp->base);
return NSERROR_CLONE_FAILED;
}
}
 
*newc = (struct content *) new_bmp;
 
return NSERROR_OK;
}
 
static void *nsbmp_get_internal(const struct content *c, void *context)
{
nsbmp_content *bmp = (nsbmp_content *)c;
 
return bmp->bitmap;
}
 
static content_type nsbmp_content_type(void)
{
return CONTENT_IMAGE;
}
 
 
static const content_handler nsbmp_content_handler = {
.create = nsbmp_create,
.data_complete = nsbmp_convert,
.destroy = nsbmp_destroy,
.redraw = nsbmp_redraw,
.clone = nsbmp_clone,
.get_internal = nsbmp_get_internal,
.type = nsbmp_content_type,
.no_share = false,
};
 
static const char *nsbmp_types[] = {
"application/bmp",
"application/preview",
"application/x-bmp",
"application/x-win-bitmap",
"image/bmp",
"image/ms-bmp",
"image/x-bitmap",
"image/x-bmp",
"image/x-ms-bmp",
"image/x-win-bitmap",
"image/x-windows-bmp",
"image/x-xbitmap"
};
 
CONTENT_FACTORY_REGISTER_TYPES(nsbmp, nsbmp_types, nsbmp_content_handler);
/programs/network/netsurf/netsurf/image/bmp.h
0,0 → 1,35
/*
* Copyright 2006 Richard Wilson <info@tinct.net>
* Copyright 2008 Sean Fox <dyntryx@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/bmp (interface).
*/
 
#ifndef _NETSURF_IMAGE_BMP_H_
#define _NETSURF_IMAGE_BMP_H_
 
#include <libnsbmp.h>
 
#include "image/bitmap.h"
 
extern bmp_bitmap_callback_vt bmp_bitmap_callbacks; /** Only to be used by ICO code. */
 
nserror nsbmp_init(void);
 
#endif
/programs/network/netsurf/netsurf/image/gif.c
0,0 → 1,427
/*
* Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
* Copyright 2008 Sean Fox <dyntryx@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/gif (implementation)
*
* All GIFs are dynamically decompressed using the routines that gifread.c
* provides. Whilst this allows support for progressive decoding, it is
* not implemented here as NetSurf currently does not provide such support.
*
* [rjw] - Sun 4th April 2004
*/
 
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <libnsgif.h>
 
#include "utils/config.h"
#include "content/content_protected.h"
#include "content/hlcache.h"
#include "desktop/options.h"
#include "desktop/plotters.h"
#include "image/image.h"
#include "image/bitmap.h"
#include "image/gif.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/schedule.h"
#include "utils/utils.h"
 
typedef struct nsgif_content {
struct content base;
 
struct gif_animation *gif; /**< GIF animation data */
int current_frame; /**< current frame to display [0...(max-1)] */
} nsgif_content;
 
 
/**
* Callback for libnsgif; forwards the call to bitmap_create()
*
* \param width width of image in pixels
* \param height width of image in pixels
* \return an opaque struct bitmap, or NULL on memory exhaustion
*/
static void *nsgif_bitmap_create(int width, int height)
{
return bitmap_create(width, height, BITMAP_NEW);
}
 
/* The Bitmap callbacks function table;
* necessary for interaction with nsgiflib.
*/
static gif_bitmap_callback_vt gif_bitmap_callbacks = {
.bitmap_create = nsgif_bitmap_create,
.bitmap_destroy = bitmap_destroy,
.bitmap_get_buffer = bitmap_get_buffer,
.bitmap_set_opaque = bitmap_set_opaque,
.bitmap_test_opaque = bitmap_test_opaque,
.bitmap_modified = bitmap_modified
};
 
static nserror nsgif_create_gif_data(nsgif_content *c)
{
union content_msg_data msg_data;
 
/* Initialise our data structure */
c->gif = calloc(sizeof(gif_animation), 1);
if (c->gif == NULL) {
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return NSERROR_NOMEM;
}
gif_create(c->gif, &gif_bitmap_callbacks);
return NSERROR_OK;
}
 
 
 
static nserror nsgif_create(const content_handler *handler,
lwc_string *imime_type, const struct http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
nsgif_content *result;
nserror error;
 
result = calloc(1, sizeof(nsgif_content));
if (result == NULL)
return NSERROR_NOMEM;
 
error = content__init(&result->base, handler, imime_type, params,
llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(result);
return error;
}
 
error = nsgif_create_gif_data(result);
if (error != NSERROR_OK) {
free(result);
return error;
}
 
*c = (struct content *) result;
 
return NSERROR_OK;
}
 
/**
* Performs any necessary animation.
*
* \param p The content to animate
*/
static void nsgif_animate(void *p)
{
nsgif_content *gif = p;
union content_msg_data data;
int delay;
int f;
 
/* Advance by a frame, updating the loop count accordingly */
gif->current_frame++;
if (gif->current_frame == (int)gif->gif->frame_count_partial) {
gif->current_frame = 0;
 
/* A loop count of 0 has a special meaning of infinite */
if (gif->gif->loop_count != 0) {
gif->gif->loop_count--;
if (gif->gif->loop_count == 0) {
gif->current_frame =
gif->gif->frame_count_partial - 1;
gif->gif->loop_count = -1;
}
}
}
 
/* Continue animating if we should */
if (gif->gif->loop_count >= 0) {
delay = gif->gif->frames[gif->current_frame].frame_delay;
if (delay < nsoption_int(minimum_gif_delay))
delay = nsoption_int(minimum_gif_delay);
schedule(delay, nsgif_animate, gif);
}
 
if ((!nsoption_bool(animate_images)) ||
(!gif->gif->frames[gif->current_frame].display)) {
return;
}
 
/* area within gif to redraw */
f = gif->current_frame;
data.redraw.x = gif->gif->frames[f].redraw_x;
data.redraw.y = gif->gif->frames[f].redraw_y;
data.redraw.width = gif->gif->frames[f].redraw_width;
data.redraw.height = gif->gif->frames[f].redraw_height;
 
/* redraw background (true) or plot on top (false) */
if (gif->current_frame > 0) {
data.redraw.full_redraw =
gif->gif->frames[f - 1].redraw_required;
/* previous frame needed clearing: expand the redraw area to
* cover it */
if (data.redraw.full_redraw) {
if (data.redraw.x >
(int)(gif->gif->frames[f - 1].redraw_x)) {
data.redraw.width += data.redraw.x -
gif->gif->frames[f - 1].redraw_x;
data.redraw.x =
gif->gif->frames[f - 1].redraw_x;
}
if (data.redraw.y >
(int)(gif->gif->frames[f - 1].redraw_y)) {
data.redraw.height += (data.redraw.y -
gif->gif->frames[f - 1].redraw_y);
data.redraw.y =
gif->gif->frames[f - 1].redraw_y;
}
if ((int)(gif->gif->frames[f - 1].redraw_x +
gif->gif->frames[f - 1].redraw_width) >
(data.redraw.x + data.redraw.width))
data.redraw.width =
gif->gif->frames[f - 1].redraw_x -
data.redraw.x +
gif->gif->frames[f - 1].redraw_width;
if ((int)(gif->gif->frames[f - 1].redraw_y +
gif->gif->frames[f - 1].redraw_height) >
(data.redraw.y + data.redraw.height))
data.redraw.height =
gif->gif->frames[f - 1].redraw_y -
data.redraw.y +
gif->gif->frames[f - 1].redraw_height;
}
} else {
/* do advanced check */
if ((data.redraw.x == 0) && (data.redraw.y == 0) &&
(data.redraw.width == (int)(gif->gif->width)) &&
(data.redraw.height == (int)(gif->gif->height))) {
data.redraw.full_redraw = !gif->gif->frames[f].opaque;
} else {
data.redraw.full_redraw = true;
data.redraw.x = 0;
data.redraw.y = 0;
data.redraw.width = gif->gif->width;
data.redraw.height = gif->gif->height;
}
}
 
/* other data */
data.redraw.object = (struct content *) gif;
data.redraw.object_x = 0;
data.redraw.object_y = 0;
data.redraw.object_width = gif->base.width;
data.redraw.object_height = gif->base.height;
 
content_broadcast(&gif->base, CONTENT_MSG_REDRAW, data);
}
 
static bool nsgif_convert(struct content *c)
{
nsgif_content *gif = (nsgif_content *) c;
int res;
union content_msg_data msg_data;
const char *data;
unsigned long size;
char *title;
 
/* Get the animation */
data = content__get_source_data(c, &size);
 
/* Initialise the GIF */
do {
res = gif_initialise(gif->gif, size, (unsigned char *) data);
if (res != GIF_OK && res != GIF_WORKING &&
res != GIF_INSUFFICIENT_FRAME_DATA) {
switch (res) {
case GIF_FRAME_DATA_ERROR:
case GIF_INSUFFICIENT_DATA:
case GIF_DATA_ERROR:
msg_data.error = messages_get("BadGIF");
break;
case GIF_INSUFFICIENT_MEMORY:
msg_data.error = messages_get("NoMemory");
break;
}
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
} while (res != GIF_OK && res != GIF_INSUFFICIENT_FRAME_DATA);
 
/* Abort on bad GIFs */
if ((gif->gif->frame_count_partial == 0) || (gif->gif->width == 0) ||
(gif->gif->height == 0)) {
msg_data.error = messages_get("BadGIF");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
/* Store our content width, height and calculate size */
c->width = gif->gif->width;
c->height = gif->gif->height;
c->size += (gif->gif->width * gif->gif->height * 4) + 16 + 44;
 
/* set title text */
title = messages_get_buff("GIFTitle",
nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
c->width, c->height);
if (title != NULL) {
content__set_title(c, title);
free(title);
}
 
/* Schedule the animation if we have one */
gif->current_frame = 0;
if (gif->gif->frame_count_partial > 1)
schedule(gif->gif->frames[0].frame_delay, nsgif_animate, c);
 
/* Exit as a success */
content_set_ready(c);
content_set_done(c);
 
/* Done: update status bar */
content_set_status(c, "");
return true;
}
 
 
/**
* Updates the GIF bitmap to display the current frame
*
* \param c the content to update
*/
static gif_result nsgif_get_frame(nsgif_content *gif)
{
int previous_frame, current_frame, frame;
gif_result res = GIF_OK;
 
current_frame = gif->current_frame;
if (!nsoption_bool(animate_images)) {
current_frame = 0;
}
 
if (current_frame < gif->gif->decoded_frame)
previous_frame = 0;
else
previous_frame = gif->gif->decoded_frame + 1;
 
for (frame = previous_frame; frame <= current_frame; frame++) {
res = gif_decode_frame(gif->gif, frame);
}
 
return res;
}
 
static bool nsgif_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
nsgif_content *gif = (nsgif_content *) c;
 
if (gif->current_frame != gif->gif->decoded_frame) {
if (nsgif_get_frame(gif) != GIF_OK) {
return false;
}
}
 
return image_bitmap_plot(gif->gif->frame_image, data, clip, ctx);
}
 
 
static void nsgif_destroy(struct content *c)
{
nsgif_content *gif = (nsgif_content *) c;
 
/* Free all the associated memory buffers */
schedule_remove(nsgif_animate, c);
gif_finalise(gif->gif);
free(gif->gif);
}
 
 
static nserror nsgif_clone(const struct content *old, struct content **newc)
{
nsgif_content *gif;
nserror error;
 
gif = calloc(1, sizeof(nsgif_content));
if (gif == NULL)
return NSERROR_NOMEM;
 
error = content__clone(old, &gif->base);
if (error != NSERROR_OK) {
content_destroy(&gif->base);
return error;
}
 
/* Simply replay creation and conversion of content */
error = nsgif_create_gif_data(gif);
if (error != NSERROR_OK) {
content_destroy(&gif->base);
return error;
}
 
if (old->status == CONTENT_STATUS_READY ||
old->status == CONTENT_STATUS_DONE) {
if (nsgif_convert(&gif->base) == false) {
content_destroy(&gif->base);
return NSERROR_CLONE_FAILED;
}
}
 
*newc = (struct content *) gif;
 
return NSERROR_OK;
}
 
static void *nsgif_get_internal(const struct content *c, void *context)
{
nsgif_content *gif = (nsgif_content *) c;
 
if (gif->current_frame != gif->gif->decoded_frame) {
if (nsgif_get_frame(gif) != GIF_OK)
return NULL;
}
 
return gif->gif->frame_image;
}
 
static content_type nsgif_content_type(void)
{
return CONTENT_IMAGE;
}
 
static const content_handler nsgif_content_handler = {
.create = nsgif_create,
.data_complete = nsgif_convert,
.destroy = nsgif_destroy,
.redraw = nsgif_redraw,
.clone = nsgif_clone,
.get_internal = nsgif_get_internal,
.type = nsgif_content_type,
.no_share = false,
};
 
static const char *nsgif_types[] = {
"image/gif"
};
 
CONTENT_FACTORY_REGISTER_TYPES(nsgif, nsgif_types, nsgif_content_handler);
/programs/network/netsurf/netsurf/image/gif.h
0,0 → 1,29
/*
* Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
* Copyright 2008 Sean Fox <dyntryx@gmail.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/gif (interface).
*/
 
#ifndef _NETSURF_IMAGE_GIF_H_
#define _NETSURF_IMAGE_GIF_H_
 
nserror nsgif_init(void);
 
#endif
/programs/network/netsurf/netsurf/image/ico.c
0,0 → 1,277
/*
* Copyright 2006 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/ico (implementation)
*/
 
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <libnsbmp.h>
#include "utils/config.h"
#include "content/content_protected.h"
#include "content/hlcache.h"
#include "desktop/plotters.h"
#include "image/bitmap.h"
#include "image/bmp.h"
#include "image/ico.h"
#include "image/image.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
 
typedef struct nsico_content {
struct content base;
 
struct ico_collection *ico; /** ICO collection data */
 
} nsico_content;
 
 
static nserror nsico_create_ico_data(nsico_content *c)
{
union content_msg_data msg_data;
 
c->ico = calloc(sizeof(ico_collection), 1);
if (c->ico == NULL) {
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return NSERROR_NOMEM;
}
ico_collection_create(c->ico, &bmp_bitmap_callbacks);
return NSERROR_OK;
}
 
 
static nserror nsico_create(const content_handler *handler,
lwc_string *imime_type, const struct http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
nsico_content *result;
nserror error;
 
result = calloc(1, sizeof(nsico_content));
if (result == NULL)
return NSERROR_NOMEM;
 
error = content__init(&result->base, handler, imime_type, params,
llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(result);
return error;
}
 
error = nsico_create_ico_data(result);
if (error != NSERROR_OK) {
free(result);
return error;
}
 
*c = (struct content *) result;
 
return NSERROR_OK;
}
 
 
 
static bool nsico_convert(struct content *c)
{
nsico_content *ico = (nsico_content *) c;
struct bmp_image *bmp;
bmp_result res;
union content_msg_data msg_data;
const char *data;
unsigned long size;
char *title;
 
/* set the ico data */
data = content__get_source_data(c, &size);
 
/* analyse the ico */
res = ico_analyse(ico->ico, size, (unsigned char *) data);
 
switch (res) {
case BMP_OK:
break;
case BMP_INSUFFICIENT_MEMORY:
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
case BMP_INSUFFICIENT_DATA:
case BMP_DATA_ERROR:
msg_data.error = messages_get("BadICO");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
/* Store our content width, height and calculate size */
c->width = ico->ico->width;
c->height = ico->ico->height;
c->size += (ico->ico->width * ico->ico->height * 4) + 16 + 44;
 
/* set title text */
title = messages_get_buff("ICOTitle",
nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
c->width, c->height);
if (title != NULL) {
content__set_title(c, title);
free(title);
}
 
/* select largest icon to ensure one can be selected */
bmp = ico_find(ico->ico, 255, 255);
if (bmp == NULL) {
/* return error */
LOG(("Failed to select icon"));
return false;
}
 
content_set_ready(c);
content_set_done(c);
 
/* Done: update status bar */
content_set_status(c, "");
return true;
}
 
 
static bool nsico_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
nsico_content *ico = (nsico_content *)c;
struct bmp_image *bmp;
 
/* select most appropriate sized icon for size */
bmp = ico_find(ico->ico, data->width, data->height);
if (bmp == NULL) {
/* return error */
LOG(("Failed to select icon"));
return false;
}
 
/* ensure its decided */
if (bmp->decoded == false) {
if (bmp_decode(bmp) != BMP_OK) {
return false;
} else {
LOG(("Decoding bitmap"));
bitmap_modified(bmp->bitmap);
}
 
}
 
return image_bitmap_plot(bmp->bitmap, data, clip, ctx);
}
 
 
static void nsico_destroy(struct content *c)
{
nsico_content *ico = (nsico_content *) c;
 
ico_finalise(ico->ico);
free(ico->ico);
}
 
static nserror nsico_clone(const struct content *old, struct content **newc)
{
nsico_content *ico;
nserror error;
 
ico = calloc(1, sizeof(nsico_content));
if (ico == NULL)
return NSERROR_NOMEM;
 
error = content__clone(old, &ico->base);
if (error != NSERROR_OK) {
content_destroy(&ico->base);
return error;
}
 
/* Simply replay creation and conversion */
error = nsico_create_ico_data(ico);
if (error != NSERROR_OK) {
content_destroy(&ico->base);
return error;
}
 
if (old->status == CONTENT_STATUS_READY ||
old->status == CONTENT_STATUS_DONE) {
if (nsico_convert(&ico->base) == false) {
content_destroy(&ico->base);
return NSERROR_CLONE_FAILED;
}
}
 
*newc = (struct content *) ico;
 
return NSERROR_OK;
}
 
static void *nsico_get_internal(const struct content *c, void *context)
{
nsico_content *ico = (nsico_content *) c;
/* TODO: Pick best size for purpose.
* Currently assumes it's for a URL bar. */
struct bmp_image *bmp;
 
bmp = ico_find(ico->ico, 16, 16);
if (bmp == NULL) {
/* return error */
LOG(("Failed to select icon"));
return NULL;
}
 
if (bmp->decoded == false) {
if (bmp_decode(bmp) != BMP_OK) {
return NULL;
} else {
bitmap_modified(bmp->bitmap);
}
}
 
return bmp->bitmap;
}
 
static content_type nsico_content_type(void)
{
return CONTENT_IMAGE;
}
 
static const content_handler nsico_content_handler = {
.create = nsico_create,
.data_complete = nsico_convert,
.destroy = nsico_destroy,
.redraw = nsico_redraw,
.clone = nsico_clone,
.get_internal = nsico_get_internal,
.type = nsico_content_type,
.no_share = false,
};
 
static const char *nsico_types[] = {
"application/ico",
"application/x-ico",
"image/ico",
"image/vnd.microsoft.icon",
"image/x-icon"
};
 
CONTENT_FACTORY_REGISTER_TYPES(nsico, nsico_types, nsico_content_handler);
/programs/network/netsurf/netsurf/image/ico.h
0,0 → 1,28
/*
* Copyright 2006 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/ico (interface).
*/
 
#ifndef _NETSURF_IMAGE_ICO_H_
#define _NETSURF_IMAGE_ICO_H_
 
nserror nsico_init(void);
 
#endif
/programs/network/netsurf/netsurf/image/image.c
0,0 → 1,181
/*
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <assert.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
 
#include "utils/errors.h"
#include "utils/config.h"
#include "utils/log.h"
#include "desktop/plotters.h"
#include "image/bitmap.h"
 
#include "image/bmp.h"
#include "image/gif.h"
#include "image/ico.h"
#include "image/jpeg.h"
#include "image/mng.h"
#include "image/nssprite.h"
#include "image/png.h"
#include "image/rsvg.h"
#include "image/svg.h"
#include "image/webp.h"
 
#include "image/image.h"
 
/**
* Initialise image content handlers
*
* \return NSERROR_OK on success, appropriate error otherwise.
*/
nserror image_init(void)
{
nserror error;
 
#ifdef WITH_BMP
error = nsbmp_init();
if (error != NSERROR_OK)
return error;
#endif
 
#ifdef WITH_GIF
error = nsgif_init();
if (error != NSERROR_OK)
return error;
#endif
 
#ifdef WITH_BMP
error = nsico_init();
if (error != NSERROR_OK)
return error;
#endif
 
#ifdef WITH_JPEG
error = nsjpeg_init();
if (error != NSERROR_OK)
return error;
#endif
 
#ifdef WITH_MNG
error = nsmng_init();
if (error != NSERROR_OK)
return error;
 
error = nsjpng_init();
if (error != NSERROR_OK)
return error;
#endif
 
#ifdef WITH_PNG
/* Prefer libpng over libmng for pngs by registering later */
error = nspng_init();
if (error != NSERROR_OK)
return error;
#endif
 
#ifdef WITH_NSSPRITE
error = nssprite_init();
if (error != NSERROR_OK)
return error;
#endif
 
/* Prefer rsvg over libsvgtiny for svgs */
#ifdef WITH_NS_SVG
error = svg_init();
if (error != NSERROR_OK)
return error;
#endif
#ifdef WITH_RSVG
error = nsrsvg_init();
if (error != NSERROR_OK)
return error;
#endif
 
#ifdef WITH_WEBP
error = webp_init();
if (error != NSERROR_OK)
return error;
#endif /* WITH_WEBP */
 
return NSERROR_OK;
}
 
 
bool image_bitmap_plot(struct bitmap *bitmap,
struct content_redraw_data *data,
const struct rect *clip,
const struct redraw_context *ctx)
{
bitmap_flags_t flags = BITMAPF_NONE;
 
int width;
int height;
unsigned char *pixel;
plot_style_t fill_style;
struct rect area;
 
width = bitmap_get_width(bitmap);
if (width == 1) {
height = bitmap_get_height(bitmap);
if (height == 1) {
/* optimise 1x1 bitmap plot */
pixel = bitmap_get_buffer(bitmap);
fill_style.fill_colour = pixel_to_colour(pixel);
 
if (bitmap_get_opaque(bitmap) ||
((fill_style.fill_colour & 0xff000000) == 0xff000000)) {
 
area = *clip;
 
if (data->repeat_x != true) {
area.x0 = data->x;
area.x1 = data->x + data->width;
}
 
if (data->repeat_y != true) {
area.y0 = data->y;
area.y1 = data->y + data->height;
}
 
fill_style.stroke_type = PLOT_OP_TYPE_NONE;
fill_style.fill_type = PLOT_OP_TYPE_SOLID;
 
return ctx->plot->rectangle(area.x0, area.y0,
area.x1, area.y1,
&fill_style);
 
} else if ((fill_style.fill_colour & 0xff000000) == 0) {
/* transparent pixel used as spacer, skip it */
return true;
}
}
}
/* do the plot */
if (data->repeat_x)
flags |= BITMAPF_REPEAT_X;
if (data->repeat_y)
flags |= BITMAPF_REPEAT_Y;
 
return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
bitmap, data->background_colour, flags);
 
}
/programs/network/netsurf/netsurf/image/image.h
0,0 → 1,43
/*
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Initialisation/finalisation of image handlers.
*/
 
#ifndef NETSURF_IMAGE_IMAGE_H_
#define NETSURF_IMAGE_IMAGE_H_
 
#include "utils/errors.h"
 
/** Initialise the content handlers for image types.
*/
nserror image_init(void);
 
/** Common image content handler bitmap plot call.
*
* This plots the specified bitmap controlled by the redraw context
* and specific content redraw data. It is a helper specifically
* provided for image content handlers redraw callback.
*/
bool image_bitmap_plot(struct bitmap *bitmap,
struct content_redraw_data *data,
const struct rect *clip,
const struct redraw_context *ctx);
 
#endif
/programs/network/netsurf/netsurf/image/image_cache.c
0,0 → 1,800
/*
* Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <assert.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
 
#include "utils/schedule.h"
#include "utils/log.h"
#include "content/content_protected.h"
 
#include "image/image_cache.h"
#include "image/image.h"
 
/** Age of an entry within the cache
*
* type deffed away so it can be readily changed later perhaps to a
* wallclock time structure.
*/
typedef unsigned int cache_age;
 
/** Image cache entry
*/
struct image_cache_entry_s {
struct image_cache_entry_s *next; /* next cache entry in list */
struct image_cache_entry_s *prev; /* previous cache entry in list */
 
struct content *content; /** content is used as a key */
struct bitmap *bitmap; /** associated bitmap entry */
/** Conversion routine */
image_cache_convert_fn *convert;
 
/* Statistics for replacement algorithm */
 
unsigned int redraw_count; /**< number of times object has been drawn */
cache_age redraw_age; /**< Age of last redraw */
size_t bitmap_size; /**< size if storage occupied by bitmap */
cache_age bitmap_age; /**< Age of last conversion to a bitmap by cache*/
 
int conversion_count; /**< Number of times image has been converted */
};
 
/** Current state of the cache.
*
* Global state of the cache. entries "age" is determined based on a
* monotonically incrementing operation count. This avoids issues with
* using wall clock time while allowing the LRU algorithm to work
* sensibly.
*/
struct image_cache_s {
/** Cache parameters */
struct image_cache_parameters params;
 
/** The "age" of the current operation */
cache_age current_age;
 
/* The objects the cache holds */
struct image_cache_entry_s *entries;
 
 
/* Statistics for management algorithm */
 
/** total size of bitmaps currently allocated */
size_t total_bitmap_size;
 
/** Total count of bitmaps currently allocated */
int bitmap_count;
 
/** Maximum size of bitmaps allocated at any one time */
size_t max_bitmap_size;
/** The number of objects when maximum bitmap usage occoured */
int max_bitmap_size_count;
 
/** Maximum count of bitmaps allocated at any one time */
int max_bitmap_count;
/** The size of the bitmaps when the max count occoured */
size_t max_bitmap_count_size;
 
/** Bitmap was not available at plot time required conversion */
int miss_count;
uint64_t miss_size;
/** Bitmap was available at plot time required no conversion */
int hit_count;
uint64_t hit_size;
/** Bitmap was not available at plot time and required
* conversion which failed.
*/
int fail_count;
uint64_t fail_size;
 
/* Cache entry freed without ever being redrawn */
int total_unrendered;
/** Bitmap was available but never required - wasted conversions */
int specultive_miss_count;
 
/** Total number of additional (after the first) conversions */
int total_extra_conversions;
/** counts total number of images with more than one conversion */
int total_extra_conversions_count;
 
/** Bitmap with most conversions was converted this many times */
int peak_conversions;
/** Size of bitmap with most conversions */
unsigned int peak_conversions_size;
};
 
/** image cache state */
static struct image_cache_s *image_cache = NULL;
 
 
/** Find the nth cache entry
*/
static struct image_cache_entry_s *image_cache__findn(int entryn)
{
struct image_cache_entry_s *found;
 
found = image_cache->entries;
while ((found != NULL) && (entryn > 0)) {
entryn--;
found = found->next;
}
return found;
}
 
/** Find the cache entry for a content
*/
static struct image_cache_entry_s *image_cache__find(const struct content *c)
{
struct image_cache_entry_s *found;
 
found = image_cache->entries;
while ((found != NULL) && (found->content != c)) {
found = found->next;
}
return found;
}
 
static void image_cache_stats_bitmap_add(struct image_cache_entry_s *centry)
{
centry->bitmap_age = image_cache->current_age;
centry->conversion_count++;
 
image_cache->total_bitmap_size += centry->bitmap_size;
image_cache->bitmap_count++;
 
if (image_cache->total_bitmap_size > image_cache->max_bitmap_size) {
image_cache->max_bitmap_size = image_cache->total_bitmap_size;
image_cache->max_bitmap_size_count = image_cache->bitmap_count;
 
}
 
if (image_cache->bitmap_count > image_cache->max_bitmap_count) {
image_cache->max_bitmap_count = image_cache->bitmap_count;
image_cache->max_bitmap_count_size = image_cache->total_bitmap_size;
}
 
if (centry->conversion_count == 2) {
image_cache->total_extra_conversions_count++;
}
 
if (centry->conversion_count > 1) {
image_cache->total_extra_conversions++;
}
 
if ((centry->conversion_count > image_cache->peak_conversions) ||
(centry->conversion_count == image_cache->peak_conversions &&
centry->bitmap_size > image_cache->peak_conversions_size)) {
image_cache->peak_conversions = centry->conversion_count;
image_cache->peak_conversions_size = centry->bitmap_size;
}
}
 
static void image_cache__link(struct image_cache_entry_s *centry)
{
centry->next = image_cache->entries;
centry->prev = NULL;
if (centry->next != NULL) {
centry->next->prev = centry;
}
image_cache->entries = centry;
}
 
static void image_cache__unlink(struct image_cache_entry_s *centry)
{
/* unlink entry */
if (centry->prev == NULL) {
/* first in list */
if (centry->next != NULL) {
centry->next->prev = centry->prev;
image_cache->entries = centry->next;
} else {
/* empty list */
image_cache->entries = NULL;
}
} else {
centry->prev->next = centry->next;
 
if (centry->next != NULL) {
centry->next->prev = centry->prev;
}
}
}
 
static void image_cache__free_bitmap(struct image_cache_entry_s *centry)
{
if (centry->bitmap != NULL) {
#ifdef IMAGE_CACHE_VERBOSE
LOG(("Freeing bitmap %p size %d age %d redraw count %d",
centry->bitmap,
centry->bitmap_size,
image_cache->current_age - centry->bitmap_age,
centry->redraw_count));
#endif
bitmap_destroy(centry->bitmap);
centry->bitmap = NULL;
image_cache->total_bitmap_size -= centry->bitmap_size;
image_cache->bitmap_count--;
if (centry->redraw_count == 0) {
image_cache->specultive_miss_count++;
}
}
 
}
 
/* free cache entry */
static void image_cache__free_entry(struct image_cache_entry_s *centry)
{
#ifdef IMAGE_CACHE_VERBOSE
LOG(("freeing %p ", centry));
#endif
 
if (centry->redraw_count == 0) {
image_cache->total_unrendered++;
}
 
image_cache__free_bitmap(centry);
 
image_cache__unlink(centry);
 
free(centry);
}
 
/** Cache cleaner */
static void image_cache__clean(struct image_cache_s *icache)
{
struct image_cache_entry_s *centry = icache->entries;
 
while (centry != NULL) {
if ((icache->current_age - centry->redraw_age) >
icache->params.bg_clean_time) {
/* only consider older entries, avoids active entries */
if ((icache->total_bitmap_size >
(icache->params.limit - icache->params.hysteresis)) &&
(rand() > (RAND_MAX / 2))) {
image_cache__free_bitmap(centry);
}
}
centry=centry->next;
}
}
 
/** Cache background scheduled callback. */
static void image_cache__background_update(void *p)
{
struct image_cache_s *icache = p;
 
/* increment current cache age */
icache->current_age += icache->params.bg_clean_time;
 
#ifdef IMAGE_CACHE_VERBOSE
LOG(("Cache age %ds", icache->current_age / 1000));
#endif
 
image_cache__clean(icache);
 
schedule((icache->params.bg_clean_time / 10),
image_cache__background_update,
icache);
}
 
/* exported interface documented in image_cache.h */
struct bitmap *image_cache_get_bitmap(const struct content *c)
{
struct image_cache_entry_s *centry;
 
centry = image_cache__find(c);
if (centry == NULL) {
return NULL;
}
 
if (centry->bitmap == NULL) {
if (centry->convert != NULL) {
centry->bitmap = centry->convert(centry->content);
}
 
if (centry->bitmap != NULL) {
image_cache_stats_bitmap_add(centry);
image_cache->miss_count++;
image_cache->miss_size += centry->bitmap_size;
} else {
image_cache->fail_count++;
image_cache->fail_size += centry->bitmap_size;
}
} else {
image_cache->hit_count++;
image_cache->hit_size += centry->bitmap_size;
}
 
return centry->bitmap;
}
 
/* exported interface documented in image_cache.h */
bool image_cache_speculate(struct content *c)
{
bool decision = false;
 
/* If the cache is below its target usage and the bitmap is
* small enough speculate.
*/
if ((image_cache->total_bitmap_size < image_cache->params.limit) &&
(c->size <= image_cache->params.speculative_small)) {
#ifdef IMAGE_CACHE_VERBOSE
LOG(("content size (%d) is smaller than minimum (%d)", c->size, SPECULATE_SMALL));
#endif
decision = true;
}
 
#ifdef IMAGE_CACHE_VERBOSE
LOG(("returning %d", decision));
#endif
return decision;
}
 
/* exported interface documented in image_cache.h */
struct bitmap *image_cache_find_bitmap(struct content *c)
{
struct image_cache_entry_s *centry;
 
centry = image_cache__find(c);
if (centry == NULL) {
return NULL;
}
 
return centry->bitmap;
}
 
/* exported interface documented in image_cache.h */
nserror
image_cache_init(const struct image_cache_parameters *image_cache_parameters)
{
image_cache = calloc(1, sizeof(struct image_cache_s));
if (image_cache == NULL) {
return NSERROR_NOMEM;
}
 
image_cache->params = *image_cache_parameters;
 
schedule((image_cache->params.bg_clean_time / 10),
image_cache__background_update,
image_cache);
 
LOG(("Image cache initilised with a limit of %d hysteresis of %d",
image_cache->params.limit, image_cache->params.hysteresis));
 
return NSERROR_OK;
}
 
/* exported interface documented in image_cache.h */
nserror image_cache_fini(void)
{
unsigned int op_count;
 
schedule_remove(image_cache__background_update, image_cache);
 
LOG(("Size at finish %d (in %d)",
image_cache->total_bitmap_size,
image_cache->bitmap_count));
 
while (image_cache->entries != NULL) {
image_cache__free_entry(image_cache->entries);
}
 
op_count = image_cache->hit_count +
image_cache->miss_count +
image_cache->fail_count;
 
LOG(("Age %ds", image_cache->current_age / 1000));
LOG(("Peak size %d (in %d)",
image_cache->max_bitmap_size,
image_cache->max_bitmap_size_count ));
LOG(("Peak image count %d (size %d)",
image_cache->max_bitmap_count,
image_cache->max_bitmap_count_size));
 
if (op_count > 0) {
uint64_t op_size;
 
op_size = image_cache->hit_size +
image_cache->miss_size +
image_cache->fail_size;
 
LOG(("Cache total/hit/miss/fail (counts) %d/%d/%d/%d (100%%/%d%%/%d%%/%d%%)",
op_count,
image_cache->hit_count,
image_cache->miss_count,
image_cache->fail_count,
(image_cache->hit_count * 100) / op_count,
(image_cache->miss_count * 100) / op_count,
(image_cache->fail_count * 100) / op_count));
LOG(("Cache total/hit/miss/fail (size) %d/%d/%d/%d (100%%/%d%%/%d%%/%d%%)",
op_size,
image_cache->hit_size,
image_cache->miss_size,
image_cache->fail_size,
(image_cache->hit_size * 100) / op_size,
(image_cache->miss_size * 100) / op_size,
(image_cache->fail_size * 100) / op_size));
}
 
LOG(("Total images never rendered: %d (includes %d that were converted)",
image_cache->total_unrendered,
image_cache->specultive_miss_count));
 
LOG(("Total number of excessive conversions: %d (from %d images converted more than once)",
image_cache->total_extra_conversions,
image_cache->total_extra_conversions_count));
 
LOG(("Bitmap of size %d had most (%d) conversions",
image_cache->peak_conversions_size,
image_cache->peak_conversions));
 
free(image_cache);
 
return NSERROR_OK;
}
 
/* exported interface documented in image_cache.h */
nserror image_cache_add(struct content *content,
struct bitmap *bitmap,
image_cache_convert_fn *convert)
{
struct image_cache_entry_s *centry;
 
/* bump the cache age by a ms to ensure multiple items are not
* added at exactly the same time
*/
image_cache->current_age++;
 
centry = image_cache__find(content);
if (centry == NULL) {
/* new cache entry, content not previously added */
centry = calloc(1, sizeof(struct image_cache_entry_s));
if (centry == NULL) {
return NSERROR_NOMEM;
}
image_cache__link(centry);
centry->content = content;
 
centry->bitmap_size = content->width * content->height * 4;
}
 
LOG(("centry %p, content %p, bitmap %p", centry, content, bitmap));
 
centry->convert = convert;
 
/* set bitmap entry if one is passed, free extant one if present */
if (bitmap != NULL) {
if (centry->bitmap != NULL) {
bitmap_destroy(centry->bitmap);
} else {
image_cache_stats_bitmap_add(centry);
}
centry->bitmap = bitmap;
} else {
/* no bitmap, check to see if we should speculatively convert */
if ((centry->convert != NULL) &&
(image_cache_speculate(content) == true)) {
centry->bitmap = centry->convert(centry->content);
 
if (centry->bitmap != NULL) {
image_cache_stats_bitmap_add(centry);
} else {
image_cache->fail_count++;
}
}
}
 
 
 
return NSERROR_OK;
}
 
/* exported interface documented in image_cache.h */
nserror image_cache_remove(struct content *content)
{
struct image_cache_entry_s *centry;
 
/* get the cache entry */
centry = image_cache__find(content);
if (centry == NULL) {
LOG(("Could not find cache entry for content (%p)", content));
return NSERROR_NOT_FOUND;
}
 
image_cache__free_entry(centry);
 
return NSERROR_OK;
}
 
/* exported interface documented in image_cache.h */
int image_cache_snsummaryf(char *string, size_t size, const char *fmt)
{
size_t slen = 0; /* current output string length */
int fmtc = 0; /* current index into format string */
bool pct;
unsigned int op_count;
uint64_t op_size;
 
op_count = image_cache->hit_count +
image_cache->miss_count +
image_cache->fail_count;
 
op_size = image_cache->hit_size +
image_cache->miss_size +
image_cache->fail_size;
 
while((slen < size) && (fmt[fmtc] != 0)) {
if (fmt[fmtc] == '%') {
fmtc++;
 
/* check for percentage modifier */
if (fmt[fmtc] == 'p') {
fmtc++;
pct = true;
} else {
pct = false;
}
 
#define FMTCHR(chr,fmt,var) case chr : \
slen += snprintf(string + slen, size - slen, "%"fmt, image_cache->var); break
 
#define FMTPCHR(chr,fmt,var,div) \
case chr : \
if (pct) { \
if (div > 0) { \
slen += snprintf(string + slen, size - slen, "%"PRId64, (uint64_t)((image_cache->var * 100) / div)); \
} else { \
slen += snprintf(string + slen, size - slen, "100"); \
} \
} else { \
slen += snprintf(string + slen, size - slen, "%"fmt, image_cache->var); \
} break
 
 
switch (fmt[fmtc]) {
case '%':
string[slen] = '%';
slen++;
break;
 
FMTCHR('a', SSIZET_FMT, params.limit);
FMTCHR('b', SSIZET_FMT, params.hysteresis);
FMTCHR('c', SSIZET_FMT, total_bitmap_size);
FMTCHR('d', "d", bitmap_count);
FMTCHR('e', "d", current_age / 1000);
FMTCHR('f', SSIZET_FMT, max_bitmap_size);
FMTCHR('g', "d", max_bitmap_size_count);
FMTCHR('h', "d", max_bitmap_count);
FMTCHR('i', SSIZET_FMT, max_bitmap_count_size);
 
 
case 'j':
slen += snprintf(string + slen, size - slen,
"%d", pct?100:op_count);
break;
 
FMTPCHR('k', "d", hit_count, op_count);
FMTPCHR('l', "d", miss_count, op_count);
FMTPCHR('m', "d", fail_count, op_count);
 
case 'n':
slen += snprintf(string + slen, size - slen,
"%"PRId64, pct?100:op_size);
break;
 
FMTPCHR('o', PRId64, hit_size, op_size);
FMTPCHR('q', PRId64, miss_size, op_size);
FMTPCHR('r', PRId64, fail_size, op_size);
 
FMTCHR('s', "d", total_unrendered);
FMTCHR('t', "d", specultive_miss_count);
FMTCHR('u', "d", total_extra_conversions);
FMTCHR('v', "d", total_extra_conversions_count);
FMTCHR('w', "d", peak_conversions_size);
FMTCHR('x', "d", peak_conversions);
 
 
}
#undef FMTCHR
#undef FMTPCHR
 
fmtc++;
} else {
string[slen] = fmt[fmtc];
slen++;
fmtc++;
}
}
 
/* Ensure that we NUL-terminate the output */
string[min(slen, size - 1)] = '\0';
 
return slen;
}
 
/* exported interface documented in image_cache.h */
int image_cache_snentryf(char *string, size_t size, unsigned int entryn,
const char *fmt)
{
struct image_cache_entry_s *centry;
size_t slen = 0; /* current output string length */
int fmtc = 0; /* current index into format string */
lwc_string *origin; /* current entry's origin */
 
centry = image_cache__findn(entryn);
if (centry == NULL)
return -1;
 
while((slen < size) && (fmt[fmtc] != 0)) {
if (fmt[fmtc] == '%') {
fmtc++;
switch (fmt[fmtc]) {
case 'e':
slen += snprintf(string + slen, size - slen,
"%d", entryn);
break;
 
case 'r':
slen += snprintf(string + slen, size - slen,
"%u", centry->redraw_count);
break;
 
case 'a':
slen += snprintf(string + slen, size - slen,
"%.2f", (float)((image_cache->current_age - centry->redraw_age)) / 1000);
break;
 
 
case 'c':
slen += snprintf(string + slen, size - slen,
"%d", centry->conversion_count);
break;
 
case 'g':
slen += snprintf(string + slen, size - slen,
"%.2f", (float)((image_cache->current_age - centry->bitmap_age)) / 1000);
break;
 
case 'k':
slen += snprintf(string + slen, size - slen,
"%p", centry->content);
break;
 
case 'U':
slen += snprintf(string + slen, size - slen,
"%s", nsurl_access(llcache_handle_get_url(centry->content->llcache)));
break;
 
case 'o':
if (nsurl_has_component(llcache_handle_get_url(
centry->content->llcache),
NSURL_HOST)) {
origin = nsurl_get_component(
llcache_handle_get_url(
centry->content->
llcache),
NSURL_HOST);
slen += snprintf(string + slen,
size - slen, "%s",
lwc_string_data(
origin));
 
lwc_string_unref(origin);
} else {
slen += snprintf(string + slen,
size - slen, "%s",
"localhost");
}
break;
case 's':
if (centry->bitmap != NULL) {
slen += snprintf(string + slen,
size - slen,
"%"SSIZET_FMT,
centry->bitmap_size);
} else {
slen += snprintf(string + slen,
size - slen,
"0");
}
break;
}
fmtc++;
} else {
string[slen] = fmt[fmtc];
slen++;
fmtc++;
}
}
 
/* Ensure that we NUL-terminate the output */
string[min(slen, size - 1)] = '\0';
 
return slen;
}
 
 
/* exported interface documented in image_cache.h */
bool image_cache_redraw(struct content *c,
struct content_redraw_data *data,
const struct rect *clip,
const struct redraw_context *ctx)
{
struct image_cache_entry_s *centry;
 
/* get the cache entry */
centry = image_cache__find(c);
if (centry == NULL) {
LOG(("Could not find cache entry for content (%p)", c));
return false;
}
 
if (centry->bitmap == NULL) {
if (centry->convert != NULL) {
centry->bitmap = centry->convert(centry->content);
}
 
if (centry->bitmap != NULL) {
image_cache_stats_bitmap_add(centry);
image_cache->miss_count++;
image_cache->miss_size += centry->bitmap_size;
} else {
image_cache->fail_count++;
image_cache->fail_size += centry->bitmap_size;
return false;
}
} else {
image_cache->hit_count++;
image_cache->hit_size += centry->bitmap_size;
}
 
 
/* update statistics */
centry->redraw_count++;
centry->redraw_age = image_cache->current_age;
 
return image_bitmap_plot(centry->bitmap, data, clip, ctx);
}
 
void image_cache_destroy(struct content *content)
{
struct image_cache_entry_s *centry;
 
/* get the cache entry */
centry = image_cache__find(content);
if (centry == NULL) {
LOG(("Could not find cache entry for content (%p)", content));
} else {
image_cache__free_entry(centry);
}
}
 
void *image_cache_get_internal(const struct content *c, void *context)
{
return image_cache_get_bitmap(c);
}
 
content_type image_cache_content_type(void)
{
return CONTENT_IMAGE;
}
/programs/network/netsurf/netsurf/image/image_cache.h
0,0 → 1,188
/*
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* The image content handler intermediate image cache.
*
* This cache allows netsurf to use a generic intermediate bitmap
* format without keeping the
* intermediate representation in memory.
*
* The bitmap structure is opaque to the rest of netsurf and is
* controlled by the platform-specific code (see image/bitmap.h for
* detials). All image content handlers convert into this format and
* pass it to the plot functions for display,
*
* This cache maintains a link between the underlying original content
* and the intermediate representation. It is intended to be flexable
* and either manage the bitmap plotting completely or give the image
* content handler complete control.
*/
 
#ifndef NETSURF_IMAGE_IMAGE_CACHE_H_
#define NETSURF_IMAGE_IMAGE_CACHE_H_
 
#include "utils/errors.h"
#include "desktop/plotters.h"
#include "image/bitmap.h"
 
typedef struct bitmap * (image_cache_convert_fn) (struct content *content);
 
struct image_cache_parameters {
/** How frequently the background cache clean process is run (ms) */
unsigned int bg_clean_time;
 
/** The target upper bound for the image cache size */
size_t limit;
 
/** The hysteresis allowed round the target size */
size_t hysteresis;
 
/** The speculative conversion "small" size */
size_t speculative_small;
};
 
/** Initialise the image cache
*
* @param image_cache_parameters The control parameters for the image cache
*/
nserror image_cache_init(const struct image_cache_parameters *image_cache_parameters);
nserror image_cache_fini(void);
 
/** adds an image content to be cached.
*
* @param content The content handle used as a key
* @param bitmap A bitmap representing the already converted content or NULL.
* @param convert A function pointer to convert the content into a bitmap or NULL.
* @return A netsurf error code.
*/
nserror image_cache_add(struct content *content,
struct bitmap *bitmap,
image_cache_convert_fn *convert);
 
nserror image_cache_remove(struct content *content);
 
 
/** Obtain a bitmap from a content converting from source if neccessary. */
struct bitmap *image_cache_get_bitmap(const struct content *c);
 
/** Obtain a bitmap from a content with no conversion */
struct bitmap *image_cache_find_bitmap(struct content *c);
 
/** Decide if a content should be speculatively converted.
*
* This allows for image content handlers to ask the cache if a bitmap
* should be generated before it is added to the cache. This is the
* same decision logic used to decide to perform an immediate
* conversion when a content is initially added to the cache.
*
* @param c The content to be considered.
* @return true if a speculative conversion is desired false otehrwise.
*/
bool image_cache_speculate(struct content *c);
 
/**
* Fill a buffer with information about a cache entry using a format.
*
* The format string is copied into the output buffer with the
* following replaced:
* %e - The entry number
* %k - The content key
* %r - The number of redraws of this bitmap
* %c - The number of times this bitmap has been converted
* %s - The size of the current bitmap allocation
*
* \param string The buffer in which to place the results.
* \param size The size of the string buffer.
* \param entryn The opaque entry number.
* \param fmt The format string.
* \return The number of bytes written to \a string or -1 on error
*/
int image_cache_snentryf(char *string, size_t size, unsigned int entryn,
const char *fmt);
 
/**
* Fill a buffer with information about the image cache using a format.
*
* The format string is copied into the output buffer with the
* following replaced:
*
* a Configured cache limit size
* b Configured cache hysteresis size
* c Current caches total consumed size
* d Number of images currently in the cache
* e The age of the cache
* f The largest amount of space the cache has occupied since initialisation
* g The number of objetcs when the cache was at its largest
* h The largest number of images in the cache since initialisation
* i The size of the cache when the largest number of objects occoured
* j The total number of read operations performed on the cache
* k The total number of read operations satisfied from the cache without
* conversion.
* l The total number of read operations satisfied from the cache which
* required a conversion.
* m The total number of read operations which could not be sucessfully
* returned. ie. not available in cache and conversion failed.
* n The total size of read operations performed on the cache
* o The total size of read operations satisfied from the cache without
* conversion.
* q The total size of read operations satisfied from the cache which
* required a conversion.
* r The total size of read operations which could not be sucessfully
* returned. ie. not available in cache and conversion failed.
* s The number of images which were placed in the cache but never read.
* t The number of images that were converted on insertion into teh cache which were subsequently never used.
* u The number of times an image was converted after the first
* v The number of images that had extra conversions performed.
* w Size of the image that was converted (read missed cache) highest number
* of times.
* x The number of times the image that was converted (read missed cache)
* highest number of times.
*
* format modifiers:
* A p before the value modifies the replacement to be a percentage.
*
*
* \param string The buffer in which to place the results.
* \param size The size of the string buffer.
* \param fmt The format string.
* \return The number of bytes written to \a string or -1 on error
*/
 
int image_cache_snsummaryf(char *string, size_t size, const char *fmt);
 
/********* Image content handler generic cache callbacks ************/
 
/** Generic content redraw callback
*
* May be used by image content handlers as their redraw
* callback. Performs all neccissary cache lookups and conversions and
* calls the bitmap plot function in the redraw context.
*/
bool image_cache_redraw(struct content *c,
struct content_redraw_data *data,
const struct rect *clip,
const struct redraw_context *ctx);
 
void image_cache_destroy(struct content *c);
 
void *image_cache_get_internal(const struct content *c, void *context);
 
content_type image_cache_content_type(void);
 
#endif
/programs/network/netsurf/netsurf/image/jpeg.c
0,0 → 1,395
/*
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/jpeg (implementation).
*
* This implementation uses the IJG JPEG library.
*/
 
#include <assert.h>
#include <setjmp.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
 
#include "content/content_protected.h"
#include "desktop/plotters.h"
#include "image/image_cache.h"
 
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/types.h"
#include "utils/utils.h"
 
#define JPEG_INTERNAL_OPTIONS
#include "jpeglib.h"
#include "image/jpeg.h"
 
/** absolute minimum size of a jpeg below which it is not even worth
* trying to read header data
*/
#define MIN_JPEG_SIZE 20
 
#ifdef riscos
/* We prefer the library to be configured with these options to save
* copying data during decoding. */
#if RGB_RED != 0 || RGB_GREEN != 1 || RGB_BLUE != 2 || RGB_PIXELSIZE != 4
#warning JPEG library not optimally configured. Decoding will be slower.
#endif
/* but we don't care if we're not on RISC OS */
#endif
 
static char nsjpeg_error_buffer[JMSG_LENGTH_MAX];
 
static unsigned char nsjpeg_eoi[] = { 0xff, JPEG_EOI };
 
/**
* Content create entry point.
*/
static nserror nsjpeg_create(const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
struct content *jpeg;
nserror error;
 
jpeg = calloc(1, sizeof(struct content));
if (jpeg == NULL)
return NSERROR_NOMEM;
 
error = content__init(jpeg, handler, imime_type, params,
llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(jpeg);
return error;
}
 
*c = jpeg;
 
return NSERROR_OK;
}
 
/**
* JPEG data source manager: initialize source.
*/
static void nsjpeg_init_source(j_decompress_ptr cinfo)
{
}
 
 
/**
* JPEG data source manager: fill the input buffer.
*
* This can only occur if the JPEG data was truncated or corrupted. Insert a
* fake EOI marker to allow the decompressor to output as much as possible.
*/
static boolean nsjpeg_fill_input_buffer(j_decompress_ptr cinfo)
{
cinfo->src->next_input_byte = nsjpeg_eoi;
cinfo->src->bytes_in_buffer = 2;
return TRUE;
}
 
 
/**
* JPEG data source manager: skip num_bytes worth of data.
*/
 
static void nsjpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
{
if ((long) cinfo->src->bytes_in_buffer < num_bytes) {
cinfo->src->next_input_byte = 0;
cinfo->src->bytes_in_buffer = 0;
} else {
cinfo->src->next_input_byte += num_bytes;
cinfo->src->bytes_in_buffer -= num_bytes;
}
}
 
 
/**
* JPEG data source manager: terminate source.
*/
static void nsjpeg_term_source(j_decompress_ptr cinfo)
{
}
 
 
/**
* Error output handler for JPEG library.
*
* This logs to NetSurf log instead of stderr.
* Warnings only - fatal errors are trapped by nsjpeg_error_exit
* and do not call the output handler.
*/
static void nsjpeg_error_log(j_common_ptr cinfo)
{
cinfo->err->format_message(cinfo, nsjpeg_error_buffer);
LOG(("%s", nsjpeg_error_buffer));
}
 
 
/**
* Fatal error handler for JPEG library.
*
* This prevents jpeglib calling exit() on a fatal error.
*/
static void nsjpeg_error_exit(j_common_ptr cinfo)
{
jmp_buf *setjmp_buffer = (jmp_buf *) cinfo->client_data;
 
cinfo->err->format_message(cinfo, nsjpeg_error_buffer);
LOG(("%s", nsjpeg_error_buffer));
 
longjmp(*setjmp_buffer, 1);
}
 
static struct bitmap *
jpeg_cache_convert(struct content *c)
{
uint8_t *source_data; /* Jpeg source data */
unsigned long source_size; /* length of Jpeg source data */
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
jmp_buf setjmp_buffer;
unsigned int height;
unsigned int width;
struct bitmap * volatile bitmap = NULL;
uint8_t * volatile pixels = NULL;
size_t rowstride;
struct jpeg_source_mgr source_mgr = {
0,
0,
nsjpeg_init_source,
nsjpeg_fill_input_buffer,
nsjpeg_skip_input_data,
jpeg_resync_to_restart,
nsjpeg_term_source };
 
/* obtain jpeg source data and perfom minimal sanity checks */
source_data = (uint8_t *)content__get_source_data(c, &source_size);
 
if ((source_data == NULL) ||
(source_size < MIN_JPEG_SIZE)) {
return NULL;
}
 
/* setup a JPEG library error handler */
cinfo.err = jpeg_std_error(&jerr);
jerr.error_exit = nsjpeg_error_exit;
jerr.output_message = nsjpeg_error_log;
 
/* handler for fatal errors during decompression */
if (setjmp(setjmp_buffer)) {
jpeg_destroy_decompress(&cinfo);
return bitmap;
}
 
jpeg_create_decompress(&cinfo);
cinfo.client_data = &setjmp_buffer;
 
/* setup data source */
source_mgr.next_input_byte = source_data;
source_mgr.bytes_in_buffer = source_size;
cinfo.src = &source_mgr;
 
/* read JPEG header information */
jpeg_read_header(&cinfo, TRUE);
 
/* set output processing parameters */
cinfo.out_color_space = JCS_RGB;
cinfo.dct_method = JDCT_ISLOW;
 
/* commence the decompression, output parameters now valid */
jpeg_start_decompress(&cinfo);
 
width = cinfo.output_width;
height = cinfo.output_height;
 
/* create opaque bitmap (jpegs cannot be transparent) */
bitmap = bitmap_create(width, height, BITMAP_NEW | BITMAP_OPAQUE);
if (bitmap == NULL) {
/* empty bitmap could not be created */
jpeg_destroy_decompress(&cinfo);
return NULL;
}
 
pixels = bitmap_get_buffer(bitmap);
if (pixels == NULL) {
/* bitmap with no buffer available */
bitmap_destroy(bitmap);
jpeg_destroy_decompress(&cinfo);
return NULL;
}
 
/* Convert scanlines from jpeg into bitmap */
rowstride = bitmap_get_rowstride(bitmap);
do {
JSAMPROW scanlines[1];
 
scanlines[0] = (JSAMPROW) (pixels +
rowstride * cinfo.output_scanline);
jpeg_read_scanlines(&cinfo, scanlines, 1);
 
#if RGB_RED != 0 || RGB_GREEN != 1 || RGB_BLUE != 2 || RGB_PIXELSIZE != 4
{
/* Missmatch between configured libjpeg pixel format and
* NetSurf pixel format. Convert to RGBA */
int i;
for (i = width - 1; 0 <= i; i--) {
int r = scanlines[0][i * RGB_PIXELSIZE + RGB_RED];
int g = scanlines[0][i * RGB_PIXELSIZE + RGB_GREEN];
int b = scanlines[0][i * RGB_PIXELSIZE + RGB_BLUE];
scanlines[0][i * 4 + 0] = r;
scanlines[0][i * 4 + 1] = g;
scanlines[0][i * 4 + 2] = b;
scanlines[0][i * 4 + 3] = 0xff;
}
}
#endif
} while (cinfo.output_scanline != cinfo.output_height);
bitmap_modified(bitmap);
 
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
 
return bitmap;
}
 
/**
* Convert a CONTENT_JPEG for display.
*/
static bool nsjpeg_convert(struct content *c)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
jmp_buf setjmp_buffer;
struct jpeg_source_mgr source_mgr = { 0, 0,
nsjpeg_init_source, nsjpeg_fill_input_buffer,
nsjpeg_skip_input_data, jpeg_resync_to_restart,
nsjpeg_term_source };
union content_msg_data msg_data;
const char *data;
unsigned long size;
char *title;
 
/* check image header is valid and get width/height */
data = content__get_source_data(c, &size);
 
cinfo.err = jpeg_std_error(&jerr);
jerr.error_exit = nsjpeg_error_exit;
jerr.output_message = nsjpeg_error_log;
 
if (setjmp(setjmp_buffer)) {
jpeg_destroy_decompress(&cinfo);
 
msg_data.error = nsjpeg_error_buffer;
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
jpeg_create_decompress(&cinfo);
cinfo.client_data = &setjmp_buffer;
source_mgr.next_input_byte = (unsigned char *) data;
source_mgr.bytes_in_buffer = size;
cinfo.src = &source_mgr;
jpeg_read_header(&cinfo, TRUE);
cinfo.out_color_space = JCS_RGB;
cinfo.dct_method = JDCT_ISLOW;
 
jpeg_calc_output_dimensions(&cinfo);
 
c->width = cinfo.output_width;
c->height = cinfo.output_height;
c->size = c->width * c->height * 4;
 
jpeg_destroy_decompress(&cinfo);
 
image_cache_add(c, NULL, jpeg_cache_convert);
 
/* set title text */
title = messages_get_buff("JPEGTitle",
nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
c->width, c->height);
if (title != NULL) {
content__set_title(c, title);
free(title);
}
 
content_set_ready(c);
content_set_done(c);
content_set_status(c, ""); /* Done: update status bar */
 
return true;
}
 
 
 
/**
* Clone content.
*/
static nserror nsjpeg_clone(const struct content *old, struct content **newc)
{
struct content *jpeg_c;
nserror error;
 
jpeg_c = calloc(1, sizeof(struct content));
if (jpeg_c == NULL)
return NSERROR_NOMEM;
 
error = content__clone(old, jpeg_c);
if (error != NSERROR_OK) {
content_destroy(jpeg_c);
return error;
}
 
/* re-convert if the content is ready */
if ((old->status == CONTENT_STATUS_READY) ||
(old->status == CONTENT_STATUS_DONE)) {
if (nsjpeg_convert(jpeg_c) == false) {
content_destroy(jpeg_c);
return NSERROR_CLONE_FAILED;
}
}
 
*newc = jpeg_c;
 
return NSERROR_OK;
}
 
static const content_handler nsjpeg_content_handler = {
.create = nsjpeg_create,
.data_complete = nsjpeg_convert,
.destroy = image_cache_destroy,
.redraw = image_cache_redraw,
.clone = nsjpeg_clone,
.get_internal = image_cache_get_internal,
.type = image_cache_content_type,
.no_share = false,
};
 
static const char *nsjpeg_types[] = {
"image/jpeg",
"image/jpg",
"image/pjpeg"
};
 
CONTENT_FACTORY_REGISTER_TYPES(nsjpeg, nsjpeg_types, nsjpeg_content_handler);
/programs/network/netsurf/netsurf/image/jpeg.h
0,0 → 1,28
/*
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/jpeg (interface).
*/
 
#ifndef _NETSURF_IMAGE_JPEG_H_
#define _NETSURF_IMAGE_JPEG_H_
 
nserror nsjpeg_init(void);
 
#endif
/programs/network/netsurf/netsurf/image/make.image
0,0 → 1,21
CFLAGS += -O2 -DWITH_PNG -DWITH_BMP -DWITH_JPEG -DWITH_GIF
NETSURF_FB_FRONTEND := sdl
NETSURF_FB_FONTLIB := internal
 
NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
 
# Default resource install path
NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
 
# Default framebuffer search path
NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
 
# freetype compiled in font serch path
NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
OBJS := image.o image_cache.o bmp.o ico.o gif.o jpeg.o png.o
 
 
OUTFILE = TEST.o
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include
include $(MENUETDEV)/makefiles/Makefile_for_o_lib
/programs/network/netsurf/netsurf/image/mng.c
0,0 → 1,832
/*
* Copyright 2005 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/mng, image/png, and image/jng (implementation).
*/
 
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <libmng.h>
#include "content/content_protected.h"
#include "desktop/options.h"
#include "desktop/plotters.h"
#include "image/bitmap.h"
#include "image/mng.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/schedule.h"
#include "utils/utils.h"
 
/* This implementation does not currently support dynamic MNGs or any
* form of colour/gamma correction,
*/
 
typedef struct nsmng_content
{
struct content base;
bool opaque_test_pending;
bool read_start;
bool read_resume;
int read_size;
bool waiting;
bool displayed;
void *handle;
 
struct bitmap *bitmap; /**< Created NetSurf bitmap */
} nsmng_content;
 
 
#ifndef MNG_INTERNAL_MEMMNGMT
 
/**
* Memory allocation callback for libmng.
*/
 
static mng_ptr nsmng_alloc(mng_size_t n)
{
return calloc(1, n);
}
 
 
/**
* Memory free callback for libmng.
*/
 
static void nsmng_free(mng_ptr p, mng_size_t n)
{
free(p);
}
 
#endif
 
/**
* Broadcasts an error message and returns false
*
* \param c the content to broadcast for
* \return Appropriate error
*/
static nserror nsmng_broadcast_error(nsmng_content *c, mng_retcode code)
{
union content_msg_data msg_data;
char error[100];
 
assert(c != NULL);
 
if (code == MNG_OUTOFMEMORY) {
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return NSERROR_NOMEM;
}
 
snprintf(error, sizeof error, messages_get("MNGError"), code);
msg_data.error = error;
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return NSERROR_MNG_ERROR;
}
 
/* CALLBACKS REQUIRED FOR libmng READING */
 
static mng_bool nsmng_openstream(mng_handle mng)
{
assert(mng != NULL);
return MNG_TRUE;
}
 
static mng_bool nsmng_readdata(mng_handle mng, mng_ptr buffer, mng_uint32 size,
mng_uint32 *bytesread)
{
nsmng_content *c;
const char *data;
unsigned long data_size;
 
assert(mng != NULL);
assert(buffer != NULL);
assert(bytesread != NULL);
 
/* Get our content back
*/
c = (nsmng_content *) mng_get_userdata(mng);
assert(c != NULL);
 
/* Copy any data we have (maximum of 'size')
*/
data = content__get_source_data(&c->base, &data_size);
 
*bytesread = ((data_size - c->read_size) < size) ?
(data_size - c->read_size) : size;
 
if ((*bytesread) > 0) {
memcpy(buffer, data + c->read_size, *bytesread);
c->read_size += *bytesread;
}
 
/* Return success
*/
return MNG_TRUE;
}
 
static mng_bool nsmng_closestream(mng_handle mng)
{
assert(mng != NULL);
return MNG_TRUE;
}
 
static mng_bool nsmng_processheader(mng_handle mng, mng_uint32 width,
mng_uint32 height)
{
nsmng_content *c;
union content_msg_data msg_data;
uint8_t *buffer;
 
assert(mng != NULL);
 
/* This function is called when the header has been read and we
know the dimensions of the canvas.
*/
c = (nsmng_content *) mng_get_userdata(mng);
assert(c != NULL);
 
c->bitmap = bitmap_create(width, height, BITMAP_NEW);
if (c->bitmap == NULL) {
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
LOG(("Insufficient memory to create canvas."));
return MNG_FALSE;
}
 
/* Get the buffer to ensure that it is allocated and the calls in
* nsmng_getcanvasline() succeed. */
buffer = bitmap_get_buffer(c->bitmap);
if (buffer == NULL) {
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
LOG(("Insufficient memory to create canvas."));
return MNG_FALSE;
}
 
/* Initialise the content size
*/
c->base.width = width;
c->base.height = height;
 
/* Set the canvas style
*/
if (mng_set_canvasstyle(mng, MNG_CANVAS_RGBA8) != MNG_NOERROR) {
LOG(("Error setting canvas style."));
}
 
/* Return success
*/
return MNG_TRUE;
}
 
 
/* END OF CALLBACKS REQUIRED FOR READING
*/
 
 
static bool nsmng_process_data(struct content *c, const char *data, unsigned int size)
{
nsmng_content *mng = (nsmng_content *) c;
mng_retcode status;
 
assert(c != NULL);
assert(data != NULL);
 
/* We only need to do any processing if we're starting/resuming reading.
*/
if ((!mng->read_resume) && (!mng->read_start))
return true;
 
/* Try to start processing, or process some more data
*/
if (mng->read_start) {
status = mng_read(mng->handle);
mng->read_start = false;
} else {
status = mng_read_resume(mng->handle);
}
mng->read_resume = (status == MNG_NEEDMOREDATA);
if ((status != MNG_NOERROR) && (status != MNG_NEEDMOREDATA)) {
LOG(("Failed to start/continue reading (%i).", status));
return nsmng_broadcast_error(mng, status) == NSERROR_OK;
}
 
/* Continue onwards
*/
return true;
}
 
/* START OF CALLBACKS REQUIRED FOR DISPLAYING
*/
 
 
static mng_ptr nsmng_getcanvasline(mng_handle mng, mng_uint32 line)
{
nsmng_content *c;
 
assert(mng != NULL);
 
/* Get our content back
*/
c = (nsmng_content *) mng_get_userdata(mng);
assert(c != NULL);
 
/* Calculate the address
*/
return bitmap_get_buffer(c->bitmap) +
bitmap_get_rowstride(c->bitmap) * line;
}
 
static mng_bool nsmng_refresh(mng_handle mng, mng_uint32 x, mng_uint32 y,
mng_uint32 w, mng_uint32 h)
{
union content_msg_data data;
nsmng_content *c;
 
assert(mng != NULL);
 
/* Get our content back
*/
c = (nsmng_content *) mng_get_userdata(mng);
assert(c != NULL);
 
/* Set the minimum redraw area
*/
data.redraw.x = x;
data.redraw.y = y;
data.redraw.width = w;
data.redraw.height = h;
 
/* Set the redraw area to the whole canvas to ensure that if
we can redraw something to trigger animation later then we do
*/
/* data.redraw.x = 0;
data.redraw.y = 0;
data.redraw.width = c->width;
data.redraw.height = c->height;
*/
/* Always redraw everything
*/
data.redraw.full_redraw = true;
 
/* Set the object characteristics
*/
data.redraw.object = &c->base;
data.redraw.object_x = 0;
data.redraw.object_y = 0;
data.redraw.object_width = c->base.width;
data.redraw.object_height = c->base.height;
 
/* Only attempt to force the redraw if we've been requested to
* display the image in the first place (i.e. nsmng_redraw has
* been called). This avoids the situation of forcibly redrawing
* an image that shouldn't be shown (e.g. if the image is a fallback
* for an object that can't be rendered)
*/
if (c->displayed)
content_broadcast(&c->base, CONTENT_MSG_REDRAW, data);
 
return MNG_TRUE;
}
 
/**
* Animates to the next frame
*/
static void nsmng_animate(void *p)
{
nsmng_content *c;
 
assert(p != NULL);
 
c = (nsmng_content *) p;
 
/* If we used the last animation we advance, if not we try again later
*/
if (c->base.user_list->next == NULL) {
c->waiting = true;
} else {
c->waiting = false;
mng_display_resume(c->handle);
c->opaque_test_pending = true;
if (c->bitmap)
bitmap_modified(c->bitmap);
}
}
 
static mng_bool nsmng_settimer(mng_handle mng, mng_uint32 msecs)
{
nsmng_content *c;
 
assert(mng != NULL);
 
/* Get our content back
*/
c = (nsmng_content *) mng_get_userdata(mng);
assert(c != NULL);
 
/* Perform the scheduling
*/
schedule(msecs / 10, nsmng_animate, c);
return MNG_TRUE;
}
 
/**
* Get the wall-clock time in milliseconds since some fixed time.
*/
 
static mng_uint32 nsmng_gettickcount(mng_handle mng)
{
static bool start = true;
static time_t t0;
struct timeval tv;
#if defined(__SVR4) && defined(__sun) || defined(__NetBSD__) || \
defined(__APPLE__)
/* Solaris, NetBSD, and OS X don't have this structure, and ignore the
* second parameter to gettimeofday()
*/
int tz;
#else
struct timezone tz;
#endif
assert(mng != NULL);
 
gettimeofday(&tv, &tz);
if (start) {
t0 = tv.tv_sec;
start = false;
}
 
return (tv.tv_sec - t0) * 1000 + tv.tv_usec / 1000;
}
 
/* END OF CALLBACKS REQUIRED FOR DISPLAYING
*/
 
static mng_bool nsmng_errorproc(mng_handle mng, mng_int32 code,
mng_int8 severity, mng_chunkid chunktype, mng_uint32 chunkseq,
mng_int32 extra1, mng_int32 extra2, mng_pchar text)
{
nsmng_content *c;
char chunk[5];
 
assert(mng != NULL);
 
c = (nsmng_content *) mng_get_userdata(mng);
assert(c != NULL);
 
chunk[0] = (char)((chunktype >> 24) & 0xFF);
chunk[1] = (char)((chunktype >> 16) & 0xFF);
chunk[2] = (char)((chunktype >> 8) & 0xFF);
chunk[3] = (char)((chunktype ) & 0xFF);
chunk[4] = '\0';
 
LOG(("error playing '%s' chunk %s (%d):",
content_get_url(&c->base), chunk, chunkseq));
LOG(("code %d severity %d extra1 %d extra2 %d text:'%s'", code,
severity, extra1, extra2, text));
 
return (0);
}
 
static nserror nsmng_create_mng_data(nsmng_content *c)
{
mng_retcode code;
union content_msg_data msg_data;
 
assert(c != NULL);
 
/* Initialise the library
*/
#ifdef MNG_INTERNAL_MEMMNGMT
c->handle = mng_initialize(c, MNG_NULL, MNG_NULL, MNG_NULL);
#else
c->handle = mng_initialize(c, nsmng_alloc, nsmng_free, MNG_NULL);
#endif
if (c->handle == MNG_NULL) {
LOG(("Unable to initialise MNG library."));
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return NSERROR_NOMEM;
}
 
/* We need to decode in suspension mode
*/
code = mng_set_suspensionmode(c->handle, MNG_TRUE);
if (code) {
LOG(("Unable to set suspension mode."));
return nsmng_broadcast_error(c, code);
}
 
/* We need to register our callbacks
*/
code = mng_setcb_openstream(c->handle, nsmng_openstream);
if (code) {
LOG(("Unable to set openstream callback."));
return nsmng_broadcast_error(c, code);
}
code = mng_setcb_readdata(c->handle, nsmng_readdata);
if (code) {
LOG(("Unable to set readdata callback."));
return nsmng_broadcast_error(c, code);
}
code = mng_setcb_closestream(c->handle, nsmng_closestream);
if (code) {
LOG(("Unable to set closestream callback."));
return nsmng_broadcast_error(c, code);
}
code = mng_setcb_processheader(c->handle, nsmng_processheader);
if (code) {
LOG(("Unable to set processheader callback."));
return nsmng_broadcast_error(c, code);
}
 
/* Register our callbacks for displaying
*/
code = mng_setcb_getcanvasline(c->handle, nsmng_getcanvasline);
if (code) {
LOG(("Unable to set getcanvasline callback."));
return nsmng_broadcast_error(c, code);
}
code = mng_setcb_refresh(c->handle, nsmng_refresh);
if (code) {
LOG(("Unable to set refresh callback."));
return nsmng_broadcast_error(c, code);
}
code = mng_setcb_gettickcount(c->handle, nsmng_gettickcount);
if (code) {
LOG(("Unable to set gettickcount callback."));
return nsmng_broadcast_error(c, code);
}
code = mng_setcb_settimer(c->handle, nsmng_settimer);
if (code) {
LOG(("Unable to set settimer callback."));
return nsmng_broadcast_error(c, code);
}
 
/* register error handling function */
code = mng_setcb_errorproc(c->handle, nsmng_errorproc);
if (code) {
LOG(("Unable to set errorproc"));
return nsmng_broadcast_error(c, code);
}
 
/* Initialise the reading
*/
c->read_start = true;
c->read_resume = false;
c->read_size = 0;
c->waiting = false;
 
c->displayed = false;
 
return NSERROR_OK;
}
 
static nserror nsmng_create(const content_handler *handler,
lwc_string *imime_type, const struct http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
nsmng_content *mng;
nserror error;
 
mng = calloc(1, sizeof(nsmng_content));
if (mng == NULL)
return NSERROR_NOMEM;
 
error = content__init(&mng->base, handler, imime_type, params,
llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(mng);
return error;
}
 
error = nsmng_create_mng_data(mng);
if (error != NSERROR_OK) {
free(mng);
return error;
}
 
*c = (struct content *) mng;
 
return NSERROR_OK;
}
 
 
 
static bool nsmng_convert(struct content *c)
{
nsmng_content *mng = (nsmng_content *) c;
mng_retcode status;
unsigned long size;
char *title;
 
assert(c != NULL);
 
content__get_source_data(c, &size);
 
/* by this point, the png should have been parsed
* and the bitmap created, so ensure that's the case
*/
if (mng->bitmap == NULL) {
return nsmng_broadcast_error(mng, -1) == NSERROR_OK;
}
 
 
/* set title text */
title = messages_get_buff("MNGTitle",
nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
c->width, c->height);
if (title != NULL) {
content__set_title(c, title);
free(title);
}
 
c->size += c->width * c->height * 4;
content_set_ready(c);
content_set_done(c);
/* Done: update status bar */
content_set_status(c, "");
 
/* jmb: I'm really not sure that this should be here.
* The *_convert functions are for converting a content into a
* displayable format. They should not, however, do anything which
* could cause the content to be displayed; the content may have
* hidden visibility or be a fallback for an object; this
* information is not available here (nor is there any need for it
* to be).
* The specific issue here is that mng_display calls the display
* callbacks, which include nsmng_refresh. nsmng_refresh forces
* a content to be redrawn regardless of whether it should be
* displayed or not.
*/
/* Start displaying
*/
status = mng_display(mng->handle);
if ((status != MNG_NOERROR) && (status != MNG_NEEDTIMERWAIT)) {
LOG(("Unable to start display (%i)", status));
return nsmng_broadcast_error(mng, status) == NSERROR_OK;
}
bitmap_modified(mng->bitmap);
 
/* Optimise the plotting of MNG */
mng->opaque_test_pending = false;
 
return true;
}
 
static bool nsjpng_convert(struct content *c)
{
nsmng_content *mng = (nsmng_content *) c;
mng_retcode status;
unsigned long size;
char *title;
mng_handle handle;
 
assert(c != NULL);
 
content__get_source_data(c, &size);
 
/* by this point, the png should have been parsed
* and the bitmap created, so ensure that's the case
*/
if (mng->bitmap == NULL) {
return nsmng_broadcast_error(mng, -1) == NSERROR_OK;
}
 
/* set title text */
title = messages_get_buff("PNGTitle",
nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
c->width, c->height);
if (title != NULL) {
content__set_title(c, title);
free(title);
}
 
c->size += c->width * c->height * 4;
content_set_ready(c);
content_set_done(c);
/* Done: update status bar */
content_set_status(c, "");
 
/* jmb: I'm really not sure that this should be here.
* The *_convert functions are for converting a content into a
* displayable format. They should not, however, do anything which
* could cause the content to be displayed; the content may have
* hidden visibility or be a fallback for an object; this
* information is not available here (nor is there any need for it
* to be).
* The specific issue here is that mng_display calls the display
* callbacks, which include nsmng_refresh. nsmng_refresh forces
* a content to be redrawn regardless of whether it should be
* displayed or not.
*/
/* Start displaying
*/
status = mng_display(mng->handle);
if ((status != MNG_NOERROR) && (status != MNG_NEEDTIMERWAIT)) {
LOG(("Unable to start display (%i)", status));
return nsmng_broadcast_error(mng, status) == NSERROR_OK;
}
bitmap_modified(mng->bitmap);
 
/* Optimise the plotting of JNG/PNGs
*/
mng->opaque_test_pending = true;
bitmap_set_opaque(mng->bitmap, false);
 
/* free associated memory */
 
handle = mng->handle;
 
mng_cleanup(&handle);
 
mng->handle = NULL;
 
return true;
}
 
static void nsmng_destroy(struct content *c)
{
nsmng_content *mng = (nsmng_content *) c;
 
assert (c != NULL);
 
/* Cleanup the MNG structure and release the canvas memory
*/
schedule_remove(nsmng_animate, c);
 
if (mng->handle != NULL) {
mng_handle handle = mng->handle;
 
mng_cleanup(&handle);
 
mng->handle = NULL;
}
 
if (mng->bitmap) {
bitmap_destroy(mng->bitmap);
}
}
 
 
static bool nsmng_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
nsmng_content *mng = (nsmng_content *) c;
bool ret;
bitmap_flags_t flags = BITMAPF_NONE;
 
/* mark image as having been requested to display */
mng->displayed = true;
 
if ((mng->bitmap) &&
(mng->opaque_test_pending)) {
bitmap_set_opaque(mng->bitmap, bitmap_test_opaque(mng->bitmap));
mng->opaque_test_pending = false;
}
 
if (data->repeat_x)
flags |= BITMAPF_REPEAT_X;
if (data->repeat_y)
flags |= BITMAPF_REPEAT_Y;
 
ret = ctx->plot->bitmap(data->x, data->y, data->width, data->height,
mng->bitmap, data->background_colour, flags);
 
/* Check if we need to restart the animation */
if ((mng->waiting) &&
(nsoption_bool(animate_images))) {
nsmng_animate(c);
}
 
return ret;
}
 
 
static nserror nsmng_clone(const struct content *old, struct content **newc)
{
nsmng_content *mng;
nserror error;
const char *data;
unsigned long size;
 
mng = calloc(1, sizeof(nsmng_content));
if (mng == NULL)
return NSERROR_NOMEM;
 
error = content__clone(old, &mng->base);
if (error != NSERROR_OK) {
content_destroy(&mng->base);
return error;
}
 
/* Simply replay create/process/convert */
error = nsmng_create_mng_data(mng);
if (error != NSERROR_OK) {
content_destroy(&mng->base);
return error;
}
 
data = content__get_source_data(&mng->base, &size);
if (size > 0) {
if (nsmng_process_data(&mng->base, data, size) == false) {
content_destroy(&mng->base);
return NSERROR_CLONE_FAILED;
}
}
 
if (old->status == CONTENT_STATUS_READY ||
old->status == CONTENT_STATUS_DONE) {
if (nsmng_convert(&mng->base) == false) {
content_destroy(&mng->base);
return NSERROR_CLONE_FAILED;
}
}
 
*newc = (struct content *) mng;
 
return NSERROR_OK;
}
 
static void *nsmng_get_internal(const struct content *c, void *context)
{
nsmng_content *mng = (nsmng_content *)c;
 
return mng->bitmap;
}
 
static content_type nsmng_content_type(void)
{
return CONTENT_IMAGE;
}
 
/* register handler for mng types */
static const content_handler nsmng_content_handler = {
.create = nsmng_create,
.process_data = nsmng_process_data,
.data_complete = nsmng_convert,
.destroy = nsmng_destroy,
.redraw = nsmng_redraw,
.clone = nsmng_clone,
.get_internal = nsmng_get_internal,
.type = nsmng_content_type,
.no_share = false,
};
 
static const char *nsmng_types[] = {
/* MNG types*/
"image/mng",
"image/x-mng",
"video/mng",
"video/x-mng",
};
 
CONTENT_FACTORY_REGISTER_TYPES(nsmng, nsmng_types, nsmng_content_handler);
 
/* register handler for jng and png types */
static const content_handler nsjpng_content_handler = {
.create = nsmng_create,
.process_data = nsmng_process_data,
.data_complete = nsjpng_convert,
.destroy = nsmng_destroy,
.redraw = nsmng_redraw,
.clone = nsmng_clone,
.get_internal = nsmng_get_internal,
.type = nsmng_content_type,
.no_share = false,
};
 
 
static const char *nsjpng_types[] = {
/* JNG types*/
"image/jng",
"image/x-jng",
/* PNG types*/
"image/png",
"image/x-png"
};
 
CONTENT_FACTORY_REGISTER_TYPES(nsjpng, nsjpng_types, nsjpng_content_handler);
/programs/network/netsurf/netsurf/image/mng.h
0,0 → 1,29
/*
* Copyright 2004 Richard Wilson <not_ginger_matt@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/mng, image/png, and image/jng (interface).
*/
 
#ifndef _NETSURF_IMAGE_MNG_H_
#define _NETSURF_IMAGE_MNG_H_
 
nserror nsmng_init(void);
nserror nsjpng_init(void);
 
#endif
/programs/network/netsurf/netsurf/image/nssprite.c
0,0 → 1,258
/*
* Copyright 2008 James Shaw <js102@zepler.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/x-riscos-sprite (librosprite implementation).
*
*/
 
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <librosprite.h>
#include "utils/config.h"
#include "content/content_protected.h"
#include "desktop/plotters.h"
#include "image/bitmap.h"
#include "image/nssprite.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
 
typedef struct nssprite_content {
struct content base;
struct bitmap *bitmap; /**< Created NetSurf bitmap */
 
struct rosprite_area* sprite_area;
} nssprite_content;
 
 
#define ERRCHK(x) do { \
rosprite_error err = x; \
if (err == ROSPRITE_EOF) { \
LOG(("Got ROSPRITE_EOF when loading sprite file")); \
return false; \
} else if (err == ROSPRITE_BADMODE) { \
LOG(("Got ROSPRITE_BADMODE when loading sprite file")); \
return false; \
} else if (err == ROSPRITE_OK) { \
} else { \
return false; \
} \
} while(0)
 
 
 
 
static nserror nssprite_create(const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
nssprite_content *sprite;
nserror error;
 
sprite = calloc(1, sizeof(nssprite_content));
if (sprite == NULL)
return NSERROR_NOMEM;
 
error = content__init(&sprite->base, handler, imime_type, params,
llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(sprite);
return error;
}
 
*c = (struct content *) sprite;
 
return NSERROR_OK;
}
 
/**
* Convert a CONTENT_SPRITE for display.
*
* No conversion is necessary. We merely read the sprite dimensions.
*/
 
static bool nssprite_convert(struct content *c)
{
nssprite_content *nssprite = (nssprite_content *) c;
union content_msg_data msg_data;
 
struct rosprite_mem_context* ctx;
 
const char *data;
unsigned long size;
char *title;
 
data = content__get_source_data(c, &size);
 
ERRCHK(rosprite_create_mem_context((uint8_t *) data, size, &ctx));
 
struct rosprite_area* sprite_area;
ERRCHK(rosprite_load(rosprite_mem_reader, ctx, &sprite_area));
rosprite_destroy_mem_context(ctx);
nssprite->sprite_area = sprite_area;
 
assert(sprite_area->sprite_count > 0);
 
struct rosprite* sprite = sprite_area->sprites[0];
 
nssprite->bitmap = bitmap_create(sprite->width, sprite->height, BITMAP_NEW);
if (!nssprite->bitmap) {
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
uint32_t* imagebuf = (uint32_t *)bitmap_get_buffer(nssprite->bitmap);
if (!imagebuf) {
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
unsigned char *spritebuf = (unsigned char *)sprite->image;
 
/* reverse byte order of each word */
for (uint32_t y = 0; y < sprite->height; y++) {
for (uint32_t x = 0; x < sprite->width; x++) {
int offset = 4 * (y * sprite->width + x);
 
*imagebuf = (spritebuf[offset] << 24) |
(spritebuf[offset + 1] << 16) |
(spritebuf[offset + 2] << 8) |
(spritebuf[offset + 3]);
 
imagebuf++;
}
}
 
c->width = sprite->width;
c->height = sprite->height;
 
/* set title text */
title = messages_get_buff("SpriteTitle",
nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
c->width, c->height);
if (title != NULL) {
content__set_title(c, title);
free(title);
}
 
bitmap_modified(nssprite->bitmap);
 
content_set_ready(c);
content_set_done(c);
content_set_status(c, ""); /* Done: update status bar */
 
return true;
}
 
 
/**
* Destroy a CONTENT_SPRITE and free all resources it owns.
*/
 
static void nssprite_destroy(struct content *c)
{
nssprite_content *nssprite = (nssprite_content *) c;
 
if (nssprite->sprite_area != NULL)
rosprite_destroy_sprite_area(nssprite->sprite_area);
if (nssprite->bitmap != NULL)
bitmap_destroy(nssprite->bitmap);
}
 
 
/**
* Redraw a CONTENT_SPRITE.
*/
 
static bool nssprite_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
nssprite_content *nssprite = (nssprite_content *) c;
bitmap_flags_t flags = BITMAPF_NONE;
 
if (data->repeat_x)
flags |= BITMAPF_REPEAT_X;
if (data->repeat_y)
flags |= BITMAPF_REPEAT_Y;
 
return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
nssprite->bitmap, data->background_colour, flags);
}
 
 
static nserror nssprite_clone(const struct content *old, struct content **newc)
{
nssprite_content *sprite;
nserror error;
 
sprite = calloc(1, sizeof(nssprite_content));
if (sprite == NULL)
return NSERROR_NOMEM;
 
error = content__clone(old, &sprite->base);
if (error != NSERROR_OK) {
content_destroy(&sprite->base);
return error;
}
 
/* Simply replay convert */
if (old->status == CONTENT_STATUS_READY ||
old->status == CONTENT_STATUS_DONE) {
if (nssprite_convert(&sprite->base) == false) {
content_destroy(&sprite->base);
return NSERROR_CLONE_FAILED;
}
}
 
*newc = (struct content *) sprite;
 
return NSERROR_OK;
}
 
static void *nssprite_get_internal(const struct content *c, void *context)
{
nssprite_content *nssprite = (nssprite_content *) c;
 
return nssprite->bitmap;
}
 
static content_type nssprite_content_type(void)
{
return CONTENT_IMAGE;
}
 
 
static const content_handler nssprite_content_handler = {
.create = nssprite_create,
.data_complete = nssprite_convert,
.destroy = nssprite_destroy,
.redraw = nssprite_redraw,
.clone = nssprite_clone,
.get_internal = nssprite_get_internal,
.type = nssprite_content_type,
.no_share = false,
};
 
static const char *nssprite_types[] = {
"image/x-riscos-sprite"
};
 
CONTENT_FACTORY_REGISTER_TYPES(nssprite, nssprite_types, nssprite_content_handler);
/programs/network/netsurf/netsurf/image/nssprite.h
0,0 → 1,28
/*
* Copyright 2008 James Shaw <js102@zepler.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/x-riscos-sprite (librosprite interface).
*/
 
#ifndef _NETSURF_NS_SPRITE_H_
#define _NETSURF_NS_SPRITE_H_
 
nserror nssprite_init(void);
 
#endif
/programs/network/netsurf/netsurf/image/png.c
0,0 → 1,608
/*
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004 Richard Wilson <not_ginger_matt@hotmail.com>
* Copyright 2008 Daniel Silverstone <dsilvers@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
 
#include <png.h>
 
#include "desktop/plotters.h"
 
#include "content/content_protected.h"
 
#include "image/bitmap.h"
#include "image/image_cache.h"
#include "image/png.h"
 
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
 
/* accommodate for old versions of libpng (beware security holes!) */
 
#ifndef png_jmpbuf
#warning you have an antique libpng
#define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
#endif
 
#if PNG_LIBPNG_VER < 10209
#define png_set_expand_gray_1_2_4_to_8(png) png_set_gray_1_2_4_to_8(png)
#endif
 
typedef struct nspng_content {
struct content base; /**< base content type */
 
bool no_process_data; /**< Do not continue to process data as it arrives */
png_structp png;
png_infop info;
int interlace;
struct bitmap *bitmap; /**< Created NetSurf bitmap */
size_t rowstride, bpp; /**< Bitmap rowstride and bpp */
size_t rowbytes; /**< Number of bytes per row */
} nspng_content;
 
static unsigned int interlace_start[8] = {0, 16, 0, 8, 0, 4, 0};
static unsigned int interlace_step[8] = {28, 28, 12, 12, 4, 4, 0};
static unsigned int interlace_row_start[8] = {0, 0, 4, 0, 2, 0, 1};
static unsigned int interlace_row_step[8] = {8, 8, 8, 4, 4, 2, 2};
 
/** Callbak error numbers*/
enum nspng_cberr {
CBERR_NONE = 0, /* no error */
CBERR_LIBPNG, /* error from png library */
CBERR_NOPRE, /* no pre-conversion performed */
};
 
/**
* nspng_warning -- callback for libpng warnings
*/
static void nspng_warning(png_structp png_ptr, png_const_charp warning_message)
{
LOG(("%s", warning_message));
}
 
/**
* nspng_error -- callback for libpng errors
*/
static void nspng_error(png_structp png_ptr, png_const_charp error_message)
{
LOG(("%s", error_message));
longjmp(png_jmpbuf(png_ptr), CBERR_LIBPNG);
}
 
static void nspng_setup_transforms(png_structp png_ptr, png_infop info_ptr)
{
int bit_depth, color_type, intent;
double gamma;
 
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
color_type = png_get_color_type(png_ptr, info_ptr);
 
/* Set up our transformations */
if (color_type == PNG_COLOR_TYPE_PALETTE) {
png_set_palette_to_rgb(png_ptr);
}
 
if ((color_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < 8)) {
png_set_expand_gray_1_2_4_to_8(png_ptr);
}
 
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_set_tRNS_to_alpha(png_ptr);
}
 
if (bit_depth == 16) {
png_set_strip_16(png_ptr);
}
 
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
png_set_gray_to_rgb(png_ptr);
}
 
if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
}
 
/* gamma correction - we use 2.2 as our screen gamma
* this appears to be correct (at least in respect to !Browse)
* see http://www.w3.org/Graphics/PNG/all_seven.html for a test case
*/
if (png_get_sRGB(png_ptr, info_ptr, &intent)) {
png_set_gamma(png_ptr, 2.2, 0.45455);
} else {
if (png_get_gAMA(png_ptr, info_ptr, &gamma)) {
png_set_gamma(png_ptr, 2.2, gamma);
} else {
png_set_gamma(png_ptr, 2.2, 0.45455);
}
}
 
png_read_update_info(png_ptr, info_ptr);
}
 
/**
* info_callback -- PNG header has been completely received, prepare to process
* image data
*/
static void info_callback(png_structp png_s, png_infop info)
{
int interlace;
png_uint_32 width, height;
nspng_content *png_c = png_get_progressive_ptr(png_s);
 
width = png_get_image_width(png_s, info);
height = png_get_image_height(png_s, info);
interlace = png_get_interlace_type(png_s, info);
 
png_c->base.width = width;
png_c->base.height = height;
png_c->base.size += width * height * 4;
 
/* see if progressive-conversion should continue */
if (image_cache_speculate((struct content *)png_c) == false) {
longjmp(png_jmpbuf(png_s), CBERR_NOPRE);
}
 
/* Claim the required memory for the converted PNG */
png_c->bitmap = bitmap_create(width, height, BITMAP_NEW);
if (png_c->bitmap == NULL) {
/* Failed to create bitmap skip pre-conversion */
longjmp(png_jmpbuf(png_s), CBERR_NOPRE);
}
 
png_c->rowstride = bitmap_get_rowstride(png_c->bitmap);
png_c->bpp = bitmap_get_bpp(png_c->bitmap);
 
nspng_setup_transforms(png_s, info);
 
png_c->rowbytes = png_get_rowbytes(png_s, info);
png_c->interlace = (interlace == PNG_INTERLACE_ADAM7);
 
LOG(("size %li * %li, rowbytes %zu", (unsigned long)width,
(unsigned long)height, png_c->rowbytes));
}
 
static void row_callback(png_structp png_s, png_bytep new_row,
png_uint_32 row_num, int pass)
{
nspng_content *png_c = png_get_progressive_ptr(png_s);
unsigned long rowbytes = png_c->rowbytes;
unsigned char *buffer, *row;
 
/* Give up if there's no bitmap */
if (png_c->bitmap == NULL)
return;
 
/* Abort if we've not got any data */
if (new_row == NULL)
return;
 
/* Get bitmap buffer */
buffer = bitmap_get_buffer(png_c->bitmap);
if (buffer == NULL) {
/* No buffer, bail out */
longjmp(png_jmpbuf(png_s), 1);
}
 
/* Calculate address of row start */
row = buffer + (png_c->rowstride * row_num);
 
/* Handle interlaced sprites using the Adam7 algorithm */
if (png_c->interlace) {
unsigned long dst_off;
unsigned long src_off = 0;
unsigned int start, step;
 
start = interlace_start[pass];
step = interlace_step[pass];
row_num = interlace_row_start[pass] +
interlace_row_step[pass] * row_num;
 
/* Copy the data to our current row taking interlacing
* into consideration */
row = buffer + (png_c->rowstride * row_num);
 
for (dst_off = start; dst_off < rowbytes; dst_off += step) {
row[dst_off++] = new_row[src_off++];
row[dst_off++] = new_row[src_off++];
row[dst_off++] = new_row[src_off++];
row[dst_off++] = new_row[src_off++];
}
} else {
/* Do a fast memcpy of the row data */
memcpy(row, new_row, rowbytes);
}
}
 
 
static void end_callback(png_structp png_s, png_infop info)
{
}
 
static nserror nspng_create_png_data(nspng_content *png_c)
{
union content_msg_data msg_data;
 
png_c->bitmap = NULL;
 
png_c->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if (png_c->png == NULL) {
msg_data.error = messages_get("NoMemory");
content_broadcast(&png_c->base, CONTENT_MSG_ERROR, msg_data);
warn_user("NoMemory", 0);
return NSERROR_NOMEM;
}
 
png_set_error_fn(png_c->png, NULL, nspng_error, nspng_warning);
 
png_c->info = png_create_info_struct(png_c->png);
if (png_c->info == NULL) {
png_destroy_read_struct(&png_c->png, &png_c->info, 0);
 
msg_data.error = messages_get("NoMemory");
content_broadcast(&png_c->base, CONTENT_MSG_ERROR, msg_data);
warn_user("NoMemory", 0);
return NSERROR_NOMEM;
}
 
if (setjmp(png_jmpbuf(png_c->png))) {
png_destroy_read_struct(&png_c->png, &png_c->info, 0);
LOG(("Failed to set callbacks"));
png_c->png = NULL;
png_c->info = NULL;
 
msg_data.error = messages_get("PNGError");
content_broadcast(&png_c->base, CONTENT_MSG_ERROR, msg_data);
return NSERROR_NOMEM;
}
 
png_set_progressive_read_fn(png_c->png, png_c,
info_callback, row_callback, end_callback);
 
return NSERROR_OK;
}
 
static nserror nspng_create(const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
nspng_content *png_c;
nserror error;
 
png_c = calloc(1, sizeof(nspng_content));
if (png_c == NULL)
return NSERROR_NOMEM;
 
error = content__init(&png_c->base,
handler,
imime_type,
params,
llcache,
fallback_charset,
quirks);
if (error != NSERROR_OK) {
free(png_c);
return error;
}
 
error = nspng_create_png_data(png_c);
if (error != NSERROR_OK) {
free(png_c);
return error;
}
 
*c = (struct content *)png_c;
 
return NSERROR_OK;
}
 
 
static bool nspng_process_data(struct content *c, const char *data,
unsigned int size)
{
nspng_content *png_c = (nspng_content *)c;
union content_msg_data msg_data;
volatile bool ret = true;
 
if (png_c->no_process_data) {
return ret;
}
 
switch (setjmp(png_jmpbuf(png_c->png))) {
case CBERR_NONE: /* direct return */
png_process_data(png_c->png, png_c->info, (uint8_t *)data, size);
break;
 
case CBERR_NOPRE: /* not going to progressive convert */
png_c->no_process_data = true;
break;
 
default: /* fatal error from library processing png */
if (png_c->bitmap != NULL) {
/* A bitmap managed to get created so
* operation is past header and possibly some
* conversion happened before faliure.
*
* In this case keep the partial
* conversion. This is usually seen if a png
* has been truncated (often jsut lost its
* last byte and hence end of image marker)
*/
png_c->no_process_data = true;
} else {
/* not managed to progress past header, clean
* up png conversion and signal the content
* error
*/
LOG(("Fatal PNG error during header, error content"));
 
png_destroy_read_struct(&png_c->png, &png_c->info, 0);
png_c->png = NULL;
png_c->info = NULL;
 
msg_data.error = messages_get("PNGError");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
 
ret = false;
 
}
break;
}
 
return ret;
}
 
struct png_cache_read_data_s {
const char *data;
unsigned long size;
};
 
/** PNG library read fucntion to read data from a memory array
*/
static void
png_cache_read_fn(png_structp png_ptr, png_bytep data, png_size_t length)
{
struct png_cache_read_data_s *png_cache_read_data;
png_cache_read_data = png_get_io_ptr(png_ptr);
 
if (length > png_cache_read_data->size) {
length = png_cache_read_data->size;
}
 
if (length == 0) {
png_error(png_ptr, "Read Error");
}
 
memcpy(data, png_cache_read_data->data, length);
 
png_cache_read_data->data += length;
png_cache_read_data->size -= length;
}
 
/** calculate an array of row pointers into a bitmap data area
*/
static png_bytep *calc_row_pointers(struct bitmap *bitmap)
{
int height = bitmap_get_height(bitmap);
unsigned char *buffer= bitmap_get_buffer(bitmap);
size_t rowstride = bitmap_get_rowstride(bitmap);
png_bytep *row_ptrs;
int hloop;
 
row_ptrs = malloc(sizeof(png_bytep) * height);
 
if (row_ptrs != NULL) {
for (hloop = 0; hloop < height; hloop++) {
row_ptrs[hloop] = buffer + (rowstride * hloop);
}
}
 
return row_ptrs;
}
 
/** PNG content to bitmap conversion.
*
* This routine generates a bitmap object from a PNG image content
*/
static struct bitmap *
png_cache_convert(struct content *c)
{
png_structp png_ptr;
png_infop info_ptr;
png_infop end_info;
volatile struct bitmap *bitmap = NULL;
struct png_cache_read_data_s png_cache_read_data;
png_uint_32 width, height;
volatile png_bytep *row_pointers = NULL;
 
png_cache_read_data.data =
content__get_source_data(c, &png_cache_read_data.size);
 
if ((png_cache_read_data.data == NULL) ||
(png_cache_read_data.size <= 8)) {
return NULL;
}
 
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL,
nspng_error,
nspng_warning);
if (png_ptr == NULL) {
return NULL;
}
 
info_ptr = png_create_info_struct(png_ptr);
if (png_ptr == NULL) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
return NULL;
}
 
end_info = png_create_info_struct(png_ptr);
if (png_ptr == NULL) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
}
 
/* setup error exit path */
if (setjmp(png_jmpbuf(png_ptr))) {
/* cleanup and bail */
goto png_cache_convert_error;
}
 
/* read from a buffer instead of stdio */
png_set_read_fn(png_ptr, &png_cache_read_data, png_cache_read_fn);
 
/* ensure the png info structure is populated */
png_read_info(png_ptr, info_ptr);
 
/* setup output transforms */
nspng_setup_transforms(png_ptr, info_ptr);
 
width = png_get_image_width(png_ptr, info_ptr);
height = png_get_image_height(png_ptr,info_ptr);
 
/* Claim the required memory for the converted PNG */
bitmap = bitmap_create(width, height, BITMAP_NEW);
if (bitmap == NULL) {
/* cleanup and bail */
goto png_cache_convert_error;
}
 
row_pointers = calc_row_pointers((struct bitmap *) bitmap);
 
if (row_pointers != NULL) {
png_read_image(png_ptr, (png_bytep *) row_pointers);
}
 
png_cache_convert_error:
 
/* cleanup png read */
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
 
free((png_bytep *) row_pointers);
 
if (bitmap != NULL)
bitmap_modified((struct bitmap *)bitmap);
 
return (struct bitmap *)bitmap;
}
 
static bool nspng_convert(struct content *c)
{
nspng_content *png_c = (nspng_content *) c;
char *title;
 
assert(png_c->png != NULL);
assert(png_c->info != NULL);
 
/* clean up png structures */
png_destroy_read_struct(&png_c->png, &png_c->info, 0);
 
/* set title text */
title = messages_get_buff("PNGTitle",
nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
c->width, c->height);
if (title != NULL) {
content__set_title(c, title);
free(title);
}
 
if (png_c->bitmap != NULL) {
bitmap_set_opaque(png_c->bitmap, bitmap_test_opaque(png_c->bitmap));
bitmap_modified(png_c->bitmap);
}
 
image_cache_add(c, png_c->bitmap, png_cache_convert);
 
content_set_ready(c);
content_set_done(c);
content_set_status(c, "");
 
return true;
}
 
 
static nserror nspng_clone(const struct content *old_c, struct content **new_c)
{
nspng_content *clone_png_c;
nserror error;
const char *data;
unsigned long size;
 
clone_png_c = calloc(1, sizeof(nspng_content));
if (clone_png_c == NULL)
return NSERROR_NOMEM;
 
error = content__clone(old_c, &clone_png_c->base);
if (error != NSERROR_OK) {
content_destroy(&clone_png_c->base);
return error;
}
 
/* Simply replay create/process/convert */
error = nspng_create_png_data(clone_png_c);
if (error != NSERROR_OK) {
content_destroy(&clone_png_c->base);
return error;
}
 
data = content__get_source_data(&clone_png_c->base, &size);
if (size > 0) {
if (nspng_process_data(&clone_png_c->base, data, size) == false) {
content_destroy(&clone_png_c->base);
return NSERROR_NOMEM;
}
}
 
if ((old_c->status == CONTENT_STATUS_READY) ||
(old_c->status == CONTENT_STATUS_DONE)) {
if (nspng_convert(&clone_png_c->base) == false) {
content_destroy(&clone_png_c->base);
return NSERROR_CLONE_FAILED;
}
}
 
*new_c = (struct content *)clone_png_c;
 
return NSERROR_OK;
}
 
static const content_handler nspng_content_handler = {
.create = nspng_create,
.process_data = nspng_process_data,
.data_complete = nspng_convert,
.clone = nspng_clone,
.destroy = image_cache_destroy,
.redraw = image_cache_redraw,
.get_internal = image_cache_get_internal,
.type = image_cache_content_type,
.no_share = false,
};
 
static const char *nspng_types[] = {
"image/png",
"image/x-png"
};
 
CONTENT_FACTORY_REGISTER_TYPES(nspng, nspng_types, nspng_content_handler);
/programs/network/netsurf/netsurf/image/png.h
0,0 → 1,25
/*
* Copyright 2003 James Bursa <bursa@users.sourceforge.net>
* Copyright 2008 Daniel Silverstone <dsilvers@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef _NETSURF_RISCOS_PNG_H_
#define _NETSURF_RISCOS_PNG_H_
 
nserror nspng_init(void);
 
#endif
/programs/network/netsurf/netsurf/image/rsvg.c
0,0 → 1,322
/*
* Copyright 2007 Rob Kendrick <rjek@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content handler for image/svg using librsvg (implementation).
*
* SVG files are rendered to a NetSurf bitmap by creating a Cairo rendering
* surface (content_rsvg_data.cs) over the bitmap's data, creating a Cairo
* drawing context using that surface, and then passing that drawing context
* to librsvg which then uses Cairo calls to plot the graphic to the bitmap.
* We store this in content->bitmap, and then use the usual bitmap plotter
* function to render it for redraw requests.
*/
 
#include <stdbool.h>
#include <assert.h>
#include <string.h>
#include <sys/types.h>
 
#include <librsvg/rsvg.h>
#include <librsvg/rsvg-cairo.h>
 
#include "content/content_protected.h"
#include "desktop/plotters.h"
#include "image/bitmap.h"
#include "utils/log.h"
#include "utils/utils.h"
#include "utils/messages.h"
 
#include "image/rsvg.h"
 
typedef struct rsvg_content {
struct content base;
 
RsvgHandle *rsvgh; /**< Context handle for RSVG renderer */
cairo_surface_t *cs; /**< The surface built inside a nsbitmap */
cairo_t *ct; /**< Cairo drawing context */
struct bitmap *bitmap; /**< Created NetSurf bitmap */
} rsvg_content;
 
static nserror rsvg_create_svg_data(rsvg_content *c)
{
union content_msg_data msg_data;
 
c->rsvgh = NULL;
c->cs = NULL;
c->ct = NULL;
c->bitmap = NULL;
 
if ((c->rsvgh = rsvg_handle_new()) == NULL) {
LOG(("rsvg_handle_new() returned NULL."));
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return NSERROR_NOMEM;
}
 
return NSERROR_OK;
}
 
 
static nserror rsvg_create(const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
rsvg_content *svg;
nserror error;
 
svg = calloc(1, sizeof(rsvg_content));
if (svg == NULL)
return NSERROR_NOMEM;
 
error = content__init(&svg->base, handler, imime_type, params,
llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(svg);
return error;
}
 
error = rsvg_create_svg_data(svg);
if (error != NSERROR_OK) {
free(svg);
return error;
}
 
*c = (struct content *) svg;
 
return NSERROR_OK;
}
 
 
static bool rsvg_process_data(struct content *c, const char *data,
unsigned int size)
{
rsvg_content *d = (rsvg_content *) c;
union content_msg_data msg_data;
GError *err = NULL;
 
if (rsvg_handle_write(d->rsvgh, (const guchar *)data, (gsize)size,
&err) == FALSE) {
LOG(("rsvg_handle_write returned an error: %s", err->message));
msg_data.error = err->message;
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
return true;
}
 
/** Convert Cairo's ARGB output to NetSurf's favoured ABGR format. It converts
* the data in-place.
*
* \param pixels Pixel data, in the form of ARGB. This will
* be overwritten with new data in the form of ABGR.
* \param width Width of the bitmap
* \param height Height of the bitmap
* \param rowstride Number of bytes to skip after each row (this
* implementation requires this to be a multiple of 4.)
*/
static inline void rsvg_argb_to_abgr(uint8_t *pixels,
int width, int height, size_t rowstride)
{
uint8_t *p = pixels;
 
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
/* Swap R and B */
const uint8_t r = p[x+3];
 
p[x+3] = p[x];
 
p[x] = r;
}
 
p += rowstride;
}
}
 
static bool rsvg_convert(struct content *c)
{
rsvg_content *d = (rsvg_content *) c;
union content_msg_data msg_data;
RsvgDimensionData rsvgsize;
GError *err = NULL;
 
if (rsvg_handle_close(d->rsvgh, &err) == FALSE) {
LOG(("rsvg_handle_close returned an error: %s", err->message));
msg_data.error = err->message;
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
assert(err == NULL);
 
/* we should now be able to query librsvg for the natural size of the
* graphic, so we can create our bitmap.
*/
 
rsvg_handle_get_dimensions(d->rsvgh, &rsvgsize);
c->width = rsvgsize.width;
c->height = rsvgsize.height;
 
if ((d->bitmap = bitmap_create(c->width, c->height,
BITMAP_NEW)) == NULL) {
LOG(("Failed to create bitmap for rsvg render."));
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
if ((d->cs = cairo_image_surface_create_for_data(
(unsigned char *)bitmap_get_buffer(d->bitmap),
CAIRO_FORMAT_ARGB32,
c->width, c->height,
bitmap_get_rowstride(d->bitmap))) == NULL) {
LOG(("Failed to create Cairo image surface for rsvg render."));
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
if ((d->ct = cairo_create(d->cs)) == NULL) {
LOG(("Failed to create Cairo drawing context for rsvg render."));
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
rsvg_handle_render_cairo(d->rsvgh, d->ct);
rsvg_argb_to_abgr(bitmap_get_buffer(d->bitmap),
c->width, c->height,
bitmap_get_rowstride(d->bitmap));
 
bitmap_modified(d->bitmap);
content_set_ready(c);
content_set_done(c);
/* Done: update status bar */
content_set_status(c, "");
 
return true;
}
 
static bool rsvg_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
rsvg_content *rsvgcontent = (rsvg_content *) c;
bitmap_flags_t flags = BITMAPF_NONE;
 
assert(rsvgcontent->bitmap != NULL);
 
if (data->repeat_x)
flags |= BITMAPF_REPEAT_X;
if (data->repeat_y)
flags |= BITMAPF_REPEAT_Y;
 
return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
rsvgcontent->bitmap, data->background_colour, flags);
}
 
static void rsvg_destroy(struct content *c)
{
rsvg_content *d = (rsvg_content *) c;
 
if (d->bitmap != NULL) bitmap_destroy(d->bitmap);
if (d->rsvgh != NULL) g_object_unref(d->rsvgh);
if (d->ct != NULL) cairo_destroy(d->ct);
if (d->cs != NULL) cairo_surface_destroy(d->cs);
 
return;
}
 
static nserror rsvg_clone(const struct content *old, struct content **newc)
{
rsvg_content *svg;
nserror error;
const char *data;
unsigned long size;
 
svg = calloc(1, sizeof(rsvg_content));
if (svg == NULL)
return NSERROR_NOMEM;
 
error = content__clone(old, &svg->base);
if (error != NSERROR_OK) {
content_destroy(&svg->base);
return error;
}
 
/* Simply replay create/process/convert */
error = rsvg_create_svg_data(svg);
if (error != NSERROR_OK) {
content_destroy(&svg->base);
return error;
}
 
data = content__get_source_data(&svg->base, &size);
if (size > 0) {
if (rsvg_process_data(&svg->base, data, size) == false) {
content_destroy(&svg->base);
return NSERROR_NOMEM;
}
}
 
if (old->status == CONTENT_STATUS_READY ||
old->status == CONTENT_STATUS_DONE) {
if (rsvg_convert(&svg->base) == false) {
content_destroy(&svg->base);
return NSERROR_CLONE_FAILED;
}
}
 
*newc = (struct content *) svg;
 
return NSERROR_OK;
}
 
static void *rsvg_get_internal(const struct content *c, void *context)
{
rsvg_content *d = (rsvg_content *) c;
 
return d->bitmap;
}
 
static content_type rsvg_content_type(void)
{
return CONTENT_IMAGE;
}
 
static const content_handler rsvg_content_handler = {
.create = rsvg_create,
.process_data = rsvg_process_data,
.data_complete = rsvg_convert,
.destroy = rsvg_destroy,
.redraw = rsvg_redraw,
.clone = rsvg_clone,
.get_internal = rsvg_get_internal,
.type = rsvg_content_type,
.no_share = false,
};
 
static const char *rsvg_types[] = {
"image/svg",
"image/svg+xml"
};
 
CONTENT_FACTORY_REGISTER_TYPES(nsrsvg, rsvg_types, rsvg_content_handler);
 
/programs/network/netsurf/netsurf/image/rsvg.h
0,0 → 1,28
/*
* Copyright 2007 Rob Kendrick <rjek@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content handler for image/svg using librsvg (interface).
*/
 
#ifndef _NETSURF_IMAGE_RSVG_H_
#define _NETSURF_IMAGE_RSVG_H_
 
nserror nsrsvg_init(void);
 
#endif
/programs/network/netsurf/netsurf/image/svg.c
0,0 → 1,352
/*
* Copyright 2007-2008 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/svg (implementation).
*/
 
#include <assert.h>
#include <limits.h>
#include <string.h>
 
#include <svgtiny.h>
 
#include "content/content_protected.h"
#include "css/css.h"
#include "desktop/plotters.h"
#include "image/svg.h"
#include "utils/messages.h"
#include "utils/utils.h"
 
typedef struct svg_content {
struct content base;
 
struct svgtiny_diagram *diagram;
 
int current_width;
int current_height;
} svg_content;
 
 
 
static nserror svg_create_svg_data(svg_content *c)
{
union content_msg_data msg_data;
 
c->diagram = svgtiny_create();
if (c->diagram == NULL)
goto no_memory;
 
c->current_width = INT_MAX;
c->current_height = INT_MAX;
 
return NSERROR_OK;
 
no_memory:
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return NSERROR_NOMEM;
}
 
 
/**
* Create a CONTENT_SVG.
*/
 
static nserror svg_create(const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
svg_content *svg;
nserror error;
 
svg = calloc(1, sizeof(svg_content));
if (svg == NULL)
return NSERROR_NOMEM;
 
error = content__init(&svg->base, handler, imime_type, params,
llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(svg);
return error;
}
 
error = svg_create_svg_data(svg);
if (error != NSERROR_OK) {
free(svg);
return error;
}
 
*c = (struct content *) svg;
 
return NSERROR_OK;
}
 
 
 
/**
* Convert a CONTENT_SVG for display.
*/
 
static bool svg_convert(struct content *c)
{
/*c->title = malloc(100);
if (c->title)
snprintf(c->title, 100, messages_get("svgTitle"),
width, height, c->source_size);*/
//c->size += ?;
content_set_ready(c);
content_set_done(c);
/* Done: update status bar */
content_set_status(c, "");
 
return true;
}
 
/**
* Reformat a CONTENT_SVG.
*/
 
static void svg_reformat(struct content *c, int width, int height)
{
svg_content *svg = (svg_content *) c;
const char *source_data;
unsigned long source_size;
 
assert(svg->diagram);
 
/* Avoid reformats to same width/height as we already reformatted to */
if (width != svg->current_width || height != svg->current_height) {
source_data = content__get_source_data(c, &source_size);
 
svgtiny_parse(svg->diagram, source_data, source_size,
nsurl_access(content_get_url(c)),
width, height);
 
svg->current_width = width;
svg->current_height = height;
}
 
c->width = svg->diagram->width;
c->height = svg->diagram->height;
}
 
 
/**
* Redraw a CONTENT_SVG.
*/
 
static bool svg_redraw_internal(struct content *c, int x, int y,
int width, int height, const struct rect *clip,
const struct redraw_context *ctx, float scale,
colour background_colour)
{
svg_content *svg = (svg_content *) c;
float transform[6];
struct svgtiny_diagram *diagram = svg->diagram;
bool ok;
int px, py;
unsigned int i;
plot_font_style_t fstyle = *plot_style_font;
 
assert(diagram);
 
transform[0] = (float) width / (float) c->width;
transform[1] = 0;
transform[2] = 0;
transform[3] = (float) height / (float) c->height;
transform[4] = x;
transform[5] = y;
 
#define BGR(c) ((c) == svgtiny_TRANSPARENT ? NS_TRANSPARENT : \
((svgtiny_RED((c))) | \
(svgtiny_GREEN((c)) << 8) | \
(svgtiny_BLUE((c)) << 16)))
 
for (i = 0; i != diagram->shape_count; i++) {
if (diagram->shape[i].path) {
ok = ctx->plot->path(diagram->shape[i].path,
diagram->shape[i].path_length,
BGR(diagram->shape[i].fill),
diagram->shape[i].stroke_width,
BGR(diagram->shape[i].stroke),
transform);
if (!ok)
return false;
 
} else if (diagram->shape[i].text) {
px = transform[0] * diagram->shape[i].text_x +
transform[2] * diagram->shape[i].text_y +
transform[4];
py = transform[1] * diagram->shape[i].text_x +
transform[3] * diagram->shape[i].text_y +
transform[5];
 
fstyle.background = 0xffffff;
fstyle.foreground = 0x000000;
fstyle.size = (8 * FONT_SIZE_SCALE) * scale;
 
ok = ctx->plot->text(px, py,
diagram->shape[i].text,
strlen(diagram->shape[i].text),
&fstyle);
if (!ok)
return false;
}
}
 
#undef BGR
 
return true;
}
 
 
/**
* Redraw a CONTENT_SVG.
*/
 
static bool svg_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
int x = data->x;
int y = data->y;
 
if ((data->width <= 0) && (data->height <= 0)) {
/* No point trying to plot SVG if it does not occupy a valid
* area */
return true;
}
 
if ((data->repeat_x == false) && (data->repeat_y == false)) {
/* Simple case: SVG is not tiled */
return svg_redraw_internal(c, x, y,
data->width, data->height,
clip, ctx, data->scale,
data->background_colour);
} else {
/* Tiled redraw required. SVG repeats to extents of clip
* rectangle, in x, y or both directions */
int x0, y0, x1, y1;
 
/* Find the redraw boundaries to loop within */
x0 = x;
if (data->repeat_x) {
for (; x0 > clip->x0; x0 -= data->width);
x1 = clip->x1;
} else {
x1 = x + 1;
}
y0 = y;
if (data->repeat_y) {
for (; y0 > clip->y0; y0 -= data->height);
y1 = clip->y1;
} else {
y1 = y + 1;
}
 
/* Repeatedly plot the SVG across the area */
for (y = y0; y < y1; y += data->height) {
for (x = x0; x < x1; x += data->width) {
if (!svg_redraw_internal(c, x, y,
data->width, data->height,
clip, ctx, data->scale,
data->background_colour)) {
return false;
}
}
}
}
 
return true;
}
 
 
/**
* Destroy a CONTENT_SVG and free all resources it owns.
*/
 
static void svg_destroy(struct content *c)
{
svg_content *svg = (svg_content *) c;
 
if (svg->diagram != NULL)
svgtiny_free(svg->diagram);
}
 
 
static nserror svg_clone(const struct content *old, struct content **newc)
{
svg_content *svg;
nserror error;
 
svg = calloc(1, sizeof(svg_content));
if (svg == NULL)
return NSERROR_NOMEM;
 
error = content__clone(old, &svg->base);
if (error != NSERROR_OK) {
content_destroy(&svg->base);
return error;
}
 
/* Simply replay create/convert */
error = svg_create_svg_data(svg);
if (error != NSERROR_OK) {
content_destroy(&svg->base);
return error;
}
 
if (old->status == CONTENT_STATUS_READY ||
old->status == CONTENT_STATUS_DONE) {
if (svg_convert(&svg->base) == false) {
content_destroy(&svg->base);
return NSERROR_CLONE_FAILED;
}
}
 
*newc = (struct content *) svg;
 
return NSERROR_OK;
}
 
static content_type svg_content_type(void)
{
return CONTENT_IMAGE;
}
 
static const content_handler svg_content_handler = {
.create = svg_create,
.data_complete = svg_convert,
.reformat = svg_reformat,
.destroy = svg_destroy,
.redraw = svg_redraw,
.clone = svg_clone,
.type = svg_content_type,
.no_share = true
};
 
static const char *svg_types[] = {
"image/svg",
"image/svg+xml"
};
 
 
CONTENT_FACTORY_REGISTER_TYPES(svg, svg_types, svg_content_handler);
 
 
/programs/network/netsurf/netsurf/image/svg.h
0,0 → 1,28
/*
* Copyright 2007-2008 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/svg (interface).
*/
 
#ifndef _NETSURF_IMAGE_SVG_H_
#define _NETSURF_IMAGE_SVG_H_
 
nserror svg_init(void);
 
#endif
/programs/network/netsurf/netsurf/image/video.c
0,0 → 1,201
/*
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <gst/gst.h>
 
#include "content/content_factory.h"
#include "content/content_protected.h"
#include "image/video.h"
 
typedef struct nsvideo_content {
struct content base;
 
GstElement *playbin;
GstElement *appsrc;
} nsvideo_content;
 
static gboolean nsvideo_bus_call(GstBus *bus, GstMessage *msg,
nsvideo_content *video)
{
switch (GST_MESSAGE_TYPE(msg)) {
case GST_MESSAGE_ERROR:
break;
case GST_MESSAGE_EOS:
break;
default:
break;
}
 
return TRUE;
}
 
static void nsvideo_need_data_event(GstElement *playbin, guint size,
nsvideo_content *video)
{
}
 
static void nsvideo_enough_data_event(GstElement *playbin,
nsvideo_content *video)
{
}
 
static void nsvideo_source_event(GObject *object, GObject *orig,
GParamSpec *pspec, nsvideo_content *video)
{
g_object_get(orig, pspec->name, &video->appsrc, NULL);
 
g_signal_connect(video->appsrc, "need-data",
G_CALLBACK(nsvideo_need_data_event), video);
g_signal_connect(video->appsrc, "enough-data",
G_CALLBACK(nsvideo_enough_data_event), video);
}
 
static nserror nsvideo_create(const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache,
const char *fallback_charset, bool quirks,
struct content **c)
{
nsvideo_content *video;
nserror error;
GstBus *bus;
 
video = calloc(1, sizeof(nsvideo_content));
if (video == NULL)
return NSERROR_NOMEM;
 
error = content__init(&video->base, handler, imime_type, params,
llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(video);
return error;
}
 
error = llcache_handle_force_stream(llcache);
if (error != NSERROR_OK) {
free(video);
return error;
}
 
video->playbin = gst_element_factory_make("playbin2", NULL);
if (video->playbin == NULL) {
free(video);
return NSERROR_NOMEM;
}
 
bus = gst_pipeline_get_bus(GST_PIPELINE(video->playbin));
gst_bus_add_watch(bus, (GstBusFunc) nsvideo_bus_call, video);
gst_object_unref(bus);
 
g_object_set(video->playbin, "uri", "appsrc://", NULL);
g_signal_connect(video->playbin, "deep-notify::source",
G_CALLBACK(nsvideo_source_event), video);
 
/** \todo Create appsink & register with playbin */
 
gst_element_set_state(video->playbin, GST_STATE_PLAYING);
*c = (struct content *) video;
 
return NSERROR_OK;
}
 
static bool nsvideo_process_data(struct content *c, const char *data,
unsigned int size)
{
nsvideo_content *video = (nsvideo_content *) c;
GstBuffer *buffer;
GstFlowReturn ret;
 
buffer = gst_buffer_new();
GST_BUFFER_DATA(buffer) = (guint8 *) data;
GST_BUFFER_SIZE(buffer) = (gsize) size;
 
/* Send data to appsrc */
g_signal_emit_by_name(video->appsrc, "push-buffer", buffer, &ret);
 
return ret == GST_FLOW_OK;
}
 
static bool nsvideo_convert(struct content *c)
{
nsvideo_content *video = (nsvideo_content *) c;
GstFlowReturn ret;
 
/* Tell appsrc we're done */
g_signal_emit_by_name(video->appsrc, "end-of-stream", &ret);
 
/* Appsink will flag DONE on receipt of first frame */
 
return ret == GST_FLOW_OK;
}
 
static void nsvideo_destroy(struct content *c)
{
nsvideo_content *video = (nsvideo_content *) c;
 
gst_element_set_state(video->playbin, GST_STATE_NULL);
gst_object_unref(video->playbin);
}
 
static bool nsvideo_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
/** \todo Implement */
return true;
}
 
static nserror nsvideo_clone(const struct content *old, struct content **newc)
{
/** \todo Implement */
return NSERROR_CLONE_FAILED;
}
 
static content_type nsvideo_type(void)
{
/** \todo Lies */
return CONTENT_IMAGE;
}
 
static void *nsvideo_get_internal(const struct content *c, void *context)
{
/** \todo Return pointer to bitmap containing current frame, if any? */
return NULL;
}
 
static const content_handler nsvideo_content_handler = {
.create = nsvideo_create,
.process_data = nsvideo_process_data,
.data_complete = nsvideo_convert,
.destroy = nsvideo_destroy,
.redraw = nsvideo_redraw,
.clone = nsvideo_clone,
.type = nsvideo_type,
.get_internal = nsvideo_get_internal,
/* Can't share videos because we stream them */
.no_share = true
};
 
static const char *nsvideo_types[] = {
"video/mp4",
"video/webm"
};
 
CONTENT_FACTORY_REGISTER_TYPES(nsvideo, nsvideo_types,
nsvideo_content_handler);
 
/programs/network/netsurf/netsurf/image/video.h
0,0 → 1,26
/*
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_IMAGE_VIDEO_H_
#define NETSURF_IMAGE_VIDEO_H_
 
#include "utils/errors.h"
 
nserror nsvideo_init(void);
 
#endif
/programs/network/netsurf/netsurf/image/webp.c
0,0 → 1,229
/*
* Copyright 2010 Chris Young <chris@unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/webp (libwebp implementation).
*
*/
 
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <webp/decode.h>
#include "desktop/plotters.h"
#include "image/bitmap.h"
#include "content/content_protected.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
 
typedef struct webp_content
{
struct content base;
 
struct bitmap *bitmap; /**< Created NetSurf bitmap */
} webp_content;
 
 
static nserror webp_create(const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
webp_content *webp;
nserror error;
 
webp = calloc(1, sizeof(webp_content));
if (webp == NULL)
return NSERROR_NOMEM;
 
error = content__init(&webp->base, handler, imime_type, params,
llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(webp);
return error;
}
 
*c = (struct content *) webp;
 
return NSERROR_OK;
}
 
/**
* Convert a CONTENT_WEBP for display.
*
* No conversion is necessary. We merely read the WebP dimensions.
*/
 
static bool webp_convert(struct content *c)
{
webp_content *webp = (webp_content *)c;
union content_msg_data msg_data;
const uint8_t *data;
unsigned char *imagebuf = NULL;
unsigned long size;
int width = 0, height = 0;
char *title;
int res = 0;
uint8_t *res_p = NULL;
 
data = (uint8_t *)content__get_source_data(c, &size);
 
res = WebPGetInfo(data, size, &width, &height);
if (res == 0) {
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
webp->bitmap = bitmap_create(width, height, BITMAP_NEW | BITMAP_OPAQUE);
if (!webp->bitmap) {
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
imagebuf = bitmap_get_buffer(webp->bitmap);
if (!imagebuf) {
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
unsigned int row_width = bitmap_get_rowstride(webp->bitmap);
 
res_p = WebPDecodeRGBAInto(data, size, imagebuf,
row_width * height, row_width);
if (res_p == NULL) {
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
c->width = width;
c->height = height;
 
/* set title */
title = messages_get_buff("WebPTitle",
nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
c->width, c->height);
if (title != NULL) {
content__set_title(c, title);
free(title);
}
 
bitmap_modified(webp->bitmap);
 
content_set_ready(c);
content_set_done(c);
 
content_set_status(c, "");
return true;
}
 
 
/**
* Destroy a CONTENT_WEBP and free all resources it owns.
*/
 
static void webp_destroy(struct content *c)
{
webp_content *webp = (webp_content *)c;
 
if (webp->bitmap != NULL)
bitmap_destroy(webp->bitmap);
}
 
 
/**
* Redraw a CONTENT_WEBP.
*/
 
static bool webp_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
webp_content *webp = (webp_content *)c;
bitmap_flags_t flags = BITMAPF_NONE;
 
if (data->repeat_x)
flags |= BITMAPF_REPEAT_X;
if (data->repeat_y)
flags |= BITMAPF_REPEAT_Y;
 
return ctx->plot->bitmap(data->x, data->y, data->width, data->height,
webp->bitmap, data->background_colour, flags);
}
 
 
static nserror webp_clone(const struct content *old, struct content **newc)
{
webp_content *webp;
nserror error;
 
webp = calloc(1, sizeof(webp_content));
if (webp == NULL)
return NSERROR_NOMEM;
 
error = content__clone(old, &webp->base);
if (error != NSERROR_OK) {
content_destroy(&webp->base);
return error;
}
 
/* Simply replay convert */
if (old->status == CONTENT_STATUS_READY ||
old->status == CONTENT_STATUS_DONE) {
if (webp_convert(&webp->base) == false) {
content_destroy(&webp->base);
return NSERROR_CLONE_FAILED;
}
}
 
*newc = (struct content *) webp;
 
return NSERROR_OK;
}
 
static void *webp_get_internal(const struct content *c, void *context)
{
webp_content *webp = (webp_content *)c;
 
return webp->bitmap;
}
 
static content_type webp_content_type(void)
{
return CONTENT_IMAGE;
}
 
static const content_handler webp_content_handler = {
.create = webp_create,
.data_complete = webp_convert,
.destroy = webp_destroy,
.redraw = webp_redraw,
.clone = webp_clone,
.get_internal = webp_get_internal,
.type = webp_content_type,
.no_share = false,
};
 
static const char *webp_types[] = {
"image/webp"
};
 
CONTENT_FACTORY_REGISTER_TYPES(webp, webp_types, webp_content_handler);
 
/programs/network/netsurf/netsurf/image/webp.h
0,0 → 1,28
/*
* Copyright 2010 Chris Young <chris@unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for image/webp (libwebp interface).
*/
 
#ifndef _NETSURF_WEBP_H_
#define _NETSURF_WEBP_H_
 
nserror webp_init(void);
 
#endif
/programs/network/netsurf/netsurf/javascript/WebIDL/Makefile
0,0 → 1,38
#!/bin/make
#
# Create the WebIDL for core DOM and HTML spec directly from
# downloaded specifications. The resulting IDL is pretty close but
# carries the example text etc. and should be manually cleaned up and
# tagged with the retrival date and source URL
#
# needs debin packages: curl w3m tidy html-xml-utils
#
# Copyright 2012 Vincent Sanders
# MIT licenced
 
.PHONY:all clean
 
all: dom.idl html.idl
 
.INTERMEDIATE:dom-spec.html dom-spec.xml dom-idl.html html-spec.html html-spec.xml html-idl.html
 
 
dom-spec.html:
curl -s http://dom.spec.whatwg.org/ -o $@
 
html-spec.html:
curl -s http://www.whatwg.org/specs/web-apps/current-work/ -o $@
 
%-spec.xml: %-spec.html
-tidy -q -f $@.errors --new-blocklevel-tags header,hgroup,figure -o $@ -asxml $<
 
%-idl.html: %-spec.xml
hxselect pre.idl < $< > $@
 
%.idl: %-idl.html
cat $< | w3m -dump -T text/html >$@
 
 
 
clean:
${RM} dom.idl html.idl dom-spec.html dom-spec.xml dom-idl.html html-spec.html html-spec.xml html-idl.html
/programs/network/netsurf/netsurf/javascript/WebIDL/console.idl
0,0 → 1,20
// de facto set of features for console object
// https://developer.mozilla.org/en-US/docs/DOM/console
// http://msdn.microsoft.com/en-us/library/dd565625%28v=vs.85%29.aspx#consolelogging
// 31st October
// Yay for non-standard standards
 
interface Console {
void debug(DOMString msg, Substitition... subst);
void dir(JSObject object);
void error(DOMString msg, Substitition... subst);
void group();
void groupCollapsed();
void groupEnd();
void info(DOMString msg, Substitition... subst);
void log(DOMString msg, Substitition... subst);
void time(DOMString timerName);
void timeEnd(DOMString timerName);
void trace();
void warn(DOMString msg, Substitition... subst);
};
/programs/network/netsurf/netsurf/javascript/WebIDL/dom.idl
0,0 → 1,446
// DOM core WebIDL
// retrived from http://dom.spec.whatwg.org/
// 23rd October 2012
 
 
 
exception DOMException {
const unsigned short INDEX_SIZE_ERR = 1;
const unsigned short DOMSTRING_SIZE_ERR = 2; // historical
const unsigned short HIERARCHY_REQUEST_ERR = 3;
const unsigned short WRONG_DOCUMENT_ERR = 4;
const unsigned short INVALID_CHARACTER_ERR = 5;
const unsigned short NO_DATA_ALLOWED_ERR = 6; // historical
const unsigned short NO_MODIFICATION_ALLOWED_ERR = 7;
const unsigned short NOT_FOUND_ERR = 8;
const unsigned short NOT_SUPPORTED_ERR = 9;
const unsigned short INUSE_ATTRIBUTE_ERR = 10; // historical
const unsigned short INVALID_STATE_ERR = 11;
const unsigned short SYNTAX_ERR = 12;
const unsigned short INVALID_MODIFICATION_ERR = 13;
const unsigned short NAMESPACE_ERR = 14;
const unsigned short INVALID_ACCESS_ERR = 15;
const unsigned short VALIDATION_ERR = 16; // historical
const unsigned short TYPE_MISMATCH_ERR = 17;
const unsigned short SECURITY_ERR = 18;
const unsigned short NETWORK_ERR = 19;
const unsigned short ABORT_ERR = 20;
const unsigned short URL_MISMATCH_ERR = 21;
const unsigned short QUOTA_EXCEEDED_ERR = 22;
const unsigned short TIMEOUT_ERR = 23;
const unsigned short INVALID_NODE_TYPE_ERR = 24;
const unsigned short DATA_CLONE_ERR = 25;
unsigned short code;
};
 
interface DOMError {
readonly attribute DOMString name;
};
 
[Constructor(DOMString type, optional EventInit eventInitDict)]
interface Event {
readonly attribute DOMString type;
readonly attribute EventTarget? target;
readonly attribute EventTarget? currentTarget;
 
const unsigned short NONE = 0;
const unsigned short CAPTURING_PHASE = 1;
const unsigned short AT_TARGET = 2;
const unsigned short BUBBLING_PHASE = 3;
readonly attribute unsigned short eventPhase;
 
void stopPropagation();
void stopImmediatePropagation();
 
readonly attribute boolean bubbles;
readonly attribute boolean cancelable;
void preventDefault();
readonly attribute boolean defaultPrevented;
 
readonly attribute boolean isTrusted;
readonly attribute DOMTimeStamp timeStamp;
 
void initEvent(DOMString type, boolean bubbles, boolean cancelable);
};
 
dictionary EventInit {
boolean bubbles;
boolean cancelable;
};
 
[Constructor(DOMString type, optional CustomEventInit eventInitDict)]
interface CustomEvent : Event {
readonly attribute any detail;
};
 
dictionary CustomEventInit : EventInit {
any detail;
};
 
interface EventTarget {
void addEventListener(DOMString type, EventListener? callback, optional boolean capture = false);
void removeEventListener(DOMString type, EventListener? callback, optional boolean capture = false);
boolean dispatchEvent(Event event);
};
 
callback interface EventListener {
void handleEvent(Event event);
};
 
[Constructor(MutationCallback callback)]
interface MutationObserver {
void observe(Node target, MutationObserverInit options);
void disconnect();
sequence<MutationRecord> takeRecords();
};
 
callback MutationCallback = void (sequence<MutationRecord> mutations, MutationObserver observer);
 
dictionary MutationObserverInit {
boolean childList;
boolean attributes;
boolean characterData;
boolean subtree;
boolean attributeOldValue;
boolean characterDataOldValue;
sequence<DOMString> attributeFilter;
};
 
interface MutationRecord {
readonly attribute DOMString type;
readonly attribute Node target;
readonly attribute NodeList addedNodes;
readonly attribute NodeList removedNodes;
readonly attribute Node? previousSibling;
readonly attribute Node? nextSibling;
readonly attribute DOMString? attributeName;
readonly attribute DOMString? attributeNamespace;
readonly attribute DOMString? oldValue;
};
 
interface Node : EventTarget {
const unsigned short ELEMENT_NODE = 1;
const unsigned short ATTRIBUTE_NODE = 2; // historical
const unsigned short TEXT_NODE = 3;
const unsigned short CDATA_SECTION_NODE = 4; // historical
const unsigned short ENTITY_REFERENCE_NODE = 5; // historical
const unsigned short ENTITY_NODE = 6; // historical
const unsigned short PROCESSING_INSTRUCTION_NODE = 7;
const unsigned short COMMENT_NODE = 8;
const unsigned short DOCUMENT_NODE = 9;
const unsigned short DOCUMENT_TYPE_NODE = 10;
const unsigned short DOCUMENT_FRAGMENT_NODE = 11;
const unsigned short NOTATION_NODE = 12; // historical
readonly attribute unsigned short nodeType;
readonly attribute DOMString nodeName;
 
readonly attribute DOMString? baseURI;
 
readonly attribute Document? ownerDocument;
readonly attribute Node? parentNode;
readonly attribute Element? parentElement;
boolean hasChildNodes();
readonly attribute NodeList childNodes;
readonly attribute Node? firstChild;
readonly attribute Node? lastChild;
readonly attribute Node? previousSibling;
readonly attribute Node? nextSibling;
 
attribute DOMString? nodeValue;
attribute DOMString? textContent;
Node insertBefore(Node node, Node? child);
Node appendChild(Node node);
Node replaceChild(Node node, Node child);
Node removeChild(Node child);
void normalize();
 
 
Node cloneNode(optional boolean deep = true);
boolean isEqualNode(Node? node);
 
const unsigned short DOCUMENT_POSITION_DISCONNECTED = 0x01;
const unsigned short DOCUMENT_POSITION_PRECEDING = 0x02;
const unsigned short DOCUMENT_POSITION_FOLLOWING = 0x04;
const unsigned short DOCUMENT_POSITION_CONTAINS = 0x08;
const unsigned short DOCUMENT_POSITION_CONTAINED_BY = 0x10;
const unsigned short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20; // historical
unsigned short compareDocumentPosition(Node other);
boolean contains(Node? other);
 
DOMString? lookupPrefix(DOMString? namespace);
DOMString? lookupNamespaceURI(DOMString? prefix);
boolean isDefaultNamespace(DOMString? namespace);
};
 
[Constructor]
interface Document : Node {
readonly attribute DOMImplementation implementation;
readonly attribute DOMString URL;
readonly attribute DOMString documentURI;
readonly attribute DOMString compatMode;
readonly attribute DOMString characterSet;
readonly attribute DOMString contentType;
 
readonly attribute DocumentType? doctype;
readonly attribute Element? documentElement;
HTMLCollection getElementsByTagName(DOMString localName);
HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
HTMLCollection getElementsByClassName(DOMString classNames);
Element? getElementById(DOMString elementId);
 
Element createElement(DOMString localName);
Element createElementNS(DOMString? namespace, DOMString qualifiedName);
DocumentFragment createDocumentFragment();
Text createTextNode(DOMString data);
Comment createComment(DOMString data);
ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data);
 
Node importNode(Node node, optional boolean deep = true);
Node adoptNode(Node node);
 
Event createEvent(DOMString interface);
 
Range createRange();
 
// NodeFilter.SHOW_ALL = 0xFFFFFFFF
NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
TreeWalker createTreeWalker(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
 
// NEW
void prepend((Node or DOMString)... nodes);
void append((Node or DOMString)... nodes);
};
 
interface XMLDocument : Document {};
 
interface DOMImplementation {
DocumentType createDocumentType(DOMString qualifiedName, DOMString publicId, DOMString systemId);
XMLDocument createDocument(DOMString? namespace, [TreatNullAs=EmptyString] DOMString qualifiedName, DocumentType? doctype);
Document createHTMLDocument(optional DOMString title);
 
boolean hasFeature(DOMString feature, [TreatNullAs=EmptyString] DOMString version);
};
 
interface DocumentFragment : Node {
// NEW
void prepend((Node or DOMString)... nodes);
void append((Node or DOMString)... nodes);
};
 
interface DocumentType : Node {
readonly attribute DOMString name;
readonly attribute DOMString publicId;
readonly attribute DOMString systemId;
 
// NEW
void before((Node or DOMString)... nodes);
void after((Node or DOMString)... nodes);
void replace((Node or DOMString)... nodes);
void remove();
};
 
interface Element : Node {
readonly attribute DOMString? namespaceURI;
readonly attribute DOMString? prefix;
readonly attribute DOMString localName;
readonly attribute DOMString tagName;
 
attribute DOMString id;
attribute DOMString className;
readonly attribute DOMTokenList classList;
 
readonly attribute Attr[] attributes;
DOMString? getAttribute(DOMString name);
DOMString? getAttributeNS(DOMString? namespace, DOMString localName);
void setAttribute(DOMString name, DOMString value);
void setAttributeNS(DOMString? namespace, DOMString name, DOMString value);
void removeAttribute(DOMString name);
void removeAttributeNS(DOMString? namespace, DOMString localName);
boolean hasAttribute(DOMString name);
boolean hasAttributeNS(DOMString? namespace, DOMString localName);
 
HTMLCollection getElementsByTagName(DOMString localName);
HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
HTMLCollection getElementsByClassName(DOMString classNames);
 
readonly attribute HTMLCollection children;
readonly attribute Element? firstElementChild;
readonly attribute Element? lastElementChild;
readonly attribute Element? previousElementSibling;
readonly attribute Element? nextElementSibling;
readonly attribute unsigned long childElementCount;
 
 
// NEW
void prepend((Node or DOMString)... nodes);
void append((Node or DOMString)... nodes);
void before((Node or DOMString)... nodes);
void after((Node or DOMString)... nodes);
void replace((Node or DOMString)... nodes);
void remove();
};
 
interface Attr {
readonly attribute DOMString name;
attribute DOMString value;
 
readonly attribute DOMString? namespaceURI;
readonly attribute DOMString? prefix;
readonly attribute DOMString localName;
};
 
interface CharacterData : Node {
[TreatNullAs=EmptyString] attribute DOMString data;
readonly attribute unsigned long length;
DOMString substringData(unsigned long offset, unsigned long count);
void appendData(DOMString data);
void insertData(unsigned long offset, DOMString data);
void deleteData(unsigned long offset, unsigned long count);
void replaceData(unsigned long offset, unsigned long count, DOMString data);
 
// NEW
void before((Node or DOMString)... nodes);
void after((Node or DOMString)... nodes);
void replace((Node or DOMString)... nodes);
void remove();
};
 
interface Text : CharacterData {
Text splitText(unsigned long offset);
readonly attribute DOMString wholeText;
};
 
interface ProcessingInstruction : CharacterData {
readonly attribute DOMString target;
};
 
interface Comment : CharacterData {
};
 
interface Range {
readonly attribute Node startContainer;
readonly attribute unsigned long startOffset;
readonly attribute Node endContainer;
readonly attribute unsigned long endOffset;
readonly attribute boolean collapsed;
readonly attribute Node commonAncestorContainer;
 
void setStart(Node refNode, unsigned long offset);
void setEnd(Node refNode, unsigned long offset);
void setStartBefore(Node refNode);
void setStartAfter(Node refNode);
void setEndBefore(Node refNode);
void setEndAfter(Node refNode);
void collapse(boolean toStart);
void selectNode(Node refNode);
void selectNodeContents(Node refNode);
 
const unsigned short START_TO_START = 0;
const unsigned short START_TO_END = 1;
const unsigned short END_TO_END = 2;
const unsigned short END_TO_START = 3;
short compareBoundaryPoints(unsigned short how, Range sourceRange);
 
void deleteContents();
DocumentFragment extractContents();
DocumentFragment cloneContents();
void insertNode(Node node);
void surroundContents(Node newParent);
 
Range cloneRange();
void detach();
 
boolean isPointInRange(Node node, unsigned long offset);
short comparePoint(Node node, unsigned long offset);
 
boolean intersectsNode(Node node);
 
stringifier;
};
 
interface NodeIterator {
readonly attribute Node root;
readonly attribute Node? referenceNode;
readonly attribute boolean pointerBeforeReferenceNode;
readonly attribute unsigned long whatToShow;
readonly attribute NodeFilter? filter;
 
Node? nextNode();
Node? previousNode();
 
void detach();
};
 
interface TreeWalker {
readonly attribute Node root;
readonly attribute unsigned long whatToShow;
readonly attribute NodeFilter? filter;
 
attribute Node currentNode;
 
Node? parentNode();
Node? firstChild();
Node? lastChild();
Node? previousSibling();
Node? nextSibling();
Node? previousNode();
Node? nextNode();
};
 
callback interface NodeFilter {
// Constants for acceptNode()
const unsigned short FILTER_ACCEPT = 1;
const unsigned short FILTER_REJECT = 2;
const unsigned short FILTER_SKIP = 3;
 
// Constants for whatToShow
const unsigned long SHOW_ALL = 0xFFFFFFFF;
const unsigned long SHOW_ELEMENT = 0x1;
const unsigned long SHOW_ATTRIBUTE = 0x2; // historical
const unsigned long SHOW_TEXT = 0x4;
const unsigned long SHOW_CDATA_SECTION = 0x8; // historical
const unsigned long SHOW_ENTITY_REFERENCE = 0x10; // historical
const unsigned long SHOW_ENTITY = 0x20; // historical
const unsigned long SHOW_PROCESSING_INSTRUCTION = 0x40;
const unsigned long SHOW_COMMENT = 0x80;
const unsigned long SHOW_DOCUMENT = 0x100;
const unsigned long SHOW_DOCUMENT_TYPE = 0x200;
const unsigned long SHOW_DOCUMENT_FRAGMENT = 0x400;
const unsigned long SHOW_NOTATION = 0x800; // historical
 
unsigned short acceptNode(Node node);
};
 
[ArrayClass]
interface NodeList {
getter Node? item(unsigned long index);
readonly attribute unsigned long length;
};
 
interface HTMLCollection {
readonly attribute unsigned long length;
getter Element? item(unsigned long index);
getter object? namedItem(DOMString name); // only returns Element
};
 
[NoInterfaceObject]
interface DOMStringList {
readonly attribute unsigned long length;
getter DOMString? item(unsigned long index);
boolean contains(DOMString string);
};
 
interface DOMTokenList {
readonly attribute unsigned long length;
getter DOMString? item(unsigned long index);
boolean contains(DOMString token);
void add(DOMString... tokens);
void remove(DOMString... tokens);
boolean toggle(DOMString token, optional boolean force);
stringifier;
};
 
interface DOMSettableTokenList : DOMTokenList {
attribute DOMString value;
};
 
/programs/network/netsurf/netsurf/javascript/WebIDL/html.idl
0,0 → 1,2194
// HTML WebIDL
// retrived from http://www.whatwg.org/specs/web-apps/current-work/
// 23rd October 2012
 
 
interface HTMLAllCollection : HTMLCollection {
// inherits length and item()
legacycaller getter object? namedItem(DOMString name); // overrides inherited namedItem()
HTMLAllCollection tags(DOMString tagName);
};
 
interface HTMLFormControlsCollection : HTMLCollection {
// inherits length and item()
legacycaller getter object? namedItem(DOMString name); // overrides inherited namedItem()
};
 
interface RadioNodeList : NodeList {
attribute DOMString value;
};
 
interface HTMLOptionsCollection : HTMLCollection {
// inherits item()
attribute unsigned long length; // overrides inherited length
legacycaller getter object? namedItem(DOMString name); // overrides inherited namedItem()
setter creator void (unsigned long index, HTMLOptionElement? option);
void add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null);
void remove(long index);
attribute long selectedIndex;
};
 
interface HTMLPropertiesCollection : HTMLCollection {
// inherits length and item()
getter PropertyNodeList? namedItem(DOMString name); // overrides inherited namedItem()
readonly attribute DOMString[] names;
};
 
typedef sequence<any> PropertyValueArray;
 
interface PropertyNodeList : NodeList {
PropertyValueArray getValues();
};
 
interface DOMStringMap {
getter DOMString (DOMString name);
setter void (DOMString name, DOMString value);
creator void (DOMString name, DOMString value);
deleter void (DOMString name);
};
 
interface DOMElementMap {
getter Element (DOMString name);
setter void (DOMString name, Element value);
creator void (DOMString name, Element value);
deleter void (DOMString name);
};
 
[NoInterfaceObject]
interface Transferable { };
 
[OverrideBuiltins]
partial interface Document {
// resource metadata management
[PutForwards=href] readonly attribute Location? location;
attribute DOMString domain;
readonly attribute DOMString referrer;
attribute DOMString cookie;
readonly attribute DOMString lastModified;
readonly attribute DOMString readyState;
 
// DOM tree accessors
getter object (DOMString name);
attribute DOMString title;
attribute DOMString dir;
attribute HTMLElement? body;
readonly attribute HTMLHeadElement? head;
readonly attribute HTMLCollection images;
readonly attribute HTMLCollection embeds;
readonly attribute HTMLCollection plugins;
readonly attribute HTMLCollection links;
readonly attribute HTMLCollection forms;
readonly attribute HTMLCollection scripts;
NodeList getElementsByName(DOMString elementName);
NodeList getItems(optional DOMString typeNames); // microdata
readonly attribute DOMElementMap cssElementMap;
 
// dynamic markup insertion
Document open(optional DOMString type, optional DOMString replace);
WindowProxy open(DOMString url, DOMString name, DOMString features, optional boolean replace);
void close();
void write(DOMString... text);
void writeln(DOMString... text);
 
// user interaction
readonly attribute WindowProxy? defaultView;
readonly attribute Element? activeElement;
boolean hasFocus();
attribute DOMString designMode;
boolean execCommand(DOMString commandId);
boolean execCommand(DOMString commandId, boolean showUI);
boolean execCommand(DOMString commandId, boolean showUI, DOMString value);
boolean queryCommandEnabled(DOMString commandId);
boolean queryCommandIndeterm(DOMString commandId);
boolean queryCommandState(DOMString commandId);
boolean queryCommandSupported(DOMString commandId);
DOMString queryCommandValue(DOMString commandId);
readonly attribute HTMLCollection commands;
 
// event handler IDL attributes
attribute EventHandler onabort;
attribute EventHandler onblur;
attribute EventHandler oncancel;
attribute EventHandler oncanplay;
attribute EventHandler oncanplaythrough;
attribute EventHandler onchange;
attribute EventHandler onclick;
attribute EventHandler onclose;
attribute EventHandler oncontextmenu;
attribute EventHandler oncuechange;
attribute EventHandler ondblclick;
attribute EventHandler ondrag;
attribute EventHandler ondragend;
attribute EventHandler ondragenter;
attribute EventHandler ondragleave;
attribute EventHandler ondragover;
attribute EventHandler ondragstart;
attribute EventHandler ondrop;
attribute EventHandler ondurationchange;
attribute EventHandler onemptied;
attribute EventHandler onended;
attribute OnErrorEventHandler onerror;
attribute EventHandler onfocus;
attribute EventHandler oninput;
attribute EventHandler oninvalid;
attribute EventHandler onkeydown;
attribute EventHandler onkeypress;
attribute EventHandler onkeyup;
attribute EventHandler onload;
attribute EventHandler onloadeddata;
attribute EventHandler onloadedmetadata;
attribute EventHandler onloadstart;
attribute EventHandler onmousedown;
attribute EventHandler onmousemove;
attribute EventHandler onmouseout;
attribute EventHandler onmouseover;
attribute EventHandler onmouseup;
attribute EventHandler onmousewheel;
attribute EventHandler onpause;
attribute EventHandler onplay;
attribute EventHandler onplaying;
attribute EventHandler onprogress;
attribute EventHandler onratechange;
attribute EventHandler onreset;
attribute EventHandler onscroll;
attribute EventHandler onseeked;
attribute EventHandler onseeking;
attribute EventHandler onselect;
attribute EventHandler onshow;
attribute EventHandler onstalled;
attribute EventHandler onsubmit;
attribute EventHandler onsuspend;
attribute EventHandler ontimeupdate;
attribute EventHandler onvolumechange;
attribute EventHandler onwaiting;
 
// special event handler IDL attributes that only apply to Document objects
[LenientThis] attribute EventHandler onreadystatechange;
};
 
partial interface XMLDocument {
boolean load(DOMString url);
};
 
interface HTMLElement : Element {
// metadata attributes
attribute DOMString title;
attribute DOMString lang;
attribute boolean translate;
attribute DOMString dir;
readonly attribute DOMStringMap dataset;
 
// microdata
attribute boolean itemScope;
[PutForwards=value] readonly attribute DOMSettableTokenList itemType;
attribute DOMString itemId;
[PutForwards=value] readonly attribute DOMSettableTokenList itemRef;
[PutForwards=value] readonly attribute DOMSettableTokenList itemProp;
readonly attribute HTMLPropertiesCollection properties;
attribute any itemValue; // acts as DOMString on setting
 
// user interaction
attribute boolean hidden;
void click();
attribute long tabIndex;
void focus();
void blur();
attribute DOMString accessKey;
readonly attribute DOMString accessKeyLabel;
attribute boolean draggable;
[PutForwards=value] readonly attribute DOMSettableTokenList dropzone;
attribute DOMString contentEditable;
readonly attribute boolean isContentEditable;
attribute HTMLMenuElement? contextMenu;
attribute boolean spellcheck;
void forceSpellCheck();
 
// command API
readonly attribute DOMString? commandType;
readonly attribute DOMString? commandLabel;
readonly attribute DOMString? commandIcon;
readonly attribute boolean? commandHidden;
readonly attribute boolean? commandDisabled;
readonly attribute boolean? commandChecked;
 
// styling
readonly attribute CSSStyleDeclaration style;
 
// event handler IDL attributes
attribute EventHandler onabort;
attribute EventHandler onblur;
attribute EventHandler oncancel;
attribute EventHandler oncanplay;
attribute EventHandler oncanplaythrough;
attribute EventHandler onchange;
attribute EventHandler onclick;
attribute EventHandler onclose;
attribute EventHandler oncontextmenu;
attribute EventHandler oncuechange;
attribute EventHandler ondblclick;
attribute EventHandler ondrag;
attribute EventHandler ondragend;
attribute EventHandler ondragenter;
attribute EventHandler ondragleave;
attribute EventHandler ondragover;
attribute EventHandler ondragstart;
attribute EventHandler ondrop;
attribute EventHandler ondurationchange;
attribute EventHandler onemptied;
attribute EventHandler onended;
attribute OnErrorEventHandler onerror;
attribute EventHandler onfocus;
attribute EventHandler oninput;
attribute EventHandler oninvalid;
attribute EventHandler onkeydown;
attribute EventHandler onkeypress;
attribute EventHandler onkeyup;
attribute EventHandler onload;
attribute EventHandler onloadeddata;
attribute EventHandler onloadedmetadata;
attribute EventHandler onloadstart;
attribute EventHandler onmousedown;
attribute EventHandler onmousemove;
attribute EventHandler onmouseout;
attribute EventHandler onmouseover;
attribute EventHandler onmouseup;
attribute EventHandler onmousewheel;
attribute EventHandler onpause;
attribute EventHandler onplay;
attribute EventHandler onplaying;
attribute EventHandler onprogress;
attribute EventHandler onratechange;
attribute EventHandler onreset;
attribute EventHandler onscroll;
attribute EventHandler onseeked;
attribute EventHandler onseeking;
attribute EventHandler onselect;
attribute EventHandler onshow;
attribute EventHandler onstalled;
attribute EventHandler onsubmit;
attribute EventHandler onsuspend;
attribute EventHandler ontimeupdate;
attribute EventHandler onvolumechange;
attribute EventHandler onwaiting;
};
 
interface HTMLUnknownElement : HTMLElement { };
 
interface HTMLHtmlElement : HTMLElement {};
 
interface HTMLHeadElement : HTMLElement {};
 
interface HTMLTitleElement : HTMLElement {
attribute DOMString text;
};
 
interface HTMLBaseElement : HTMLElement {
attribute DOMString href;
attribute DOMString target;
};
 
interface HTMLLinkElement : HTMLElement {
attribute boolean disabled;
attribute DOMString href;
attribute DOMString rel;
readonly attribute DOMTokenList relList;
attribute DOMString media;
attribute DOMString hreflang;
attribute DOMString type;
[PutForwards=value] readonly attribute DOMSettableTokenList sizes;
};
HTMLLinkElement implements LinkStyle;
 
interface HTMLMetaElement : HTMLElement {
attribute DOMString name;
attribute DOMString httpEquiv;
attribute DOMString content;
};
 
interface HTMLStyleElement : HTMLElement {
attribute boolean disabled;
attribute DOMString media;
attribute DOMString type;
attribute boolean scoped;
};
HTMLStyleElement implements LinkStyle;
 
interface HTMLScriptElement : HTMLElement {
attribute DOMString src;
attribute boolean async;
attribute boolean defer;
attribute DOMString type;
attribute DOMString charset;
attribute DOMString text;
};
 
interface HTMLBodyElement : HTMLElement {
attribute EventHandler onafterprint;
attribute EventHandler onbeforeprint;
attribute EventHandler onbeforeunload;
attribute EventHandler onblur;
attribute OnErrorEventHandler onerror;
attribute EventHandler onfocus;
attribute EventHandler onhashchange;
attribute EventHandler onload;
attribute EventHandler onmessage;
attribute EventHandler onoffline;
attribute EventHandler ononline;
attribute EventHandler onpopstate;
attribute EventHandler onpagehide;
attribute EventHandler onpageshow;
attribute EventHandler onresize;
attribute EventHandler onscroll;
attribute EventHandler onstorage;
attribute EventHandler onunload;
};
 
interface HTMLHeadingElement : HTMLElement {};
 
interface HTMLParagraphElement : HTMLElement {};
 
interface HTMLHRElement : HTMLElement {};
 
interface HTMLPreElement : HTMLElement {};
 
interface HTMLQuoteElement : HTMLElement {
attribute DOMString cite;
};
 
interface HTMLOListElement : HTMLElement {
attribute boolean reversed;
attribute long start;
attribute DOMString type;
};
 
interface HTMLUListElement : HTMLElement {};
 
interface HTMLLIElement : HTMLElement {
attribute long value;
};
 
interface HTMLDListElement : HTMLElement {};
 
interface HTMLDivElement : HTMLElement {};
 
interface HTMLAnchorElement : HTMLElement {
stringifier attribute DOMString href;
attribute DOMString target;
 
attribute DOMString download;
attribute DOMString ping;
 
attribute DOMString rel;
readonly attribute DOMTokenList relList;
attribute DOMString media;
attribute DOMString hreflang;
attribute DOMString type;
 
attribute DOMString text;
 
// URL decomposition IDL attributes
attribute DOMString protocol;
attribute DOMString host;
attribute DOMString hostname;
attribute DOMString port;
attribute DOMString pathname;
attribute DOMString search;
attribute DOMString hash;
};
 
interface HTMLDataElement : HTMLElement {
attribute DOMString value;
};
 
interface HTMLTimeElement : HTMLElement {
attribute DOMString datetime;
};
 
interface HTMLSpanElement : HTMLElement {};
 
interface HTMLBRElement : HTMLElement {};
 
interface HTMLModElement : HTMLElement {
attribute DOMString cite;
attribute DOMString dateTime;
};
 
[NamedConstructor=Image(),
NamedConstructor=Image(unsigned long width),
NamedConstructor=Image(unsigned long width, unsigned long height)]
interface HTMLImageElement : HTMLElement {
attribute DOMString alt;
attribute DOMString src;
attribute DOMString srcset;
attribute DOMString crossOrigin;
attribute DOMString useMap;
attribute boolean isMap;
attribute unsigned long width;
attribute unsigned long height;
readonly attribute unsigned long naturalWidth;
readonly attribute unsigned long naturalHeight;
readonly attribute boolean complete;
};
 
interface HTMLIFrameElement : HTMLElement {
attribute DOMString src;
attribute DOMString srcdoc;
attribute DOMString name;
[PutForwards=value] readonly attribute DOMSettableTokenList sandbox;
attribute boolean seamless;
attribute DOMString width;
attribute DOMString height;
readonly attribute Document? contentDocument;
readonly attribute WindowProxy? contentWindow;
};
 
interface HTMLEmbedElement : HTMLElement {
attribute DOMString src;
attribute DOMString type;
attribute DOMString width;
attribute DOMString height;
legacycaller any (any... arguments);
};
 
interface HTMLObjectElement : HTMLElement {
attribute DOMString data;
attribute DOMString type;
attribute boolean typeMustMatch;
attribute DOMString name;
attribute DOMString useMap;
readonly attribute HTMLFormElement? form;
attribute DOMString width;
attribute DOMString height;
readonly attribute Document? contentDocument;
readonly attribute WindowProxy? contentWindow;
 
readonly attribute boolean willValidate;
readonly attribute ValidityState validity;
readonly attribute DOMString validationMessage;
boolean checkValidity();
void setCustomValidity(DOMString error);
 
legacycaller any (any... arguments);
};
 
interface HTMLParamElement : HTMLElement {
attribute DOMString name;
attribute DOMString value;
};
 
interface HTMLVideoElement : HTMLMediaElement {
attribute unsigned long width;
attribute unsigned long height;
readonly attribute unsigned long videoWidth;
readonly attribute unsigned long videoHeight;
attribute DOMString poster;
};
 
[NamedConstructor=Audio(),
NamedConstructor=Audio(DOMString src)]
interface HTMLAudioElement : HTMLMediaElement {};
 
interface HTMLSourceElement : HTMLElement {
attribute DOMString src;
attribute DOMString type;
attribute DOMString media;
};
 
interface HTMLTrackElement : HTMLElement {
attribute DOMString kind;
attribute DOMString src;
attribute DOMString srclang;
attribute DOMString label;
attribute boolean default;
 
const unsigned short NONE = 0;
const unsigned short LOADING = 1;
const unsigned short LOADED = 2;
const unsigned short ERROR = 3;
readonly attribute unsigned short readyState;
 
readonly attribute TextTrack track;
};
 
interface HTMLMediaElement : HTMLElement {
 
// error state
readonly attribute MediaError? error;
 
// network state
attribute DOMString src;
readonly attribute DOMString currentSrc;
attribute DOMString crossOrigin;
const unsigned short NETWORK_EMPTY = 0;
const unsigned short NETWORK_IDLE = 1;
const unsigned short NETWORK_LOADING = 2;
const unsigned short NETWORK_NO_SOURCE = 3;
readonly attribute unsigned short networkState;
attribute DOMString preload;
readonly attribute TimeRanges buffered;
void load();
DOMString canPlayType(DOMString type);
 
// ready state
const unsigned short HAVE_NOTHING = 0;
const unsigned short HAVE_METADATA = 1;
const unsigned short HAVE_CURRENT_DATA = 2;
const unsigned short HAVE_FUTURE_DATA = 3;
const unsigned short HAVE_ENOUGH_DATA = 4;
readonly attribute unsigned short readyState;
readonly attribute boolean seeking;
 
// playback state
attribute double currentTime;
void fastSeek(double time);
readonly attribute unrestricted double duration;
readonly attribute Date startDate;
readonly attribute boolean paused;
attribute double defaultPlaybackRate;
attribute double playbackRate;
readonly attribute TimeRanges played;
readonly attribute TimeRanges seekable;
readonly attribute boolean ended;
attribute boolean autoplay;
attribute boolean loop;
void play();
void pause();
 
// media controller
attribute DOMString mediaGroup;
attribute MediaController? controller;
 
// controls
attribute boolean controls;
attribute double volume;
attribute boolean muted;
attribute boolean defaultMuted;
 
// tracks
readonly attribute AudioTrackList audioTracks;
readonly attribute VideoTrackList videoTracks;
readonly attribute TextTrackList textTracks;
TextTrack addTextTrack(DOMString kind, optional DOMString label, optional DOMString language);
};
 
interface MediaError {
const unsigned short MEDIA_ERR_ABORTED = 1;
const unsigned short MEDIA_ERR_NETWORK = 2;
const unsigned short MEDIA_ERR_DECODE = 3;
const unsigned short MEDIA_ERR_SRC_NOT_SUPPORTED = 4;
readonly attribute unsigned short code;
};
 
interface AudioTrackList : EventTarget {
readonly attribute unsigned long length;
getter AudioTrack (unsigned long index);
AudioTrack? getTrackById(DOMString id);
 
attribute EventHandler onchange;
attribute EventHandler onaddtrack;
attribute EventHandler onremovetrack;
};
 
interface AudioTrack {
readonly attribute DOMString id;
readonly attribute DOMString kind;
readonly attribute DOMString label;
readonly attribute DOMString language;
attribute boolean enabled;
};
 
interface VideoTrackList : EventTarget {
readonly attribute unsigned long length;
getter VideoTrack (unsigned long index);
VideoTrack? getTrackById(DOMString id);
readonly attribute long selectedIndex;
 
attribute EventHandler onchange;
attribute EventHandler onaddtrack;
attribute EventHandler onremovetrack;
};
 
interface VideoTrack {
readonly attribute DOMString id;
readonly attribute DOMString kind;
readonly attribute DOMString label;
readonly attribute DOMString language;
attribute boolean selected;
};
 
enum MediaControllerPlaybackState { "waiting", "playing", "ended" };
[Constructor]
interface MediaController : EventTarget {
readonly attribute unsigned short readyState; // uses HTMLMediaElement.readyState's values
 
readonly attribute TimeRanges buffered;
readonly attribute TimeRanges seekable;
readonly attribute unrestricted double duration;
attribute double currentTime;
 
readonly attribute boolean paused;
readonly attribute MediaControllerPlaybackState playbackState;
readonly attribute TimeRanges played;
void pause();
void unpause();
void play(); // calls play() on all media elements as well
 
attribute double defaultPlaybackRate;
attribute double playbackRate;
 
attribute double volume;
attribute boolean muted;
 
attribute EventHandler onemptied;
attribute EventHandler onloadedmetadata;
attribute EventHandler onloadeddata;
attribute EventHandler oncanplay;
attribute EventHandler oncanplaythrough;
attribute EventHandler onplaying;
attribute EventHandler onended;
attribute EventHandler onwaiting;
 
attribute EventHandler ondurationchange;
attribute EventHandler ontimeupdate;
attribute EventHandler onplay;
attribute EventHandler onpause;
attribute EventHandler onratechange;
attribute EventHandler onvolumechange;
};
 
interface TextTrackList : EventTarget {
readonly attribute unsigned long length;
getter TextTrack (unsigned long index);
 
attribute EventHandler onaddtrack;
attribute EventHandler onremovetrack;
};
 
enum TextTrackMode { "disabled", "hidden", "showing" };
interface TextTrack : EventTarget {
readonly attribute DOMString kind;
readonly attribute DOMString label;
readonly attribute DOMString language;
readonly attribute DOMString inBandMetadataTrackDispatchType;
 
attribute TextTrackMode mode;
 
readonly attribute TextTrackCueList? cues;
readonly attribute TextTrackCueList? activeCues;
 
void addCue(TextTrackCue cue);
void removeCue(TextTrackCue cue);
 
attribute EventHandler oncuechange;
};
 
interface TextTrackCueList {
readonly attribute unsigned long length;
getter TextTrackCue (unsigned long index);
TextTrackCue? getCueById(DOMString id);
};
 
enum AutoKeyword { "auto" };
[Constructor(double startTime, double endTime, DOMString text)]
interface TextTrackCue : EventTarget {
readonly attribute TextTrack? track;
 
attribute DOMString id;
attribute double startTime;
attribute double endTime;
attribute boolean pauseOnExit;
attribute DOMString vertical;
attribute boolean snapToLines;
attribute (long or AutoKeyword) line;
attribute long position;
attribute long size;
attribute DOMString align;
attribute DOMString text;
DocumentFragment getCueAsHTML();
 
attribute EventHandler onenter;
attribute EventHandler onexit;
};
 
interface TimeRanges {
readonly attribute unsigned long length;
double start(unsigned long index);
double end(unsigned long index);
};
 
[Constructor(DOMString type, optional TrackEventInit eventInitDict)]
interface TrackEvent : Event {
readonly attribute object? track;
};
 
dictionary TrackEventInit : EventInit {
object? track;
};
 
interface HTMLCanvasElement : HTMLElement {
attribute unsigned long width;
attribute unsigned long height;
 
DOMString toDataURL(optional DOMString type, any... arguments);
DOMString toDataURLHD(optional DOMString type, any... arguments);
void toBlob(FileCallback? _callback, optional DOMString type, any... arguments);
void toBlobHD(FileCallback? _callback, optional DOMString type, any... arguments);
 
object? getContext(DOMString contextId, any... arguments);
boolean supportsContext(DOMString contextId, any... arguments);
};
 
interface CanvasRenderingContext2D {
 
// back-reference to the canvas
readonly attribute HTMLCanvasElement canvas;
 
// state
void save(); // push state on state stack
void restore(); // pop state stack and restore state
 
// transformations (default transform is the identity matrix)
attribute SVGMatrix currentTransform;
void scale(unrestricted double x, unrestricted double y);
void rotate(unrestricted double angle);
void translate(unrestricted double x, unrestricted double y);
void transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
void setTransform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
void resetTransform();
 
// compositing
attribute unrestricted double globalAlpha; // (default 1.0)
attribute DOMString globalCompositeOperation; // (default source-over)
 
// image smoothing
attribute boolean imageSmoothingEnabled; // (default true)
 
// colors and styles (see also the CanvasDrawingStyles interface)
attribute (DOMString or CanvasGradient or CanvasPattern) strokeStyle; // (default black)
attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (default black)
CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1);
CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1);
CanvasPattern createPattern((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, DOMString repetition);
 
// shadows
attribute unrestricted double shadowOffsetX; // (default 0)
attribute unrestricted double shadowOffsetY; // (default 0)
attribute unrestricted double shadowBlur; // (default 0)
attribute DOMString shadowColor; // (default transparent black)
 
// rects
void clearRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
void fillRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
void strokeRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
 
// path API (see also CanvasPathMethods)
void beginPath();
void fill();
void fill(Path path);
void stroke();
void stroke(Path path);
void drawSystemFocusRing(Element element);
void drawSystemFocusRing(Path path, Element element);
boolean drawCustomFocusRing(Element element);
boolean drawCustomFocusRing(Path path, Element element);
void scrollPathIntoView();
void scrollPathIntoView(Path path);
void clip();
void clip(Path path);
void resetClip();
boolean isPointInPath(unrestricted double x, unrestricted double y);
boolean isPointInPath(Path path, unrestricted double x, unrestricted double y);
 
// text (see also the CanvasDrawingStyles interface)
void fillText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
void strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
TextMetrics measureText(DOMString text);
 
// drawing images
void drawImage((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, unrestricted double dx, unrestricted double dy);
void drawImage((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh);
void drawImage((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, unrestricted double sx, unrestricted double sy, unrestricted double sw, unrestricted double sh, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh);
 
// hit regions
void addHitRegion(HitRegionOptions options);
void removeHitRegion(HitRegionOptions options);
 
// pixel manipulation
ImageData createImageData(double sw, double sh);
ImageData createImageData(ImageData imagedata);
ImageData createImageDataHD(double sw, double sh);
ImageData getImageData(double sx, double sy, double sw, double sh);
ImageData getImageDataHD(double sx, double sy, double sw, double sh);
void putImageData(ImageData imagedata, double dx, double dy);
void putImageData(ImageData imagedata, double dx, double dy, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight);
void putImageDataHD(ImageData imagedata, double dx, double dy);
void putImageDataHD(ImageData imagedata, double dx, double dy, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight);
};
CanvasRenderingContext2D implements CanvasDrawingStyles;
CanvasRenderingContext2D implements CanvasPathMethods;
 
[NoInterfaceObject]
interface CanvasDrawingStyles {
// line caps/joins
attribute unrestricted double lineWidth; // (default 1)
attribute DOMString lineCap; // "butt", "round", "square" (default "butt")
attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter")
attribute unrestricted double miterLimit; // (default 10)
 
// dashed lines
void setLineDash(sequence<unrestricted double> segments); // default empty
sequence<unrestricted double> getLineDash();
attribute unrestricted double lineDashOffset;
 
// text
attribute DOMString font; // (default 10px sans-serif)
attribute DOMString textAlign; // "start", "end", "left", "right", "center" (default: "start")
attribute DOMString textBaseline; // "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" (default: "alphabetic")
};
 
[NoInterfaceObject]
interface CanvasPathMethods {
// shared path API methods
void closePath();
void moveTo(unrestricted double x, unrestricted double y);
void lineTo(unrestricted double x, unrestricted double y);
void quadraticCurveTo(unrestricted double cpx, unrestricted double cpy, unrestricted double x, unrestricted double y);
void bezierCurveTo(unrestricted double cp1x, unrestricted double cp1y, unrestricted double cp2x, unrestricted double cp2y, unrestricted double x, unrestricted double y);
void arcTo(unrestricted double x1, unrestricted double y1, unrestricted double x2, unrestricted double y2, unrestricted double radius);
void arcTo(unrestricted double x1, unrestricted double y1, unrestricted double x2, unrestricted double y2, unrestricted double radiusX, unrestricted double radiusY, unrestricted double rotation);
void rect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
void arc(unrestricted double x, unrestricted double y, unrestricted double radius, unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false);
void ellipse(unrestricted double x, unrestricted double y, unrestricted double radiusX, unrestricted double radiusY, unrestricted double rotation, unrestricted double startAngle, unrestricted double endAngle, boolean anticlockwise);
};
 
interface CanvasGradient {
// opaque object
void addColorStop(double offset, DOMString color);
};
 
interface CanvasPattern {
// opaque object
void setTransform(SVGMatrix transform);
};
 
interface TextMetrics {
// x-direction
readonly attribute double width; // advance width
readonly attribute double actualBoundingBoxLeft;
readonly attribute double actualBoundingBoxRight;
 
// y-direction
readonly attribute double fontBoundingBoxAscent;
readonly attribute double fontBoundingBoxDescent;
readonly attribute double actualBoundingBoxAscent;
readonly attribute double actualBoundingBoxDescent;
readonly attribute double emHeightAscent;
readonly attribute double emHeightDescent;
readonly attribute double hangingBaseline;
readonly attribute double alphabeticBaseline;
readonly attribute double ideographicBaseline;
};
 
dictionary HitRegionOptions {
Path? path = null;
DOMString id = "";
DOMString? parentID = null;
DOMString cursor = "inherit";
// for control-backed regions:
Element? control = null;
// for unbacked regions:
DOMString? label = null;
DOMString? role = null;
};
 
interface ImageData {
readonly attribute unsigned long width;
readonly attribute unsigned long height;
readonly attribute Uint8ClampedArray data;
};
 
[Constructor(optional Element scope)]
interface DrawingStyle { };
DrawingStyle implements CanvasDrawingStyles;
 
[Constructor,
Constructor(Path path),
Constructor(DOMString d)]
interface Path {
void addPath(Path path, SVGMatrix? transformation);
void addPathByStrokingPath(Path path, CanvasDrawingStyles styles, SVGMatrix? transformation);
void addText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
void addPathByStrokingText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
void addText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, Path path, optional unrestricted double maxWidth);
void addPathByStrokingText(DOMString text, CanvasDrawingStyles styles, SVGMatrix? transformation, Path path, optional unrestricted double maxWidth);
};
Path implements CanvasPathMethods;
 
partial interface Screen {
readonly attribute double canvasResolution;
};
 
partial interface MouseEvent {
readonly attribute DOMString? region;
};
 
partial dictionary MouseEventInit {
DOMString? region;
};
 
interface HTMLMapElement : HTMLElement {
attribute DOMString name;
readonly attribute HTMLCollection areas;
readonly attribute HTMLCollection images;
};
 
interface HTMLAreaElement : HTMLElement {
attribute DOMString alt;
attribute DOMString coords;
attribute DOMString shape;
stringifier attribute DOMString href;
attribute DOMString target;
 
attribute DOMString download;
attribute DOMString ping;
 
attribute DOMString rel;
readonly attribute DOMTokenList relList;
attribute DOMString media;
attribute DOMString hreflang;
attribute DOMString type;
 
// URL decomposition IDL attributes
attribute DOMString protocol;
attribute DOMString host;
attribute DOMString hostname;
attribute DOMString port;
attribute DOMString pathname;
attribute DOMString search;
attribute DOMString hash;
};
 
interface HTMLTableElement : HTMLElement {
attribute HTMLTableCaptionElement? caption;
HTMLElement createCaption();
void deleteCaption();
attribute HTMLTableSectionElement? tHead;
HTMLElement createTHead();
void deleteTHead();
attribute HTMLTableSectionElement? tFoot;
HTMLElement createTFoot();
void deleteTFoot();
readonly attribute HTMLCollection tBodies;
HTMLElement createTBody();
readonly attribute HTMLCollection rows;
HTMLElement insertRow(optional long index);
void deleteRow(long index);
};
 
interface HTMLTableCaptionElement : HTMLElement {};
 
interface HTMLTableColElement : HTMLElement {
attribute unsigned long span;
};
 
interface HTMLTableSectionElement : HTMLElement {
readonly attribute HTMLCollection rows;
HTMLElement insertRow(optional long index);
void deleteRow(long index);
};
 
interface HTMLTableRowElement : HTMLElement {
readonly attribute long rowIndex;
readonly attribute long sectionRowIndex;
readonly attribute HTMLCollection cells;
HTMLElement insertCell(optional long index);
void deleteCell(long index);
};
 
interface HTMLTableDataCellElement : HTMLTableCellElement {};
 
interface HTMLTableHeaderCellElement : HTMLTableCellElement {
attribute DOMString scope;
attribute DOMString abbr;
};
 
interface HTMLTableCellElement : HTMLElement {
attribute unsigned long colSpan;
attribute unsigned long rowSpan;
[PutForwards=value] readonly attribute DOMSettableTokenList headers;
readonly attribute long cellIndex;
};
 
[OverrideBuiltins]
interface HTMLFormElement : HTMLElement {
attribute DOMString acceptCharset;
attribute DOMString action;
attribute DOMString autocomplete;
attribute DOMString enctype;
attribute DOMString encoding;
attribute DOMString method;
attribute DOMString name;
attribute boolean noValidate;
attribute DOMString target;
 
readonly attribute HTMLFormControlsCollection elements;
readonly attribute long length;
getter Element (unsigned long index);
getter object (DOMString name);
 
void submit();
void reset();
boolean checkValidity();
};
 
interface HTMLFieldSetElement : HTMLElement {
attribute boolean disabled;
readonly attribute HTMLFormElement? form;
attribute DOMString name;
 
readonly attribute DOMString type;
 
readonly attribute HTMLFormControlsCollection elements;
 
readonly attribute boolean willValidate;
readonly attribute ValidityState validity;
readonly attribute DOMString validationMessage;
boolean checkValidity();
void setCustomValidity(DOMString error);
};
 
interface HTMLLegendElement : HTMLElement {
readonly attribute HTMLFormElement? form;
};
 
interface HTMLLabelElement : HTMLElement {
readonly attribute HTMLFormElement? form;
attribute DOMString htmlFor;
readonly attribute HTMLElement? control;
};
 
interface HTMLInputElement : HTMLElement {
attribute DOMString accept;
attribute DOMString alt;
attribute DOMString autocomplete;
attribute boolean autofocus;
attribute boolean defaultChecked;
attribute boolean checked;
attribute DOMString dirName;
attribute boolean disabled;
readonly attribute HTMLFormElement? form;
readonly attribute FileList? files;
attribute DOMString formAction;
attribute DOMString formEnctype;
attribute DOMString formMethod;
attribute boolean formNoValidate;
attribute DOMString formTarget;
attribute unsigned long height;
attribute boolean indeterminate;
attribute DOMString inputMode;
readonly attribute HTMLElement? list;
attribute DOMString max;
attribute long maxLength;
attribute DOMString min;
attribute boolean multiple;
attribute DOMString name;
attribute DOMString pattern;
attribute DOMString placeholder;
attribute boolean readOnly;
attribute boolean required;
attribute unsigned long size;
attribute DOMString src;
attribute DOMString step;
attribute DOMString type;
attribute DOMString defaultValue;
[TreatNullAs=EmptyString] attribute DOMString value;
attribute Date? valueAsDate;
attribute unrestricted double valueAsNumber;
attribute unsigned long width;
 
void stepUp(optional long n);
void stepDown(optional long n);
 
readonly attribute boolean willValidate;
readonly attribute ValidityState validity;
readonly attribute DOMString validationMessage;
boolean checkValidity();
void setCustomValidity(DOMString error);
 
readonly attribute NodeList labels;
 
void select();
attribute unsigned long selectionStart;
attribute unsigned long selectionEnd;
attribute DOMString selectionDirection;
 
void setRangeText(DOMString replacement);
void setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode);
 
void setSelectionRange(unsigned long start, unsigned long end, optional DOMString direction);
};
 
interface HTMLButtonElement : HTMLElement {
attribute boolean autofocus;
attribute boolean disabled;
readonly attribute HTMLFormElement? form;
attribute DOMString formAction;
attribute DOMString formEnctype;
attribute DOMString formMethod;
attribute boolean formNoValidate;
attribute DOMString formTarget;
attribute DOMString name;
attribute DOMString type;
attribute DOMString value;
 
readonly attribute boolean willValidate;
readonly attribute ValidityState validity;
readonly attribute DOMString validationMessage;
boolean checkValidity();
void setCustomValidity(DOMString error);
 
readonly attribute NodeList labels;
};
 
interface HTMLSelectElement : HTMLElement {
attribute boolean autofocus;
attribute boolean disabled;
readonly attribute HTMLFormElement? form;
attribute boolean multiple;
attribute DOMString name;
attribute boolean required;
attribute unsigned long size;
 
readonly attribute DOMString type;
 
readonly attribute HTMLOptionsCollection options;
attribute unsigned long length;
getter Element item(unsigned long index);
object namedItem(DOMString name);
void add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null);
void remove(long index);
setter creator void (unsigned long index, HTMLOptionElement? option);
 
readonly attribute HTMLCollection selectedOptions;
attribute long selectedIndex;
attribute DOMString value;
 
readonly attribute boolean willValidate;
readonly attribute ValidityState validity;
readonly attribute DOMString validationMessage;
boolean checkValidity();
void setCustomValidity(DOMString error);
 
readonly attribute NodeList labels;
};
 
interface HTMLDataListElement : HTMLElement {
readonly attribute HTMLCollection options;
};
 
interface HTMLOptGroupElement : HTMLElement {
attribute boolean disabled;
attribute DOMString label;
};
 
[NamedConstructor=Option(),
NamedConstructor=Option(DOMString text),
NamedConstructor=Option(DOMString text, DOMString value),
NamedConstructor=Option(DOMString text, DOMString value, boolean defaultSelected),
NamedConstructor=Option(DOMString text, DOMString value, boolean defaultSelected, boolean selected)]
interface HTMLOptionElement : HTMLElement {
attribute boolean disabled;
readonly attribute HTMLFormElement? form;
attribute DOMString label;
attribute boolean defaultSelected;
attribute boolean selected;
attribute DOMString value;
 
attribute DOMString text;
readonly attribute long index;
};
 
interface HTMLTextAreaElement : HTMLElement {
attribute DOMString autocomplete;
attribute boolean autofocus;
attribute unsigned long cols;
attribute DOMString dirName;
attribute boolean disabled;
readonly attribute HTMLFormElement? form;
attribute DOMString inputMode;
attribute long maxLength;
attribute DOMString name;
attribute DOMString placeholder;
attribute boolean readOnly;
attribute boolean required;
attribute unsigned long rows;
attribute DOMString wrap;
 
readonly attribute DOMString type;
attribute DOMString defaultValue;
[TreatNullAs=EmptyString] attribute DOMString value;
readonly attribute unsigned long textLength;
 
readonly attribute boolean willValidate;
readonly attribute ValidityState validity;
readonly attribute DOMString validationMessage;
boolean checkValidity();
void setCustomValidity(DOMString error);
 
readonly attribute NodeList labels;
 
void select();
attribute unsigned long selectionStart;
attribute unsigned long selectionEnd;
attribute DOMString selectionDirection;
 
void setRangeText(DOMString replacement);
void setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode);
 
void setSelectionRange(unsigned long start, unsigned long end, optional DOMString direction);
};
 
interface HTMLKeygenElement : HTMLElement {
attribute boolean autofocus;
attribute DOMString challenge;
attribute boolean disabled;
readonly attribute HTMLFormElement? form;
attribute DOMString keytype;
attribute DOMString name;
 
readonly attribute DOMString type;
 
readonly attribute boolean willValidate;
readonly attribute ValidityState validity;
readonly attribute DOMString validationMessage;
boolean checkValidity();
void setCustomValidity(DOMString error);
 
readonly attribute NodeList labels;
};
 
interface HTMLOutputElement : HTMLElement {
[PutForwards=value] readonly attribute DOMSettableTokenList htmlFor;
readonly attribute HTMLFormElement? form;
attribute DOMString name;
 
readonly attribute DOMString type;
attribute DOMString defaultValue;
attribute DOMString value;
 
readonly attribute boolean willValidate;
readonly attribute ValidityState validity;
readonly attribute DOMString validationMessage;
boolean checkValidity();
void setCustomValidity(DOMString error);
 
readonly attribute NodeList labels;
};
 
interface HTMLProgressElement : HTMLElement {
attribute double value;
attribute double max;
readonly attribute double position;
readonly attribute NodeList labels;
};
 
interface HTMLMeterElement : HTMLElement {
attribute double value;
attribute double min;
attribute double max;
attribute double low;
attribute double high;
attribute double optimum;
readonly attribute NodeList labels;
};
 
interface ValidityState {
readonly attribute boolean valueMissing;
readonly attribute boolean typeMismatch;
readonly attribute boolean patternMismatch;
readonly attribute boolean tooLong;
readonly attribute boolean rangeUnderflow;
readonly attribute boolean rangeOverflow;
readonly attribute boolean stepMismatch;
readonly attribute boolean customError;
readonly attribute boolean valid;
};
 
interface HTMLDetailsElement : HTMLElement {
attribute boolean open;
};
 
interface HTMLCommandElement : HTMLElement {
attribute DOMString type;
attribute DOMString label;
attribute DOMString icon;
attribute boolean disabled;
attribute boolean checked;
attribute DOMString radiogroup;
readonly attribute HTMLElement? command;
};
 
interface HTMLMenuElement : HTMLElement {
attribute DOMString type;
attribute DOMString label;
};
 
interface HTMLDialogElement : HTMLElement {
attribute boolean open;
attribute DOMString returnValue;
void show(optional (MouseEvent or Element) anchor);
void showModal(optional (MouseEvent or Element) anchor);
void close(optional DOMString returnValue);
};
 
[NamedPropertiesObject]
interface Window : EventTarget {
// the current browsing context
[Unforgeable] readonly attribute WindowProxy window;
[Replaceable] readonly attribute WindowProxy self;
[Unforgeable] readonly attribute Document document;
attribute DOMString name;
[PutForwards=href, Unforgeable] readonly attribute Location location;
readonly attribute History history;
[Replaceable] readonly attribute BarProp locationbar;
[Replaceable] readonly attribute BarProp menubar;
[Replaceable] readonly attribute BarProp personalbar;
[Replaceable] readonly attribute BarProp scrollbars;
[Replaceable] readonly attribute BarProp statusbar;
[Replaceable] readonly attribute BarProp toolbar;
attribute DOMString status;
void close();
void stop();
void focus();
void blur();
 
// other browsing contexts
[Replaceable] readonly attribute WindowProxy frames;
[Replaceable] readonly attribute unsigned long length;
[Unforgeable] readonly attribute WindowProxy top;
attribute WindowProxy? opener;
readonly attribute WindowProxy parent;
readonly attribute Element? frameElement;
WindowProxy open(optional DOMString url, optional DOMString target, optional DOMString features, optional boolean replace);
getter WindowProxy (unsigned long index);
getter object (DOMString name);
 
// the user agent
readonly attribute Navigator navigator;
 
readonly attribute External external;
readonly attribute ApplicationCache applicationCache;
 
// user prompts
void alert(DOMString message);
boolean confirm(DOMString message);
DOMString? prompt(DOMString message, optional DOMString default);
void print();
any showModalDialog(DOMString url, optional any argument);
 
// cross-document messaging
void postMessage(any message, DOMString targetOrigin, optional sequence<Transferable> transfer);
 
// event handler IDL attributes
attribute EventHandler onabort;
attribute EventHandler onafterprint;
attribute EventHandler onbeforeprint;
attribute EventHandler onbeforeunload;
attribute EventHandler onblur;
attribute EventHandler oncancel;
attribute EventHandler oncanplay;
attribute EventHandler oncanplaythrough;
attribute EventHandler onchange;
attribute EventHandler onclick;
attribute EventHandler onclose;
attribute EventHandler oncontextmenu;
attribute EventHandler oncuechange;
attribute EventHandler ondblclick;
attribute EventHandler ondrag;
attribute EventHandler ondragend;
attribute EventHandler ondragenter;
attribute EventHandler ondragleave;
attribute EventHandler ondragover;
attribute EventHandler ondragstart;
attribute EventHandler ondrop;
attribute EventHandler ondurationchange;
attribute EventHandler onemptied;
attribute EventHandler onended;
attribute OnErrorEventHandler onerror;
attribute EventHandler onfocus;
attribute EventHandler onhashchange;
attribute EventHandler oninput;
attribute EventHandler oninvalid;
attribute EventHandler onkeydown;
attribute EventHandler onkeypress;
attribute EventHandler onkeyup;
attribute EventHandler onload;
attribute EventHandler onloadeddata;
attribute EventHandler onloadedmetadata;
attribute EventHandler onloadstart;
attribute EventHandler onmessage;
attribute EventHandler onmousedown;
attribute EventHandler onmousemove;
attribute EventHandler onmouseout;
attribute EventHandler onmouseover;
attribute EventHandler onmouseup;
attribute EventHandler onmousewheel;
attribute EventHandler onoffline;
attribute EventHandler ononline;
attribute EventHandler onpause;
attribute EventHandler onplay;
attribute EventHandler onplaying;
attribute EventHandler onpagehide;
attribute EventHandler onpageshow;
attribute EventHandler onpopstate;
attribute EventHandler onprogress;
attribute EventHandler onratechange;
attribute EventHandler onreset;
attribute EventHandler onresize;
attribute EventHandler onscroll;
attribute EventHandler onseeked;
attribute EventHandler onseeking;
attribute EventHandler onselect;
attribute EventHandler onshow;
attribute EventHandler onstalled;
attribute EventHandler onstorage;
attribute EventHandler onsubmit;
attribute EventHandler onsuspend;
attribute EventHandler ontimeupdate;
attribute EventHandler onunload;
attribute EventHandler onvolumechange;
attribute EventHandler onwaiting;
};
 
interface BarProp {
attribute boolean visible;
};
 
interface History {
readonly attribute long length;
readonly attribute any state;
void go(optional long delta);
void back();
void forward();
void pushState(any data, DOMString title, optional DOMString url);
void replaceState(any data, DOMString title, optional DOMString url);
};
 
interface Location {
stringifier attribute DOMString href;
void assign(DOMString url);
void replace(DOMString url);
void reload();
 
// URL decomposition IDL attributes
attribute DOMString protocol;
attribute DOMString host;
attribute DOMString hostname;
attribute DOMString port;
attribute DOMString pathname;
attribute DOMString search;
attribute DOMString hash;
};
 
[Constructor(DOMString type, optional PopStateEventInit eventInitDict)]
interface PopStateEvent : Event {
readonly attribute any state;
};
 
dictionary PopStateEventInit : EventInit {
any state;
};
 
[Constructor(DOMString type, optional HashChangeEventInit eventInitDict)]
interface HashChangeEvent : Event {
readonly attribute DOMString oldURL;
readonly attribute DOMString newURL;
};
 
dictionary HashChangeEventInit : EventInit {
DOMString oldURL;
DOMString newURL;
};
 
[Constructor(DOMString type, optional PageTransitionEventInit eventInitDict)]
interface PageTransitionEvent : Event {
readonly attribute boolean persisted;
};
 
dictionary PageTransitionEventInit : EventInit {
boolean persisted;
};
 
interface BeforeUnloadEvent : Event {
attribute DOMString returnValue;
};
 
interface ApplicationCache : EventTarget {
 
// update status
const unsigned short UNCACHED = 0;
const unsigned short IDLE = 1;
const unsigned short CHECKING = 2;
const unsigned short DOWNLOADING = 3;
const unsigned short UPDATEREADY = 4;
const unsigned short OBSOLETE = 5;
readonly attribute unsigned short status;
 
// updates
void update();
void abort();
void swapCache();
 
// events
attribute EventHandler onchecking;
attribute EventHandler onerror;
attribute EventHandler onnoupdate;
attribute EventHandler ondownloading;
attribute EventHandler onprogress;
attribute EventHandler onupdateready;
attribute EventHandler oncached;
attribute EventHandler onobsolete;
};
 
[NoInterfaceObject]
interface NavigatorOnLine {
readonly attribute boolean onLine;
};
 
[TreatNonCallableAsNull]
callback EventHandlerNonNull = any (Event event);
typedef EventHandlerNonNull? EventHandler;
 
[TreatNonCallableAsNull]
callback OnErrorEventHandlerNonNull = any ((Event or DOMString) event, DOMString source, unsigned long lineno, unsigned long column);
typedef OnErrorEventHandlerNonNull? OnErrorEventHandler;
 
[NoInterfaceObject]
interface WindowBase64 {
DOMString btoa(DOMString btoa);
DOMString atob(DOMString atob);
};
Window implements WindowBase64;
 
[NoInterfaceObject]
interface WindowTimers {
long setTimeout(Function handler, optional long timeout, any... arguments);
long setTimeout(DOMString handler, optional long timeout, any... arguments);
void clearTimeout(long handle);
long setInterval(Function handler, optional long timeout, any... arguments);
long setInterval(DOMString handler, optional long timeout, any... arguments);
void clearInterval(long handle);
};
Window implements WindowTimers;
 
[NoInterfaceObject] interface WindowModal {
readonly attribute any dialogArguments;
attribute DOMString returnValue;
};
 
interface Navigator {
// objects implementing this interface also implement the interfaces given below
};
Navigator implements NavigatorID;
Navigator implements NavigatorOnLine;
Navigator implements NavigatorContentUtils;
Navigator implements NavigatorStorageUtils;
 
[NoInterfaceObject]
interface NavigatorID {
readonly attribute DOMString appName;
readonly attribute DOMString appVersion;
readonly attribute DOMString platform;
readonly attribute DOMString userAgent;
};
 
[NoInterfaceObject]
interface NavigatorContentUtils {
// content handler registration
void registerProtocolHandler(DOMString scheme, DOMString url, DOMString title);
void registerContentHandler(DOMString mimeType, DOMString url, DOMString title);
DOMString isProtocolHandlerRegistered(DOMString scheme, DOMString url);
DOMString isContentHandlerRegistered(DOMString mimeType, DOMString url);
void unregisterProtocolHandler(DOMString scheme, DOMString url);
void unregisterContentHandler(DOMString mimeType, DOMString url);
};
 
[NoInterfaceObject]
interface NavigatorStorageUtils {
void yieldForStorageUpdates();
};
 
interface External {
void AddSearchProvider(DOMString engineURL);
unsigned long IsSearchProviderInstalled(DOMString engineURL);
};
 
interface DataTransfer {
attribute DOMString dropEffect;
attribute DOMString effectAllowed;
 
readonly attribute DataTransferItemList items;
 
void setDragImage(Element image, long x, long y);
 
/* old interface */
readonly attribute DOMString[] types;
DOMString getData(DOMString format);
void setData(DOMString format, DOMString data);
void clearData(optional DOMString format);
readonly attribute FileList files;
};
 
interface DataTransferItemList {
readonly attribute unsigned long length;
getter DataTransferItem (unsigned long index);
deleter void (unsigned long index);
void clear();
 
DataTransferItem? add(DOMString data, DOMString type);
DataTransferItem? add(File data);
};
 
interface DataTransferItem {
readonly attribute DOMString kind;
readonly attribute DOMString type;
void getAsString(FunctionStringCallback? _callback);
 
File? getAsFile();
};
 
[Callback, NoInterfaceObject]
interface FunctionStringCallback {
void handleEvent(DOMString data);
};
 
[Constructor(DOMString type, optional DragEventInit eventInitDict)]
interface DragEvent : MouseEvent {
readonly attribute DataTransfer? dataTransfer;
};
 
dictionary DragEventInit : MouseEventInit {
DataTransfer? dataTransfer;
};
 
interface WorkerGlobalScope : EventTarget {
readonly attribute WorkerGlobalScope self;
readonly attribute WorkerLocation location;
 
void close();
attribute EventHandler onerror;
attribute EventHandler onoffline;
attribute EventHandler ononline;
};
WorkerGlobalScope implements WorkerUtils;
 
interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
void postMessage(any message, optional sequence<Transferable> transfer);
attribute EventHandler onmessage;
};
 
interface SharedWorkerGlobalScope : WorkerGlobalScope {
readonly attribute DOMString name;
readonly attribute ApplicationCache applicationCache;
attribute EventHandler onconnect;
};
 
[Constructor(DOMString type, optional ErrorEventInit eventInitDict)]
interface ErrorEvent : Event {
readonly attribute DOMString message;
readonly attribute DOMString filename;
readonly attribute unsigned long lineno;
readonly attribute unsigned long column;
};
 
dictionary ErrorEventInit : EventInit {
DOMString message;
DOMString filename;
unsigned long lineno;
unsigned long column;
};
 
[NoInterfaceObject]
interface AbstractWorker {
attribute EventHandler onerror;
 
};
 
[Constructor(DOMString scriptURL)]
interface Worker : EventTarget {
void terminate();
 
void postMessage(any message, optional sequence<Transferable> transfer);
attribute EventHandler onmessage;
};
Worker implements AbstractWorker;
 
[Constructor(DOMString scriptURL, optional DOMString name)]
interface SharedWorker : EventTarget {
readonly attribute MessagePort port;
};
SharedWorker implements AbstractWorker;
 
[NoInterfaceObject]
interface WorkerUtils {
void importScripts(DOMString... urls);
readonly attribute WorkerNavigator navigator;
};
WorkerUtils implements WindowTimers;
WorkerUtils implements WindowBase64;
 
interface WorkerNavigator {};
WorkerNavigator implements NavigatorID;
WorkerNavigator implements NavigatorOnLine;
 
interface WorkerLocation {
// URL decomposition IDL attributes
stringifier readonly attribute DOMString href;
readonly attribute DOMString protocol;
readonly attribute DOMString host;
readonly attribute DOMString hostname;
readonly attribute DOMString port;
readonly attribute DOMString pathname;
readonly attribute DOMString search;
readonly attribute DOMString hash;
};
 
[Constructor(DOMString type, optional MessageEventInit eventInitDict)]
interface MessageEvent : Event {
readonly attribute any data;
readonly attribute DOMString origin;
readonly attribute DOMString lastEventId;
readonly attribute (WindowProxy or MessagePort)? source;
readonly attribute MessagePort[]? ports;
};
 
dictionary MessageEventInit : EventInit {
any data;
DOMString origin;
DOMString lastEventId;
WindowProxy? source;
MessagePort[]? ports;
};
 
[Constructor(DOMString url, optional EventSourceInit eventSourceInitDict)]
interface EventSource : EventTarget {
readonly attribute DOMString url;
readonly attribute boolean withCredentials;
 
// ready state
const unsigned short CONNECTING = 0;
const unsigned short OPEN = 1;
const unsigned short CLOSED = 2;
readonly attribute unsigned short readyState;
 
// networking
attribute EventHandler onopen;
attribute EventHandler onmessage;
attribute EventHandler onerror;
void close();
};
 
dictionary EventSourceInit {
boolean withCredentials = false;
};
 
enum BinaryType { "blob", "arraybuffer" };
[Constructor(DOMString url, optional (DOMString or DOMString[]) protocols)]
interface WebSocket : EventTarget {
readonly attribute DOMString url;
 
// ready state
const unsigned short CONNECTING = 0;
const unsigned short OPEN = 1;
const unsigned short CLOSING = 2;
const unsigned short CLOSED = 3;
readonly attribute unsigned short readyState;
readonly attribute unsigned long bufferedAmount;
 
// networking
attribute EventHandler onopen;
attribute EventHandler onerror;
attribute EventHandler onclose;
readonly attribute DOMString extensions;
readonly attribute DOMString protocol;
void close([Clamp] optional unsigned short code, optional DOMString reason);
 
// messaging
attribute EventHandler onmessage;
attribute BinaryType binaryType;
void send(DOMString data);
void send(Blob data);
void send(ArrayBuffer data);
void send(ArrayBufferView data);
};
 
[Constructor(DOMString type, optional CloseEventInit eventInitDict)]
interface CloseEvent : Event {
readonly attribute boolean wasClean;
readonly attribute unsigned short code;
readonly attribute DOMString reason;
};
 
dictionary CloseEventInit : EventInit {
boolean wasClean;
unsigned short code;
DOMString reason;
};
 
[Constructor]
interface MessageChannel {
readonly attribute MessagePort port1;
readonly attribute MessagePort port2;
};
 
interface MessagePort : EventTarget {
void postMessage(any message, optional sequence<Transferable> transfer);
void start();
void close();
 
// event handlers
attribute EventHandler onmessage;
};
MessagePort implements Transferable;
 
interface Storage {
readonly attribute unsigned long length;
DOMString? key(unsigned long index);
getter DOMString getItem(DOMString key);
setter creator void setItem(DOMString key, DOMString value);
deleter void removeItem(DOMString key);
void clear();
};
 
[NoInterfaceObject]
interface WindowSessionStorage {
readonly attribute Storage sessionStorage;
};
Window implements WindowSessionStorage;
 
[NoInterfaceObject]
interface WindowLocalStorage {
readonly attribute Storage localStorage;
};
Window implements WindowLocalStorage;
 
[Constructor(DOMString type, optional StorageEventInit eventInitDict)]
interface StorageEvent : Event {
readonly attribute DOMString? key;
readonly attribute DOMString? oldValue;
readonly attribute DOMString? newValue;
readonly attribute DOMString url;
readonly attribute Storage? storageArea;
};
 
dictionary StorageEventInit : EventInit {
DOMString? key;
DOMString? oldValue;
DOMString? newValue;
DOMString url;
Storage? storageArea;
};
 
interface HTMLAppletElement : HTMLElement {
attribute DOMString align;
attribute DOMString alt;
attribute DOMString archive;
attribute DOMString code;
attribute DOMString codeBase;
attribute DOMString height;
attribute unsigned long hspace;
attribute DOMString name;
attribute DOMString _object; // the underscore is not part of the identifier
attribute unsigned long vspace;
attribute DOMString width;
};
 
interface HTMLMarqueeElement : HTMLElement {
attribute DOMString behavior;
attribute DOMString bgColor;
attribute DOMString direction;
attribute DOMString height;
attribute unsigned long hspace;
attribute long loop;
attribute unsigned long scrollAmount;
attribute unsigned long scrollDelay;
attribute boolean trueSpeed;
attribute unsigned long vspace;
attribute DOMString width;
 
attribute EventHandler onbounce;
attribute EventHandler onfinish;
attribute EventHandler onstart;
 
void start();
void stop();
};
 
interface HTMLFrameSetElement : HTMLElement {
attribute DOMString cols;
attribute DOMString rows;
attribute EventHandler onafterprint;
attribute EventHandler onbeforeprint;
attribute EventHandler onbeforeunload;
attribute EventHandler onblur;
attribute EventHandler onerror;
attribute EventHandler onfocus;
attribute EventHandler onhashchange;
attribute EventHandler onload;
attribute EventHandler onmessage;
attribute EventHandler onoffline;
attribute EventHandler ononline;
attribute EventHandler onpagehide;
attribute EventHandler onpageshow;
attribute EventHandler onpopstate;
attribute EventHandler onresize;
attribute EventHandler onscroll;
attribute EventHandler onstorage;
attribute EventHandler onunload;
};
 
interface HTMLFrameElement : HTMLElement {
attribute DOMString name;
attribute DOMString scrolling;
attribute DOMString src;
attribute DOMString frameBorder;
attribute DOMString longDesc;
attribute boolean noResize;
readonly attribute Document? contentDocument;
readonly attribute WindowProxy? contentWindow;
 
[TreatNullAs=EmptyString] attribute DOMString marginHeight;
[TreatNullAs=EmptyString] attribute DOMString marginWidth;
};
 
partial interface HTMLAnchorElement {
attribute DOMString coords;
attribute DOMString charset;
attribute DOMString name;
attribute DOMString rev;
attribute DOMString shape;
};
 
partial interface HTMLAreaElement {
attribute boolean noHref;
};
 
interface HTMLBaseFontElement : HTMLElement {
attribute DOMString color;
attribute DOMString face;
attribute long size;
 
};
 
partial interface HTMLBodyElement {
[TreatNullAs=EmptyString] attribute DOMString text;
[TreatNullAs=EmptyString] attribute DOMString link;
[TreatNullAs=EmptyString] attribute DOMString vLink;
[TreatNullAs=EmptyString] attribute DOMString aLink;
[TreatNullAs=EmptyString] attribute DOMString bgColor;
attribute DOMString background;
};
 
partial interface HTMLBRElement {
attribute DOMString clear;
};
 
partial interface HTMLTableCaptionElement {
attribute DOMString align;
};
 
partial interface HTMLTableColElement {
attribute DOMString align;
attribute DOMString ch;
attribute DOMString chOff;
attribute DOMString vAlign;
attribute DOMString width;
};
 
interface HTMLDirectoryElement : HTMLElement {
attribute boolean compact;
};
 
partial interface HTMLDivElement {
attribute DOMString align;
};
 
partial interface HTMLDListElement {
attribute boolean compact;
};
 
partial interface HTMLEmbedElement {
attribute DOMString align;
attribute DOMString name;
};
 
interface HTMLFontElement : HTMLElement {
[TreatNullAs=EmptyString] attribute DOMString color;
attribute DOMString face;
attribute DOMString size;
 
};
 
partial interface HTMLHeadingElement {
attribute DOMString align;
};
 
partial interface HTMLHRElement {
attribute DOMString align;
attribute DOMString color;
attribute boolean noShade;
attribute DOMString size;
attribute DOMString width;
};
 
partial interface HTMLHtmlElement {
attribute DOMString version;
};
 
partial interface HTMLIFrameElement {
attribute DOMString align;
attribute DOMString scrolling;
attribute DOMString frameBorder;
attribute DOMString longDesc;
 
[TreatNullAs=EmptyString] attribute DOMString marginHeight;
[TreatNullAs=EmptyString] attribute DOMString marginWidth;
};
 
partial interface HTMLImageElement {
attribute DOMString name;
attribute DOMString align;
attribute unsigned long hspace;
attribute unsigned long vspace;
attribute DOMString longDesc;
 
[TreatNullAs=EmptyString] attribute DOMString border;
};
 
partial interface HTMLInputElement {
attribute DOMString align;
attribute DOMString useMap;
};
 
partial interface HTMLLegendElement {
attribute DOMString align;
};
 
partial interface HTMLLIElement {
attribute DOMString type;
};
 
partial interface HTMLLinkElement {
attribute DOMString charset;
attribute DOMString rev;
attribute DOMString target;
};
 
partial interface HTMLMenuElement {
attribute boolean compact;
};
 
partial interface HTMLMetaElement {
attribute DOMString scheme;
};
 
partial interface HTMLObjectElement {
attribute DOMString align;
attribute DOMString archive;
attribute DOMString code;
attribute boolean declare;
attribute unsigned long hspace;
attribute DOMString standby;
attribute unsigned long vspace;
attribute DOMString codeBase;
attribute DOMString codeType;
 
[TreatNullAs=EmptyString] attribute DOMString border;
};
 
partial interface HTMLOListElement {
attribute boolean compact;
};
 
partial interface HTMLParagraphElement {
attribute DOMString align;
};
 
partial interface HTMLParamElement {
attribute DOMString type;
attribute DOMString valueType;
};
 
partial interface HTMLPreElement {
attribute long width;
};
 
partial interface HTMLScriptElement {
attribute DOMString event;
attribute DOMString htmlFor;
};
 
partial interface HTMLTableElement {
attribute DOMString align;
attribute DOMString border;
attribute DOMString frame;
attribute DOMString rules;
attribute DOMString summary;
attribute DOMString width;
 
[TreatNullAs=EmptyString] attribute DOMString bgColor;
[TreatNullAs=EmptyString] attribute DOMString cellPadding;
[TreatNullAs=EmptyString] attribute DOMString cellSpacing;
};
 
partial interface HTMLTableSectionElement {
attribute DOMString align;
attribute DOMString ch;
attribute DOMString chOff;
attribute DOMString vAlign;
};
 
partial interface HTMLTableCellElement {
attribute DOMString abbr;
attribute DOMString align;
attribute DOMString axis;
attribute DOMString height;
attribute DOMString width;
 
attribute DOMString ch;
attribute DOMString chOff;
attribute boolean noWrap;
attribute DOMString vAlign;
 
[TreatNullAs=EmptyString] attribute DOMString bgColor;
};
 
partial interface HTMLTableRowElement {
attribute DOMString align;
attribute DOMString ch;
attribute DOMString chOff;
attribute DOMString vAlign;
 
[TreatNullAs=EmptyString] attribute DOMString bgColor;
};
 
partial interface HTMLUListElement {
attribute boolean compact;
attribute DOMString type;
};
 
partial interface Document {
[TreatNullAs=EmptyString] attribute DOMString fgColor;
[TreatNullAs=EmptyString] attribute DOMString linkColor;
[TreatNullAs=EmptyString] attribute DOMString vlinkColor;
[TreatNullAs=EmptyString] attribute DOMString alinkColor;
[TreatNullAs=EmptyString] attribute DOMString bgColor;
 
readonly attribute HTMLCollection anchors;
readonly attribute HTMLCollection applets;
 
void clear();
 
readonly attribute HTMLAllCollection all;
};
 
/programs/network/netsurf/netsurf/javascript/content.c
0,0 → 1,120
/*
* Copyright 2012 Vincent Sanders <vince@kyllikki.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for javascript (implementation)
*/
 
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
 
#include "utils/config.h"
#include "content/content_protected.h"
#include "content/hlcache.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
#include "javascript/content.h"
 
typedef struct javascript_content {
struct content base;
} javascript_content;
 
static nserror javascript_create(const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
javascript_content *script;
nserror error;
 
script = calloc(1, sizeof(javascript_content));
if (script == NULL)
return NSERROR_NOMEM;
 
error = content__init(&script->base, handler, imime_type, params,
llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(script);
return error;
}
 
*c = (struct content *) script;
 
return NSERROR_OK;
}
 
static bool javascript_convert(struct content *c)
{
content_set_ready(c);
content_set_done(c);
 
return true;
}
 
static nserror
javascript_clone(const struct content *old, struct content **newc)
{
javascript_content *script;
nserror error;
 
script = calloc(1, sizeof(javascript_content));
if (script == NULL)
return NSERROR_NOMEM;
 
error = content__clone(old, &script->base);
if (error != NSERROR_OK) {
content_destroy(&script->base);
return error;
}
 
*newc = (struct content *) script;
 
return NSERROR_OK;
}
 
static void javascript_destroy(struct content *c)
{
}
 
static content_type javascript_content_type(void)
{
return CONTENT_JS;
}
 
 
static const content_handler javascript_content_handler = {
.create = javascript_create,
.data_complete = javascript_convert,
.destroy = javascript_destroy,
.clone = javascript_clone,
.type = javascript_content_type,
.no_share = false,
};
 
static const char *javascript_types[] = {
"application/javascript", /* RFC 4329 */
"application/ecmascript", /* RFC 4329 */
"application/x-javascript", /* common usage */
"text/javascript", /* common usage */
"text/ecmascript", /* common usage */
};
 
CONTENT_FACTORY_REGISTER_TYPES(javascript, javascript_types, javascript_content_handler);
/programs/network/netsurf/netsurf/javascript/content.h
0,0 → 1,0
nserror javascript_init(void);
/programs/network/netsurf/netsurf/javascript/js.h
0,0 → 1,70
/*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Interface to javascript engine functions.
*/
 
#ifndef _NETSURF_JAVASCRIPT_JS_H_
#define _NETSURF_JAVASCRIPT_JS_H_
 
typedef struct jscontext jscontext;
typedef struct jsobject jsobject;
 
struct dom_document;
struct dom_node;
struct dom_string;
 
/** Initialise javascript interpreter */
void js_initialise(void);
 
/** finalise javascript interpreter */
void js_finalise(void);
 
/** Create a new javascript context.
*
* There aare usually one context per browser context
*/
jscontext *js_newcontext(void);
 
/** Destroy a previously created context */
void js_destroycontext(jscontext *ctx);
 
/** Create a new javascript compartment
*
* This is called once for a page with javascript script tags on
* it. It constructs a fresh global window object.
*/
jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv);
 
/* execute some javascript in a context */
bool js_exec(jscontext *ctx, const char *txt, size_t txtlen);
 
 
/* fire an event at a dom node */
bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc, struct dom_node *target);
 
bool
js_dom_event_add_listener(jscontext *ctx,
struct dom_document *document,
struct dom_node *node,
struct dom_string *event_type_dom,
void *js_funcval);
 
 
#endif /* _NETSURF_JAVASCRIPT_JS_H_ */
/programs/network/netsurf/netsurf/javascript/jsapi/comment.bnd
0,0 → 1,47
/* Binding to generate Comment interface
*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
 
 
webidlfile "html.idl";
 
hdrcomment "Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>";
hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/";
hdrcomment "Released under the terms of the MIT License,";
hdrcomment " http://www.opensource.org/licenses/mit-license";
 
preamble %{
 
#include <dom/dom.h>
 
#include "utils/config.h"
#include "utils/log.h"
#include "render/html_internal.h"
#include "javascript/jsapi.h"
 
#include "comment.h"
 
%}
 
#include "dom.bnd"
 
binding comment {
type js_libdom; /* the binding type */
 
interface Comment; /* Web IDL interface to generate */
 
private "dom_comment *" node;
private "struct html_content *" htmlc;
}
 
api finalise %{
if (private != NULL) {
dom_node_unref(private->node);
}
%}
/programs/network/netsurf/netsurf/javascript/jsapi/console.bnd
0,0 → 1,47
/* Binding to generate Console interface
*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
 
webidlfile "console.idl";
 
hdrcomment "Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>";
hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/";
hdrcomment "Released under the terms of the MIT License,";
hdrcomment " http://www.opensource.org/licenses/mit-license";
 
preamble %{
 
#include "utils/config.h"
#include "utils/log.h"
#include "javascript/jsapi.h"
 
#include "console.h"
 
%}
 
binding navigator {
type js_libdom; /* the binding type */
 
interface Console; /* Web IDL interface to generate */
 
}
 
operation log %{
unsigned int argloop;
JSString *jsstr;
unsigned long jsstrlen;
char *txt;
 
for (argloop = 0; argloop < argc; argloop++) {
jsstr = JS_ValueToString(cx, argv[argloop]);
 
JSString_to_char(jsstr, txt, jsstrlen);
LOG(("%s", txt));
}
%}
/programs/network/netsurf/netsurf/javascript/jsapi/dom.bnd
0,0 → 1,172
/* Binding to generate interfaces for the DOM IDL
*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
 
webidlfile "dom.idl";
 
preamble %{
#include "comment.h"
#include "text.h"
#include "htmlelement.h"
%}
 
 
prologue %{
/* CAUTION this expects all javascript Node objects private pointers
* to have private->node in the same place.
*/
static struct dom_node *jsnode_to_domnode(JSContext *cx, JSObject *jsnode)
{
struct jsclass_private *jsnode_private;
 
if (jsnode == NULL) {
return NULL;
}
 
/* element */
jsnode_private = JS_GetInstancePrivate(cx,
jsnode,
&JSClass_HTMLElement,
NULL);
if (jsnode_private != NULL) {
return (struct dom_node *)jsnode_private->node;
}
 
/* text */
jsnode_private = JS_GetInstancePrivate(cx,
jsnode,
&JSClass_Text,
NULL);
if (jsnode_private != NULL) {
return (struct dom_node *)jsnode_private->node;
}
 
/* comment */
jsnode_private = JS_GetInstancePrivate(cx,
jsnode,
&JSClass_Comment,
NULL);
if (jsnode_private != NULL) {
return (struct dom_node *)jsnode_private->node;
}
 
return NULL;
}
 
%}
 
/* interface Node members */
 
getter nodeType %{
dom_exception exc;
dom_node_type node_type;
 
exc = dom_node_get_node_type(private->node, &node_type);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
jsret = node_type;
%}
 
 
getter nodeName %{
dom_exception exc;
dom_string *name;
 
exc = dom_node_get_node_name(private->node, &name);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (name != NULL) {
jsret = JS_NewStringCopyN(cx,
dom_string_data(name),
dom_string_length(name));
dom_string_unref(name);
}
%}
 
getter nodeValue %{
dom_exception exc;
dom_string *value;
 
exc = dom_node_get_node_value(private->node, &value);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (value != NULL) {
jsret = JS_NewStringCopyN(cx,
dom_string_data(value),
dom_string_length(value));
dom_string_unref(value);
}
%}
 
getter textContent %{
dom_exception exc;
dom_string *content;
 
exc = dom_node_get_text_content(private->node, &content);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (content != NULL) {
jsret = JS_NewStringCopyN(cx, dom_string_data(content), dom_string_length(content));
dom_string_unref(content);
 
}
%}
 
/* interface Node { Node appendChild(Node node); } */
operation appendChild %{
struct dom_node *domnode; /* dom node from js input node */
struct dom_node *result = NULL;
dom_exception exc;
dom_node_type node_type;
 
domnode = jsnode_to_domnode(cx, node);
if (domnode == NULL) {
/* should cause Error: NOT_FOUND_ERR: DOM Exception 8 */
JSLOG("Error: NOT_FOUND_ERR: DOM Exception 8");
return JS_FALSE;
}
 
JSLOG("appending js node %p (dom %p)", node, domnode);
 
/* append the found element */
exc = dom_node_append_child(private->node, domnode, &result);
if (exc != DOM_NO_ERR) {
JSLOG("Error: DOM Exception (libdom append child)");
return JS_FALSE;
}
 
if (result != NULL) {
exc = dom_node_get_node_type(result, &node_type);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
switch (node_type) {
case DOM_ELEMENT_NODE:
jsret = jsapi_new_HTMLElement(cx, NULL, NULL, (dom_element *)result, private->htmlc);
break;
 
case DOM_TEXT_NODE:
jsret = jsapi_new_Text(cx, NULL, NULL, (dom_text *)result, private->htmlc);
break;
 
default:
JSLOG("Unsupported result node type %d", node_type);
}
 
} else {
JSLOG("No result");
}
%}
/programs/network/netsurf/netsurf/javascript/jsapi/event.bnd
0,0 → 1,37
/* Binding to generate event interface
*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
 
webidlfile "dom.idl";
 
hdrcomment "Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>";
hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/";
hdrcomment "Released under the terms of the MIT License,";
hdrcomment " http://www.opensource.org/licenses/mit-license";
 
preamble %{
#include <stdlib.h>
 
#include <dom/dom.h>
#include "utils/config.h"
#include "utils/log.h"
#include "javascript/jsapi.h"
 
#include "event.h"
 
%}
 
binding node {
type js_libdom; /* the binding type */
 
interface Event; /* Web IDL interface to generate */
 
private "dom_event *" event;
}
/programs/network/netsurf/netsurf/javascript/jsapi/htmlcollection.bnd
0,0 → 1,93
/* Binding to generate HTMLcollection interface
*
* The js_libdom (javascript to libdom) binding type is currently the
* only one implemented and this principly describes that binding.
*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
 
/* The hdrcomment are added into the geenrated output comment header */
hdrcomment "Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>";
hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/";
hdrcomment "Released under the terms of the MIT License,";
hdrcomment " http://www.opensource.org/licenses/mit-license";
 
preamble %{
 
#include <dom/dom.h>
#include "utils/config.h"
#include "utils/log.h"
#include "javascript/jsapi.h"
#include "render/html_internal.h"
 
#include "htmlelement.h"
#include "htmlcollection.h"
 
%}
 
webidlfile "dom.idl";
 
binding htmlcollection {
type js_libdom; /* the binding type */
 
interface HTMLCollection; /* The WebIDL interface to generate a binding for */
 
private "dom_html_collection *" collection;
private "struct html_content *" htmlc;
}
 
getter length %{
dom_exception err;
 
err = dom_html_collection_get_length(private->collection, &jsret);
if (err != DOM_NO_ERR) {
return JS_FALSE;
}
%}
operation item %{
dom_exception err;
dom_node *domnode;
 
err = dom_html_collection_item(private->collection, index, &domnode);
if (err != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (domnode != NULL) {
jsret = jsapi_new_HTMLElement(cx, NULL, NULL, (dom_element *)domnode, private->htmlc);
}
%}
 
operation namedItem %{
dom_exception err;
dom_node *domnode;
dom_string *name_dom;
 
err = dom_string_create((uint8_t *)name, name_len, &name_dom);
if (err != DOM_NO_ERR) {
return JS_FALSE;
}
 
err = dom_html_collection_named_item(private->collection, name_dom, &domnode);
if (err != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (domnode != NULL) {
jsret = jsapi_new_HTMLElement(cx, NULL, NULL, (dom_element *)domnode, private->htmlc);
}
 
%}
 
api finalise %{
if (private != NULL) {
dom_html_collection_unref(private->collection);
}
%}
/programs/network/netsurf/netsurf/javascript/jsapi/htmldocument.bnd
0,0 → 1,596
/* Binding to generate HTMLdocument interface
*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
 
webidlfile "html.idl";
 
hdrcomment "Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>";
hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/";
hdrcomment "Released under the terms of the MIT License,";
hdrcomment " http://www.opensource.org/licenses/mit-license";
 
preamble %{
 
#include <dom/dom.h>
 
#include "utils/config.h"
#include "utils/log.h"
#include "utils/corestrings.h"
#include "utils/libdom.h"
#include "content/urldb.h"
#include "javascript/js.h"
#include "javascript/jsapi.h"
#include "render/html_internal.h"
 
#include "htmldocument.h"
#include "htmlelement.h"
#include "text.h"
#include "nodelist.h"
#include "location.h"
 
%}
 
#include "dom.bnd"
 
binding document {
type js_libdom; /* the binding type */
 
interface Document; /* Web IDL interface to generate */
 
/* parameters to constructor value stored in private
* context structure.
*/
private "dom_document *" node;
private "struct html_content *" htmlc;
 
/** location instantiated on first use */
property unshared location;
 
/* compatability mode instantiated on first use */
property unshared compatMode;
 
/* events through a single interface */
property unshared type EventHandler;
}
 
api finalise %{
if (private != NULL) {
JSLOG("dom_document %p in content %p",
private->node, private->htmlc);
dom_node_unref(private->node);
}
%}
 
 
getter location %{
if (!JSVAL_IS_VOID(JSAPI_PROP_RVAL(cx, vp))) {
/* already created - return it */
return JS_TRUE;
}
jsret = jsapi_new_Location(cx,
NULL,
NULL,
llcache_handle_get_url(private->htmlc->base.llcache),
private->htmlc);
%}
 
getter URL %{
jsval loc;
jsval jsstr = JSVAL_NULL;
if (JS_GetProperty(cx, obj, "location", &loc) == JS_TRUE) {
JS_GetProperty(cx, JSVAL_TO_OBJECT(loc), "href", &jsstr);
}
jsret = JSVAL_TO_STRING(jsstr);
%}
 
getter documentURI %{
jsval loc;
jsval jsstr = JSVAL_NULL;
if (JS_GetProperty(cx, obj, "location", &loc) == JS_TRUE) {
JS_GetProperty(cx, JSVAL_TO_OBJECT(loc), "href", &jsstr);
}
jsret = JSVAL_TO_STRING(jsstr);
%}
 
 
getter compatMode %{
/* Returns the string "CSS1Compat" if document is in no-quirks
* mode or limited-quirks mode, and "BackCompat", if document
* is in quirks mode.
*/
if (!JSVAL_IS_VOID(JSAPI_PROP_RVAL(cx, vp))) {
/* already created, just use it */
return JS_TRUE;
}
if (private->htmlc->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL) {
jsret = JS_NewStringCopyN(cx, "BackCompat", SLEN("BackCompat"));
} else {
jsret = JS_NewStringCopyN(cx, "CSS1Compat", SLEN("CSS1Compat"));
}
 
%}
 
/*
getter characterSet %{
%}
 
getter contentType %{
%}
*/
 
getter cookie %{
char *cookie_str;
cookie_str = urldb_get_cookie(llcache_handle_get_url(private->htmlc->base.llcache), false);
if (cookie_str != NULL) {
jsret = JS_NewStringCopyN(cx, cookie_str, strlen(cookie_str));
free(cookie_str);
}
%}
 
getter documentElement %{
dom_exception exc;
dom_element *element;
 
/* document (html) element */
exc = dom_document_get_document_element(private->node, (void *)&element);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (element != NULL) {
jsret = jsapi_new_HTMLElement(cx, NULL, NULL, element, private->htmlc);
}
%}
 
getter head %{
dom_node *element;
dom_node *head;
dom_exception exc;
 
/* document (html) element */
exc = dom_document_get_document_element(private->node, &element);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (element != NULL) {
head = libdom_find_first_element(element, corestring_lwc_head) ;
if (head != NULL) {
jsret = jsapi_new_HTMLElement(cx, NULL, NULL, (dom_element *)head, private->htmlc);
}
dom_node_unref(element);
}
%}
 
getter body %{
dom_node *element;
dom_node *body;
dom_exception exc;
 
JSDBG("Getting your body");
 
/* document (html) element */
exc = dom_document_get_document_element(private->node, &element);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (element != NULL) {
body = libdom_find_first_element(element, corestring_lwc_body) ;
if (body != NULL) {
jsret = jsapi_new_HTMLElement(cx, NULL, NULL, (dom_element *)body, private->htmlc);
}
dom_node_unref(element);
}
 
JSDBG("returning jsobject %p",jsret);
 
%}
 
operation getElementById %{
dom_string *elementId_dom;
dom_element *element;
dom_exception exc;
 
exc = dom_string_create((unsigned char*)elementId, elementId_len, &elementId_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
exc = dom_document_get_element_by_id(private->node, elementId_dom, &element);
dom_string_unref(elementId_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (element != NULL) {
jsret = jsapi_new_HTMLElement(cx, NULL, NULL, element, private->htmlc);
}
%}
 
/*
*
* Dom 4 says this should return a htmlcollection, libdom currently
* returns DOM 3 spec of a nodelist
*/
/* HTMLCollection Document::getElementsByTagName(DOMString localName); */
operation getElementsByTagName %{
dom_string *localName_dom;
/* dom_html_collection *collection;*/
dom_nodelist *nodelist;
dom_exception exc;
 
exc = dom_string_create((uint8_t *)localName, localName_len, &localName_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
exc = dom_document_get_elements_by_tag_name(private->node, localName_dom, /*&collection*/&nodelist);
dom_string_unref(localName_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (/*collection*/nodelist != NULL) {
/*jsret = jsapi_new_HTMLCollection(cx,
NULL,
NULL,
collection,
private->htmlc);*/
jsret = jsapi_new_NodeList(cx,
NULL,
NULL,
nodelist,
private->htmlc);
}
 
%}
 
operation write %{
if (private->htmlc->parser != NULL) {
dom_hubbub_parser_insert_chunk(private->htmlc->parser, (uint8_t *)text, text_len);
}
%}
 
/* interface Document (dom) { Text createTextNode(DOMString data); } */
operation createTextNode %{
dom_string *data_dom;
dom_exception exc;
dom_text *text;
 
if (data != NULL) {
 
JSDBG("Creating text node for string \"%s\"", data);
exc = dom_string_create((unsigned char*)data, data_len, &data_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
exc = dom_document_create_text_node(private->node, data_dom, &text);
dom_string_unref(data_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
jsret = jsapi_new_Text(cx, NULL, NULL, text, private->htmlc);
}
 
JSDBG("returning jsobject %p",jsret);
 
%}
 
/* interface Document (dom) { Comment createComment(DOMString data); } */
operation createComment %{
dom_string *data_dom;
dom_exception exc;
dom_comment *comment;
 
if (data != NULL) {
 
JSDBG("Creating string \"%s\"", data);
exc = dom_string_create((unsigned char*)data,
data_len,
&data_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
JSDBG("Creating comment object for dom string \"%s\"",
dom_string_data(data_dom));
exc = dom_document_create_comment(private->node,
data_dom,
&comment);
dom_string_unref(data_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
jsret = jsapi_new_Comment(cx, NULL, NULL, comment, private->htmlc);
}
 
JSDBG("returning jsobject %p", jsret);
 
%}
 
/* in dom Document */
operation createElement %{
dom_string *localName_dom;
dom_exception exc;
dom_element *element;
 
if (localName != NULL) {
JSDBG("Creating text node for string \"%s\"", localName);
exc = dom_string_create((unsigned char*)localName, localName_len, &localName_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
exc = dom_document_create_element(private->node, localName_dom, &element);
dom_string_unref(localName_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
jsret = jsapi_new_HTMLElement(cx, NULL, NULL, element, private->htmlc);
}
 
JSDBG("returning jsobject %p",jsret);
 
%}
 
getter EventHandler %{
JSLOG("propname[%d].name=\"%s\"",
tinyid,
jsclass_properties[tinyid].name);
%}
 
 
setter EventHandler %{
dom_string *event_type_dom;
 
JSLOG("propname[%d].name=\"%s\"",
tinyid,
jsclass_properties[tinyid].name);
 
switch (tinyid) {
case JSAPI_PROP_TINYID_onabort:
event_type_dom = corestring_dom_abort;
break;
 
case JSAPI_PROP_TINYID_onblur:
event_type_dom = corestring_dom_blur;
break;
 
case JSAPI_PROP_TINYID_oncancel:
event_type_dom = corestring_dom_cancel;
break;
 
case JSAPI_PROP_TINYID_oncanplay:
event_type_dom = corestring_dom_canplay;
break;
 
case JSAPI_PROP_TINYID_oncanplaythrough:
event_type_dom = corestring_dom_canplaythrough;
break;
 
case JSAPI_PROP_TINYID_onchange:
event_type_dom = corestring_dom_change;
break;
 
case JSAPI_PROP_TINYID_onclick:
event_type_dom = corestring_dom_click;
break;
 
case JSAPI_PROP_TINYID_onclose:
event_type_dom = corestring_dom_close;
break;
 
case JSAPI_PROP_TINYID_oncontextmenu:
event_type_dom = corestring_dom_contextmenu;
break;
 
case JSAPI_PROP_TINYID_oncuechange:
event_type_dom = corestring_dom_cuechange;
break;
 
case JSAPI_PROP_TINYID_ondblclick:
event_type_dom = corestring_dom_dblclick;
break;
 
case JSAPI_PROP_TINYID_ondrag:
event_type_dom = corestring_dom_drag;
break;
 
case JSAPI_PROP_TINYID_ondragend:
event_type_dom = corestring_dom_dragend;
break;
 
case JSAPI_PROP_TINYID_ondragenter:
event_type_dom = corestring_dom_dragenter;
break;
 
case JSAPI_PROP_TINYID_ondragleave:
event_type_dom = corestring_dom_dragleave;
break;
 
case JSAPI_PROP_TINYID_ondragover:
event_type_dom = corestring_dom_dragover;
break;
 
case JSAPI_PROP_TINYID_ondragstart:
event_type_dom = corestring_dom_dragstart;
break;
 
case JSAPI_PROP_TINYID_ondrop:
event_type_dom = corestring_dom_drop;
break;
 
case JSAPI_PROP_TINYID_ondurationchange:
event_type_dom = corestring_dom_durationchange;
break;
 
case JSAPI_PROP_TINYID_onemptied:
event_type_dom = corestring_dom_emptied;
break;
 
case JSAPI_PROP_TINYID_onended:
event_type_dom = corestring_dom_ended;
break;
 
case JSAPI_PROP_TINYID_onerror:
event_type_dom = corestring_dom_error;
break;
 
case JSAPI_PROP_TINYID_onfocus:
event_type_dom = corestring_dom_focus;
break;
 
case JSAPI_PROP_TINYID_oninput:
event_type_dom = corestring_dom_input;
break;
 
case JSAPI_PROP_TINYID_oninvalid:
event_type_dom = corestring_dom_invalid;
break;
 
case JSAPI_PROP_TINYID_onkeydown:
event_type_dom = corestring_dom_keydown;
break;
 
case JSAPI_PROP_TINYID_onkeypress:
event_type_dom = corestring_dom_keypress;
break;
 
case JSAPI_PROP_TINYID_onkeyup:
event_type_dom = corestring_dom_keyup;
break;
 
case JSAPI_PROP_TINYID_onload:
event_type_dom = corestring_dom_load;
break;
 
case JSAPI_PROP_TINYID_onloadeddata:
event_type_dom = corestring_dom_loadeddata;
break;
 
case JSAPI_PROP_TINYID_onloadedmetadata:
event_type_dom = corestring_dom_loadedmetadata;
break;
 
case JSAPI_PROP_TINYID_onloadstart:
event_type_dom = corestring_dom_loadstart;
break;
 
case JSAPI_PROP_TINYID_onmousedown:
event_type_dom = corestring_dom_mousedown;
break;
 
case JSAPI_PROP_TINYID_onmousemove:
event_type_dom = corestring_dom_mousemove;
break;
 
case JSAPI_PROP_TINYID_onmouseout:
event_type_dom = corestring_dom_mouseout;
break;
 
case JSAPI_PROP_TINYID_onmouseover:
event_type_dom = corestring_dom_mouseover;
break;
 
case JSAPI_PROP_TINYID_onmouseup:
event_type_dom = corestring_dom_mouseup;
break;
 
case JSAPI_PROP_TINYID_onmousewheel:
event_type_dom = corestring_dom_mousewheel;
break;
 
case JSAPI_PROP_TINYID_onpause:
event_type_dom = corestring_dom_pause;
break;
 
case JSAPI_PROP_TINYID_onplay:
event_type_dom = corestring_dom_play;
break;
 
case JSAPI_PROP_TINYID_onplaying:
event_type_dom = corestring_dom_playing;
break;
 
case JSAPI_PROP_TINYID_onprogress:
event_type_dom = corestring_dom_progress;
break;
 
case JSAPI_PROP_TINYID_onratechange:
event_type_dom = corestring_dom_ratechange;
break;
 
case JSAPI_PROP_TINYID_onreset:
event_type_dom = corestring_dom_reset;
break;
 
case JSAPI_PROP_TINYID_onscroll:
event_type_dom = corestring_dom_scroll;
break;
 
case JSAPI_PROP_TINYID_onseeked:
event_type_dom = corestring_dom_seeked;
break;
 
case JSAPI_PROP_TINYID_onseeking:
event_type_dom = corestring_dom_seeking;
break;
 
case JSAPI_PROP_TINYID_onselect:
event_type_dom = corestring_dom_select;
break;
 
case JSAPI_PROP_TINYID_onshow:
event_type_dom = corestring_dom_show;
break;
 
case JSAPI_PROP_TINYID_onstalled:
event_type_dom = corestring_dom_stalled;
break;
 
case JSAPI_PROP_TINYID_onsubmit:
event_type_dom = corestring_dom_submit;
break;
 
case JSAPI_PROP_TINYID_onsuspend:
event_type_dom = corestring_dom_suspend;
break;
 
case JSAPI_PROP_TINYID_ontimeupdate:
event_type_dom = corestring_dom_timeupdate;
break;
 
case JSAPI_PROP_TINYID_onvolumechange:
event_type_dom = corestring_dom_volumechange;
break;
 
case JSAPI_PROP_TINYID_onwaiting:
event_type_dom = corestring_dom_waiting;
break;
 
case JSAPI_PROP_TINYID_onreadystatechange:
event_type_dom = corestring_dom_readystatechange;
break;
 
default:
JSLOG("called with unknown tinyid");
return JS_TRUE;
}
 
js_dom_event_add_listener((struct jscontext *)cx,
private->node,
(dom_node *)private->node,
event_type_dom,
vp);
%}
/programs/network/netsurf/netsurf/javascript/jsapi/htmlelement.bnd
0,0 → 1,721
/* Binding to generate HTMLElement interface
*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
 
webidlfile "html.idl";
 
hdrcomment "Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>";
hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/";
hdrcomment "Released under the terms of the MIT License,";
hdrcomment " http://www.opensource.org/licenses/mit-license";
 
preamble %{
 
#include <dom/dom.h>
 
#include "utils/config.h"
#include "utils/log.h"
#include "utils/corestrings.h"
#include "javascript/js.h"
#include "javascript/jsapi.h"
#include "render/html_internal.h"
 
#include "htmlelement.h"
#include "text.h"
#include "location.h"
#include "nodelist.h"
 
%}
 
#include "dom.bnd"
 
binding htmlelement {
type js_libdom; /* the binding type */
 
interface HTMLElement; /* Web IDL interface to generate */
/* superclasses
 
interface HTMLAnchorElement
interface HTMLAppletElement
interface HTMLAreaElement
interface HTMLBaseElement
interface HTMLBaseFontElement
interface HTMLBodyElement
interface HTMLBRElement
interface HTMLButtonElement
interface HTMLCanvasElement
interface HTMLCommandElement
interface HTMLDataElement
interface HTMLDataListElement
interface HTMLDetailsElement
interface HTMLDialogElement
interface HTMLDirectoryElement
interface HTMLDivElement
interface HTMLDListElement
interface HTMLEmbedElement
interface HTMLFieldSetElement
interface HTMLFontElement
interface HTMLFormElement
interface HTMLFrameElement
interface HTMLFrameSetElement
interface HTMLHeadElement
interface HTMLHeadingElement
interface HTMLHRElement
interface HTMLHtmlElement
interface HTMLIFrameElement
interface HTMLImageElement
interface HTMLInputElement
interface HTMLKeygenElement
interface HTMLLabelElement
interface HTMLLegendElement
interface HTMLLIElement
interface HTMLLinkElement
interface HTMLMapElement
interface HTMLMarqueeElement
interface HTMLMediaElement
interface HTMLMenuElement
interface HTMLMetaElement
interface HTMLMeterElement
interface HTMLModElement
interface HTMLObjectElement
interface HTMLOListElement
interface HTMLOptGroupElement
interface HTMLOptionElement
interface HTMLOutputElement
interface HTMLParagraphElement
interface HTMLParamElement
interface HTMLPreElement
interface HTMLProgressElement
interface HTMLQuoteElement
interface HTMLScriptElement
interface HTMLSelectElement
interface HTMLSourceElement
interface HTMLSpanElement
interface HTMLStyleElement
interface HTMLTableCaptionElement
interface HTMLTableCellElement
interface HTMLTableColElement
interface HTMLTableElement
interface HTMLTableRowElement
interface HTMLTableSectionElement
interface HTMLTextAreaElement
interface HTMLTimeElement
interface HTMLTitleElement
interface HTMLTrackElement
interface HTMLUListElement
interface HTMLUnknownElement
*/
 
private "dom_element *" node;
private "struct html_content *" htmlc;
 
/* tag name retrieved first time its fetched and doesnt change */
property unshared tagName;
 
/* events through a single interface */
property unshared type EventHandler;
}
 
api finalise %{
if (private != NULL) {
dom_node_unref(private->node);
}
%}
 
/* interface Element in dom idl */
 
/* readonly attribute DOMString Element::tagName; */
getter tagName %{
if (!JSVAL_IS_VOID(JSAPI_PROP_RVAL(cx, vp))) {
/* already created - return it */
return JS_TRUE;
}
 
dom_exception exc;
dom_string *name;
 
exc = dom_element_get_tag_name(private->node, &name);
if (name != NULL) {
jsret = JS_NewStringCopyN(cx, dom_string_data(name), dom_string_length(name));
dom_string_unref(name);
}
%}
 
/* attribute DOMString Element::id; */
getter id %{
dom_string *value;
dom_exception exc;
 
exc = dom_element_get_attribute(private->node, corestring_dom_id, &value);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (value != NULL) {
jsret = JS_NewStringCopyN(cx, dom_string_data(value), dom_string_length(value));
dom_string_unref(value);
}
%}
 
/* attribute DOMString Element::className; */
getter className %{
dom_string *value;
dom_exception exc;
 
exc = dom_element_get_attribute(private->node, corestring_dom_class, &value);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (value != NULL) {
jsret = JS_NewStringCopyN(cx, dom_string_data(value), dom_string_length(value));
dom_string_unref(value);
}
%}
 
/* DOMString? Element::getAttribute(DOMString name); */
operation getAttribute %{
dom_string *value;
dom_string *name_dom;
dom_exception exc;
 
exc = dom_string_create((unsigned char*)name, name_len, &name_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
exc = dom_element_get_attribute(private->node, name_dom, &value);
dom_string_unref(name_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (value != NULL) {
jsret = JS_NewStringCopyN(cx, dom_string_data(value), dom_string_length(value));
dom_string_unref(value);
}
%}
 
/* void Element::setAttribute(DOMString name, DOMString value); */
operation setAttribute %{
dom_string *value_dom;
dom_string *name_dom;
dom_exception exc;
 
exc = dom_string_create((unsigned char*)name, name_len, &name_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
exc = dom_string_create((unsigned char*)name, name_len, &value_dom);
if (exc != DOM_NO_ERR) {
dom_string_unref(name_dom);
return JS_FALSE;
}
 
exc = dom_element_set_attribute(private->node, name_dom, value_dom);
dom_string_unref(name_dom);
dom_string_unref(value_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
%}
 
/* void Element::removeAttribute(DOMString name); */
operation removeAttribute %{
dom_string *name_dom;
dom_exception exc;
 
exc = dom_string_create((unsigned char*)name, name_len, &name_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
exc = dom_element_remove_attribute(private->node, name_dom);
dom_string_unref(name_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
%}
 
/* boolean Element::hasAttribute(DOMString name); */
operation hasAttribute %{
bool result;
dom_string *name_dom;
dom_exception exc;
 
exc = dom_string_create((unsigned char*)name, name_len, &name_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
exc = dom_element_has_attribute(private->node, name_dom, &result);
dom_string_unref(name_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (result) {
jsret = JS_TRUE;
}
%}
 
/*
*
* Dom 4 says this should return a htmlcollection, libdom currently
* returns DOM 3 spec of a nodelist
*/
/* HTMLCollection Element::getElementsByTagName(DOMString localName); */
operation getElementsByTagName %{
dom_string *localName_dom;
/* dom_html_collection *collection;*/
dom_nodelist *nodelist;
dom_exception exc;
 
exc = dom_string_create((uint8_t *)localName, localName_len, &localName_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
exc = dom_element_get_elements_by_tag_name(private->node, localName_dom, /*&collection*/&nodelist);
dom_string_unref(localName_dom);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (/*collection*/nodelist != NULL) {
/*jsret = jsapi_new_HTMLCollection(cx,
NULL,
NULL,
collection,
private->htmlc);*/
jsret = jsapi_new_NodeList(cx,
NULL,
NULL,
nodelist,
private->htmlc);
}
 
%}
 
/*
* DOM 3 has these as the element traversal extension
*
* http://dev.w3.org/2006/webapi/ElementTraversal/publish/ElementTraversal.html
*/
 
getter firstElementChild %{
dom_node *element;
dom_exception exc;
dom_node_type node_type;
dom_node *next_node;
 
exc = dom_node_get_first_child(private->node, &element);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
while (element != NULL) {
exc = dom_node_get_node_type(element, &node_type);
if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
/* found it */
jsret = jsapi_new_HTMLElement(cx,
NULL,
NULL,
(dom_element *)element,
private->htmlc);
break;
}
 
exc = dom_node_get_next_sibling(element, &next_node);
dom_node_unref(element);
if (exc == DOM_NO_ERR) {
element = next_node;
} else {
element = NULL;
}
 
}
 
 
%}
 
getter lastElementChild %{
dom_node *element;
dom_exception exc;
dom_node_type node_type;
dom_node *sib_node;
 
exc = dom_node_get_last_child(private->node, &element);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
while (element != NULL) {
exc = dom_node_get_node_type(element, &node_type);
if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
/* found it */
jsret = jsapi_new_HTMLElement(cx,
NULL,
NULL,
(dom_element *)element,
private->htmlc);
break;
}
 
exc = dom_node_get_previous_sibling(element, &sib_node);
dom_node_unref(element);
if (exc == DOM_NO_ERR) {
element = sib_node;
} else {
element = NULL;
}
 
}
%}
 
getter previousElementSibling %{
dom_node *element;
dom_exception exc;
dom_node_type node_type;
dom_node *sib_node;
 
exc = dom_node_get_previous_sibling(private->node, &element);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
while (element != NULL) {
exc = dom_node_get_node_type(element, &node_type);
if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
/* found it */
jsret = jsapi_new_HTMLElement(cx,
NULL,
NULL,
(dom_element *)element,
private->htmlc);
break;
}
 
exc = dom_node_get_previous_sibling(element, &sib_node);
dom_node_unref(element);
if (exc == DOM_NO_ERR) {
element = sib_node;
} else {
element = NULL;
}
}
%}
 
getter nextElementSibling %{
dom_node *element;
dom_exception exc;
dom_node_type node_type;
dom_node *sib_node;
 
exc = dom_node_get_next_sibling(private->node, &element);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
while (element != NULL) {
exc = dom_node_get_node_type(element, &node_type);
if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
/* found it */
jsret = jsapi_new_HTMLElement(cx,
NULL,
NULL,
(dom_element *)element,
private->htmlc);
break;
}
 
exc = dom_node_get_next_sibling(element, &sib_node);
dom_node_unref(element);
if (exc == DOM_NO_ERR) {
element = sib_node;
} else {
element = NULL;
}
}
%}
 
getter childElementCount %{
dom_node *element;
dom_exception exc;
dom_node_type node_type;
dom_node *next_node;
 
exc = dom_node_get_first_child(private->node, &element);
if (exc != DOM_NO_ERR) {
return JS_FALSE;
}
 
while (element != NULL) {
exc = dom_node_get_node_type(element, &node_type);
if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
jsret += 1;
}
 
exc = dom_node_get_next_sibling(element, &next_node);
dom_node_unref(element);
if (exc == DOM_NO_ERR) {
element = next_node;
} else {
element = NULL;
}
}
%}
 
getter EventHandler %{
JSLOG("propname[%d].name=\"%s\"",
tinyid,
jsclass_properties[tinyid].name);
%}
 
 
setter EventHandler %{
dom_string *event_type_dom;
 
JSLOG("propname[%d].name=\"%s\"",
tinyid,
jsclass_properties[tinyid].name);
 
switch (tinyid) {
case JSAPI_PROP_TINYID_onabort:
event_type_dom = corestring_dom_abort;
break;
 
case JSAPI_PROP_TINYID_onblur:
event_type_dom = corestring_dom_blur;
break;
 
case JSAPI_PROP_TINYID_oncancel:
event_type_dom = corestring_dom_cancel;
break;
 
case JSAPI_PROP_TINYID_oncanplay:
event_type_dom = corestring_dom_canplay;
break;
 
case JSAPI_PROP_TINYID_oncanplaythrough:
event_type_dom = corestring_dom_canplaythrough;
break;
 
case JSAPI_PROP_TINYID_onchange:
event_type_dom = corestring_dom_change;
break;
 
case JSAPI_PROP_TINYID_onclick:
event_type_dom = corestring_dom_click;
break;
 
case JSAPI_PROP_TINYID_onclose:
event_type_dom = corestring_dom_close;
break;
 
case JSAPI_PROP_TINYID_oncontextmenu:
event_type_dom = corestring_dom_contextmenu;
break;
 
case JSAPI_PROP_TINYID_oncuechange:
event_type_dom = corestring_dom_cuechange;
break;
 
case JSAPI_PROP_TINYID_ondblclick:
event_type_dom = corestring_dom_dblclick;
break;
 
case JSAPI_PROP_TINYID_ondrag:
event_type_dom = corestring_dom_drag;
break;
 
case JSAPI_PROP_TINYID_ondragend:
event_type_dom = corestring_dom_dragend;
break;
 
case JSAPI_PROP_TINYID_ondragenter:
event_type_dom = corestring_dom_dragenter;
break;
 
case JSAPI_PROP_TINYID_ondragleave:
event_type_dom = corestring_dom_dragleave;
break;
 
case JSAPI_PROP_TINYID_ondragover:
event_type_dom = corestring_dom_dragover;
break;
 
case JSAPI_PROP_TINYID_ondragstart:
event_type_dom = corestring_dom_dragstart;
break;
 
case JSAPI_PROP_TINYID_ondrop:
event_type_dom = corestring_dom_drop;
break;
 
case JSAPI_PROP_TINYID_ondurationchange:
event_type_dom = corestring_dom_durationchange;
break;
 
case JSAPI_PROP_TINYID_onemptied:
event_type_dom = corestring_dom_emptied;
break;
 
case JSAPI_PROP_TINYID_onended:
event_type_dom = corestring_dom_ended;
break;
 
case JSAPI_PROP_TINYID_onerror:
event_type_dom = corestring_dom_error;
break;
 
case JSAPI_PROP_TINYID_onfocus:
event_type_dom = corestring_dom_focus;
break;
 
case JSAPI_PROP_TINYID_oninput:
event_type_dom = corestring_dom_input;
break;
 
case JSAPI_PROP_TINYID_oninvalid:
event_type_dom = corestring_dom_invalid;
break;
 
case JSAPI_PROP_TINYID_onkeydown:
event_type_dom = corestring_dom_keydown;
break;
 
case JSAPI_PROP_TINYID_onkeypress:
event_type_dom = corestring_dom_keypress;
break;
 
case JSAPI_PROP_TINYID_onkeyup:
event_type_dom = corestring_dom_keyup;
break;
 
case JSAPI_PROP_TINYID_onload:
event_type_dom = corestring_dom_load;
break;
 
case JSAPI_PROP_TINYID_onloadeddata:
event_type_dom = corestring_dom_loadeddata;
break;
 
case JSAPI_PROP_TINYID_onloadedmetadata:
event_type_dom = corestring_dom_loadedmetadata;
break;
 
case JSAPI_PROP_TINYID_onloadstart:
event_type_dom = corestring_dom_loadstart;
break;
 
case JSAPI_PROP_TINYID_onmousedown:
event_type_dom = corestring_dom_mousedown;
break;
 
case JSAPI_PROP_TINYID_onmousemove:
event_type_dom = corestring_dom_mousemove;
break;
 
case JSAPI_PROP_TINYID_onmouseout:
event_type_dom = corestring_dom_mouseout;
break;
 
case JSAPI_PROP_TINYID_onmouseover:
event_type_dom = corestring_dom_mouseover;
break;
 
case JSAPI_PROP_TINYID_onmouseup:
event_type_dom = corestring_dom_mouseup;
break;
 
case JSAPI_PROP_TINYID_onmousewheel:
event_type_dom = corestring_dom_mousewheel;
break;
 
case JSAPI_PROP_TINYID_onpause:
event_type_dom = corestring_dom_pause;
break;
 
case JSAPI_PROP_TINYID_onplay:
event_type_dom = corestring_dom_play;
break;
 
case JSAPI_PROP_TINYID_onplaying:
event_type_dom = corestring_dom_playing;
break;
 
case JSAPI_PROP_TINYID_onprogress:
event_type_dom = corestring_dom_progress;
break;
 
case JSAPI_PROP_TINYID_onratechange:
event_type_dom = corestring_dom_ratechange;
break;
 
case JSAPI_PROP_TINYID_onreset:
event_type_dom = corestring_dom_reset;
break;
 
case JSAPI_PROP_TINYID_onscroll:
event_type_dom = corestring_dom_scroll;
break;
 
case JSAPI_PROP_TINYID_onseeked:
event_type_dom = corestring_dom_seeked;
break;
 
case JSAPI_PROP_TINYID_onseeking:
event_type_dom = corestring_dom_seeking;
break;
 
case JSAPI_PROP_TINYID_onselect:
event_type_dom = corestring_dom_select;
break;
 
case JSAPI_PROP_TINYID_onshow:
event_type_dom = corestring_dom_show;
break;
 
case JSAPI_PROP_TINYID_onstalled:
event_type_dom = corestring_dom_stalled;
break;
 
case JSAPI_PROP_TINYID_onsubmit:
event_type_dom = corestring_dom_submit;
break;
 
case JSAPI_PROP_TINYID_onsuspend:
event_type_dom = corestring_dom_suspend;
break;
 
case JSAPI_PROP_TINYID_ontimeupdate:
event_type_dom = corestring_dom_timeupdate;
break;
 
case JSAPI_PROP_TINYID_onvolumechange:
event_type_dom = corestring_dom_volumechange;
break;
 
case JSAPI_PROP_TINYID_onwaiting:
event_type_dom = corestring_dom_waiting;
break;
 
default:
JSLOG("called with unknown tinyid");
return JS_TRUE;
}
 
js_dom_event_add_listener((struct jscontext *)cx,
private->htmlc->document,
(dom_node *)private->node,
event_type_dom,
vp);
%}
/programs/network/netsurf/netsurf/javascript/jsapi/location.bnd
0,0 → 1,157
/* Binding to generate Location interface
*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
 
webidlfile "html.idl";
 
hdrcomment "Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>";
hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/";
hdrcomment "Released under the terms of the MIT License,";
hdrcomment " http://www.opensource.org/licenses/mit-license";
 
preamble %{
 
#include "desktop/browser.h"
#include "utils/config.h"
#include "utils/log.h"
#include "javascript/jsapi.h"
#include "render/html_internal.h"
 
#include "location.h"
 
%}
 
binding location {
type js_libdom; /* the binding type */
 
interface Location; /* Web IDL interface to generate */
 
private "nsurl *" url;
private "struct html_content *" htmlc;
 
property unshared href;
 
}
 
operation reload %{
browser_window_reload(private->htmlc->bw, false);
%}
 
 
getter href %{
char *url_s = NULL;
size_t url_l;
 
if (!JSVAL_IS_VOID(JSAPI_PROP_RVAL(cx,vp))) {
/* already created - return it */
return JS_TRUE;
}
 
nsurl_get(private->url, NSURL_COMPLETE, &url_s, &url_l);
if (url_s != NULL) {
jsret = JS_NewStringCopyN(cx, url_s, url_l);
free(url_s);
}
%}
 
setter href %{
JSString *url_jsstr = NULL;
int url_len = 0;
char *url = NULL;
 
url_jsstr = JS_ValueToString(cx, *vp);
if (url_jsstr != NULL) {
JSString_to_char(url_jsstr, url, url_len);
browser_window_go(private->htmlc->bw, url, NULL, false);
} else {
JSLOG("failed to convert string value");
}
%}
 
getter protocol %{
lwc_string *component;
component = nsurl_get_component(private->url, NSURL_SCHEME);
if (component != NULL) {
jsret = JS_NewStringCopyN(cx,
lwc_string_data(component),
lwc_string_length(component));
lwc_string_unref(component);
}
%}
 
getter host %{
lwc_string *component;
component = nsurl_get_component(private->url, NSURL_HOST);
if (component != NULL) {
jsret = JS_NewStringCopyN(cx,
lwc_string_data(component),
lwc_string_length(component));
lwc_string_unref(component);
}
%}
 
getter hostname %{
lwc_string *component;
component = nsurl_get_component(private->url, NSURL_HOST);
if (component != NULL) {
jsret = JS_NewStringCopyN(cx,
lwc_string_data(component),
lwc_string_length(component));
lwc_string_unref(component);
}
 
%}
 
getter port %{
lwc_string *component;
component = nsurl_get_component(private->url, NSURL_PORT);
if (component != NULL) {
jsret = JS_NewStringCopyN(cx,
lwc_string_data(component),
lwc_string_length(component));
lwc_string_unref(component);
}
 
%}
 
getter pathname %{
lwc_string *component;
component = nsurl_get_component(private->url, NSURL_PATH);
if (component != NULL) {
jsret = JS_NewStringCopyN(cx,
lwc_string_data(component),
lwc_string_length(component));
lwc_string_unref(component);
}
 
%}
 
getter search %{
lwc_string *component;
component = nsurl_get_component(private->url, NSURL_QUERY);
if (component != NULL) {
jsret = JS_NewStringCopyN(cx,
lwc_string_data(component),
lwc_string_length(component));
lwc_string_unref(component);
}
 
%}
 
getter hash %{
lwc_string *component;
component = nsurl_get_component(private->url, NSURL_FRAGMENT);
if (component != NULL) {
jsret = JS_NewStringCopyN(cx,
lwc_string_data(component),
lwc_string_length(component));
lwc_string_unref(component);
}
%}
/programs/network/netsurf/netsurf/javascript/jsapi/navigator.bnd
0,0 → 1,118
/* Binding to generate Navigator interface
*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
 
 
webidlfile "html.idl";
 
hdrcomment "Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>";
hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/";
hdrcomment "Released under the terms of the MIT License,";
hdrcomment " http://www.opensource.org/licenses/mit-license";
 
preamble %{
 
#include <assert.h>
#include <stdlib.h>
 
#include "desktop/netsurf.h"
#include "desktop/options.h"
#include "utils/config.h"
#include "utils/useragent.h"
#include "utils/log.h"
#include "utils/utsname.h"
#include "javascript/jsapi.h"
 
#include "navigator.h"
 
/*
* navigator properties for netsurf
*
* Property | Everyone else | NetSurf | Notes
* ------------+-----------------+--------------+------------------------------
* appCodeName | "Mozilla" | "NetSurf" | This is kinda a pointless
* | | | constant as everyone returns
* | | | "Mozilla" which is dumb
* ------------+-----------------+--------------+------------------------------
* appName | "<Browsername>" | "NetSurf" | Browsers named other than
* | | | "Netscape", "Mozilla",
* | | | "Netscape Navigator",
* | | | "Microsoft Internet Explorer"
* | | | often other browser have
* | | | "(compatible with Netscape)"
* | | | append.
* ------------+-----------------+--------------+------------------------------
* appVersion | "<ver> (<type>)"| "<ver>" | Actually just the version
* | | | number e.g "3.0".
* ------------+-----------------+--------------+------------------------------
* language | "<lang>" | "<lang>" | The language the frontend is
* | | | configured for
* ------------+-----------------+--------------+------------------------------
* platform | "<krn> <hw>" | "<krn> <hw>" | Efectively uname -s -i,
* | | | eg "Linux x86_64"
* ------------+-----------------+--------------+------------------------------
* userAgent | "Mozilla/5.0 (" | "NetSurf" | The usual useragent string
* | | | with excessive lies
* ------------+-----------------+--------------+------------------------------
*/
 
#define NAVIGATOR_APPNAME "NetSurf"
#define NAVIGATOR_APPCODENAME "NetSurf"
%}
 
binding navigator {
type js_libdom; /* the binding type */
 
interface Navigator; /* Web IDL interface to generate */
 
}
 
getter appName %{
jsret = JS_NewStringCopyZ(cx, NAVIGATOR_APPNAME);
%}
 
getter appCodeName %{
jsret = JS_NewStringCopyZ(cx, NAVIGATOR_APPCODENAME);
%}
 
getter appVersion %{
jsret = JS_NewStringCopyZ(cx, netsurf_version);
%}
 
getter language %{
const char *alang = nsoption_charp(accept_language);
 
if (alang != NULL) {
jsret = JS_NewStringCopyZ(cx, alang);
}
 
%}
 
getter platform %{
struct utsname *cutsname;
 
cutsname = malloc(sizeof(struct utsname));
 
if ((cutsname != NULL) && (uname(cutsname) >= 0)) {
char *platstr;
int platstrlen;
 
platstrlen = strlen(cutsname->sysname) + strlen(cutsname->machine) + 2;
platstr = malloc(platstrlen);
if (platstr != NULL) {
snprintf(platstr, platstrlen, "%s %s", cutsname->sysname, cutsname->machine);
jsret = JS_NewStringCopyN(cx, platstr, platstrlen - 1);
free(platstr);
}
}
%}
 
getter userAgent %{
jsret = JS_NewStringCopyZ(cx, user_agent_string());
%}
/programs/network/netsurf/netsurf/javascript/jsapi/node.bnd
0,0 → 1,35
/* Binding to generate Node interface
*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
 
webidlfile "dom.idl";
 
hdrcomment "Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>";
hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/";
hdrcomment "Released under the terms of the MIT License,";
hdrcomment " http://www.opensource.org/licenses/mit-license";
 
preamble %{
 
#include <dom/dom.h>
#include "utils/config.h"
#include "utils/log.h"
 
#include "javascript/jsapi.h"
 
#include "node.h"
 
%}
 
binding node {
type js_libdom; /* the binding type */
 
interface Node; /* Web IDL interface to generate */
}
/programs/network/netsurf/netsurf/javascript/jsapi/nodelist.bnd
0,0 → 1,99
/* Binding to generate NodeList interface
*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
 
/* The hdrcomment are added into the geenrated output comment header */
hdrcomment "Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>";
hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/";
hdrcomment "Released under the terms of the MIT License,";
hdrcomment " http://www.opensource.org/licenses/mit-license";
 
preamble %{
 
#include <dom/dom.h>
#include "utils/config.h"
#include "utils/log.h"
#include "javascript/jsapi.h"
#include "render/html_internal.h"
 
#include "nodelist.h"
#include "htmlelement.h"
 
%}
 
webidlfile "dom.idl";
 
binding nodelist {
type js_libdom; /* the binding type */
 
interface NodeList; /* The WebIDL interface to generate a binding for */
 
private "dom_nodelist *" nodelist;
private "struct html_content *" htmlc;
}
 
api finalise %{
if (private != NULL) {
dom_nodelist_unref(private->nodelist);
}
%}
 
/* default handler for numericaly indexed property values */
api getproperty %{
jsval queryprop;
int idx;
JSObject *jsret = NULL; /* Node */
dom_exception err;
dom_node *domnode;
 
JSAPI_PROP_IDVAL(cx, &queryprop);
if (JSVAL_IS_INT(queryprop)) {
idx = JSVAL_TO_INT(queryprop);
JSDBG("Index was %d", idx);
 
 
err = dom_nodelist_item(private->nodelist, idx, &domnode);
if (err != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (domnode != NULL) {
jsret = jsapi_new_HTMLElement(cx, NULL, NULL, (dom_element *)domnode, private->htmlc);
 
JSDBG("return object:%p", jsret);
 
JSAPI_PROP_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(jsret));
}
}
%}
 
getter length %{
dom_exception err;
 
err = dom_nodelist_get_length(private->nodelist, &jsret);
if (err != DOM_NO_ERR) {
return JS_FALSE;
}
%}
operation item %{
dom_exception err;
dom_node *domnode;
 
err = dom_nodelist_item(private->nodelist, index, &domnode);
if (err != DOM_NO_ERR) {
return JS_FALSE;
}
 
if (domnode != NULL) {
jsret = jsapi_new_HTMLElement(cx, NULL, NULL, (dom_element *)domnode, private->htmlc);
}
%}
 
/programs/network/netsurf/netsurf/javascript/jsapi/text.bnd
0,0 → 1,47
/* Binding to generate Text interface
*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
 
 
webidlfile "html.idl";
 
hdrcomment "Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>";
hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/";
hdrcomment "Released under the terms of the MIT License,";
hdrcomment " http://www.opensource.org/licenses/mit-license";
 
preamble %{
 
#include <dom/dom.h>
 
#include "utils/config.h"
#include "utils/log.h"
#include "render/html_internal.h"
#include "javascript/jsapi.h"
 
#include "text.h"
 
%}
 
#include "dom.bnd"
 
binding text {
type js_libdom; /* the binding type */
 
interface Text; /* Web IDL interface to generate */
 
private "dom_text *" node;
private "struct html_content *" htmlc;
}
 
api finalise %{
if (private != NULL) {
dom_node_unref(private->node);
}
%}
/programs/network/netsurf/netsurf/javascript/jsapi/window.bnd
0,0 → 1,284
/* Binding to generate window interface
*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* Released under the terms of the MIT License,
* http://www.opensource.org/licenses/mit-license
*/
 
 
webidlfile "html.idl";
webidlfile "dom.idl";
 
hdrcomment "Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>";
hdrcomment "This file is part of NetSurf, http://www.netsurf-browser.org/";
hdrcomment "Released under the terms of the MIT License,";
hdrcomment " http://www.opensource.org/licenses/mit-license";
 
preamble %{
 
#include <dom/dom.h>
 
#include "utils/config.h"
#include "utils/log.h"
#include "utils/corestrings.h"
#include "render/html_internal.h"
#include "javascript/jsapi.h"
 
#include "console.h"
#include "navigator.h"
#include "event.h"
#include "node.h"
#include "htmlcollection.h"
#include "nodelist.h"
#include "htmldocument.h"
#include "text.h"
#include "comment.h"
#include "htmlelement.h"
#include "window.h"
#include "location.h"
 
%}
 
binding window {
type js_libdom; /* the binding type */
 
interface Window; /* Web IDL interface to generate */
 
private "struct browser_window *" bw;
private "struct html_content *" htmlc;
 
internal "JSObject *" document;
internal "JSObject *" navigator;
internal "JSObject *" console;
 
property unshared type EventHandler;
}
 
api mark %{
if (private != NULL) {
if (private->document != NULL) {
JSAPI_GCMARK(private->document);
}
if (private->navigator != NULL) {
JSAPI_GCMARK(private->navigator);
}
if (private->console != NULL) {
JSAPI_GCMARK(private->console);
}
}
%}
 
api global %{
%}
 
api init %{
JSObject *user_proto;
 
prototype = JS_NewCompartmentAndGlobalObject(cx, &JSClass_Window, NULL);
if (prototype == NULL) {
return NULL;
}
 
/** @todo reconsider global object handling. future
* editions of spidermonkey appear to be removing the
* idea of a global so we probably need to handle
* global object references internally
*/
 
/* set the contexts global */
JS_SetGlobalObject(cx, prototype);
 
/* Populate the global object with the standard globals, like
* Object and Array.
*/
if (!JS_InitStandardClasses(cx, prototype)) {
return NULL;
}
 
/* add functions to prototype */
if (!JS_DefineFunctions(cx, prototype, jsclass_functions)) {
return NULL;
}
 
/* add properties to prototype */
if (!JS_DefineProperties(cx, prototype, jsclass_properties))
return NULL;
 
/* Initialises all the user javascript classes to make their
* prototypes available.
*/
/** @todo should we be managing these prototype objects ourselves */
user_proto = jsapi_InitClass_Document(cx, prototype);
if (user_proto == NULL) {
return NULL;
}
 
user_proto = jsapi_InitClass_Navigator(cx, prototype);
if (user_proto == NULL) {
return NULL;
}
 
user_proto = jsapi_InitClass_Location(cx, prototype);
if (user_proto == NULL) {
return NULL;
}
 
user_proto = jsapi_InitClass_Console(cx, prototype);
if (user_proto == NULL) {
return NULL;
}
 
user_proto = jsapi_InitClass_HTMLElement(cx, prototype);
if (user_proto == NULL) {
return NULL;
}
 
user_proto = jsapi_InitClass_HTMLCollection(cx, prototype);
if (user_proto == NULL) {
return NULL;
}
 
user_proto = jsapi_InitClass_NodeList(cx, prototype);
if (user_proto == NULL) {
return NULL;
}
 
user_proto = jsapi_InitClass_Text(cx, prototype);
if (user_proto == NULL) {
return NULL;
}
 
user_proto = jsapi_InitClass_Comment(cx, prototype);
if (user_proto == NULL) {
return NULL;
}
 
user_proto = jsapi_InitClass_Node(cx, prototype);
if (user_proto == NULL) {
return NULL;
}
 
user_proto = jsapi_InitClass_Event(cx, prototype);
if (user_proto == NULL) {
return NULL;
}
 
%}
 
api new %{
/* @todo sort out windows that are not globals */
assert(parent == NULL);
 
/* the window object is the global so its prototype *is* the instance */
newobject = prototype;
 
/* instantiate the subclasses off the window global */
private->document = jsapi_new_Document(cx,
NULL,
newobject,
(dom_document *)dom_node_ref(htmlc->document),
htmlc);
if (private->document == NULL) {
free(private);
return NULL;
}
 
private->navigator = jsapi_new_Navigator(cx, NULL, newobject);
if (private->navigator == NULL) {
free(private);
return NULL;
}
 
private->console = jsapi_new_Console(cx, NULL, newobject);
if (private->console == NULL) {
free(private);
return NULL;
}
 
/** @todo forms, history */
 
LOG(("Created new window object %p", newobject));
%}
 
operation confirm %{
warn_user(message, NULL);
%}
 
operation alert %{
warn_user(message, NULL);
%}
 
operation prompt %{
warn_user(message, NULL);
%}
 
/* boolean dispatchEvent(Event event); */
operation dispatchEvent %{
/* this implementation is unique to the window object as it is
* not a "real" dom node.
*/
 
/* caution, this must match the struct generated from event.bnd */
struct {
dom_event *event;
} *event_private;
dom_string *type_dom = NULL;
dom_exception exc;
jsval eventval = JSVAL_VOID;
jsval event_argv[1];
jsval event_rval;
 
event_private = JS_GetInstancePrivate(cx, event, &JSClass_Event, NULL);
if (event_private->event == NULL) {
/** @todo type error? */
jsret = JS_FALSE;
} else {
exc = dom_event_get_type(event_private->event, &type_dom);
if (exc == DOM_NO_ERR) {
 
if (dom_string_isequal(type_dom, corestring_dom_load)) {
JS_GetProperty(cx, JSAPI_THIS_OBJECT(cx, vp), "onload", &eventval);
}
 
if (!JSVAL_IS_VOID(eventval)) {
event_argv[0] = eventval;
jsret = JS_CallFunctionValue(cx, NULL, eventval, 1, event_argv, &event_rval);
}
}
}
%}
 
getter location %{
jsval loc;
JS_GetProperty(cx, private->document, "location", &loc);
jsret = JSVAL_TO_OBJECT(loc);
%}
 
getter window %{
jsret = obj;
%}
 
getter self %{
jsret = obj;
%}
 
getter EventHandler %{
/* this implementation is unique to the window object as it is
* not a dom node.
*/
JSLOG("propname[%d]=\"%s\"",
tinyid,
jsclass_properties[tinyid].name);
%}
 
setter EventHandler %{
/* this implementation is unique to the window object as it is
* not a dom node.
*/
JSLOG("propname[%d]=\"%s\"",
tinyid,
jsclass_properties[tinyid].name);
%}
/programs/network/netsurf/netsurf/javascript/jsapi.c
0,0 → 1,333
/*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include "javascript/jsapi.h"
#include "render/html_internal.h"
#include "content/content.h"
#include "javascript/content.h"
#include "javascript/js.h"
 
#include "utils/log.h"
 
#include "window.h"
#include "event.h"
 
static JSRuntime *rt; /* global runtime */
 
void js_initialise(void)
{
/* Create a JS runtime. */
 
#if JS_VERSION >= 180
JS_SetCStringsAreUTF8(); /* we prefer our runtime to be utf-8 */
#endif
 
rt = JS_NewRuntime(8L * 1024L * 1024L);
JSLOG("New runtime handle %p", rt);
 
if (rt != NULL) {
/* register script content handler */
javascript_init();
}
}
 
void js_finalise(void)
{
if (rt != NULL) {
JSLOG("destroying runtime handle %p", rt);
JS_DestroyRuntime(rt);
}
JS_ShutDown();
}
 
/* The error reporter callback. */
static void js_reportError(JSContext *cx, const char *message, JSErrorReport *report)
{
JSLOG("%s:%u:%s",
report->filename ? report->filename : "<no filename>",
(unsigned int) report->lineno,
message);
}
 
jscontext *js_newcontext(void)
{
JSContext *cx;
 
if (rt == NULL) {
return NULL;
}
 
cx = JS_NewContext(rt, 8192);
if (cx == NULL) {
return NULL;
}
JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT );
JS_SetVersion(cx, JSVERSION_LATEST);
JS_SetErrorReporter(cx, js_reportError);
 
/*JS_SetGCZeal(cx, 2); */
 
JSLOG("New Context %p", cx);
 
return (jscontext *)cx;
}
 
void js_destroycontext(jscontext *ctx)
{
JSContext *cx = (JSContext *)ctx;
if (cx != NULL) {
JSLOG("Destroying Context %p", cx);
JS_DestroyContext(cx);
}
}
 
 
/** Create new compartment to run scripts within
*
* This performs the following actions
* 1. constructs a new global object by initialising a window class
* 2. Instantiate the global a window object
*/
jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv)
{
JSContext *cx = (JSContext *)ctx;
JSObject *window_proto;
JSObject *window;
 
if (cx == NULL) {
return NULL;
}
 
window_proto = jsapi_InitClass_Window(cx, NULL);
if (window_proto == NULL) {
JSLOG("Unable to initialise window class");
return NULL;
}
 
window = jsapi_new_Window(cx, window_proto, NULL, win_priv, doc_priv);
 
return (jsobject *)window;
}
 
bool js_exec(jscontext *ctx, const char *txt, size_t txtlen)
{
JSContext *cx = (JSContext *)ctx;
jsval rval;
 
/* JSLOG("%p \"%s\"",cx ,txt); */
 
if (ctx == NULL) {
return false;
}
 
if (txt == NULL) {
return false;
}
 
if (txtlen == 0) {
return false;
}
 
if (JS_EvaluateScript(cx,
JS_GetGlobalObject(cx),
txt, txtlen,
"<head>", 0, &rval) == JS_TRUE) {
 
return true;
}
 
return false;
}
 
dom_exception _dom_event_create(dom_document *doc, dom_event **evt);
#define dom_event_create(d, e) _dom_event_create((dom_document *)(d), (dom_event **) (e))
 
bool js_fire_event(jscontext *ctx, const char *type, dom_document *doc, dom_node *target)
{
JSContext *cx = (JSContext *)ctx;
dom_node *node = target;
JSObject *jsevent;
jsval rval;
jsval argv[1];
JSBool ret = JS_TRUE;
dom_exception exc;
dom_event *event;
dom_string *type_dom;
 
if (cx == NULL) {
return false;
}
 
if (node == NULL) {
/* deliver manufactured event to window */
JSLOG("Dispatching event %s at window", type);
 
/* create and initialise and event object */
exc = dom_string_create((unsigned char*)type,
strlen(type),
&type_dom);
if (exc != DOM_NO_ERR) {
return false;
}
 
exc = dom_event_create(doc, &event);
if (exc != DOM_NO_ERR) {
return false;
}
 
exc = dom_event_init(event, type_dom, false, false);
dom_string_unref(type_dom);
if (exc != DOM_NO_ERR) {
return false;
}
 
jsevent = jsapi_new_Event(cx, NULL, NULL, event);
if (jsevent == NULL) {
return false;
}
 
/* dispatch event at the window object */
argv[0] = OBJECT_TO_JSVAL(jsevent);
 
ret = JS_CallFunctionName(cx,
JS_GetGlobalObject(cx),
"dispatchEvent",
1,
argv,
&rval);
} else {
JSLOG("Dispatching event %s at %p", type, node);
 
/* create and initialise and event object */
exc = dom_string_create((unsigned char*)type,
strlen(type),
&type_dom);
if (exc != DOM_NO_ERR) {
return false;
}
 
exc = dom_event_create(doc, &event);
if (exc != DOM_NO_ERR) {
return false;
}
 
exc = dom_event_init(event, type_dom, true, true);
dom_string_unref(type_dom);
if (exc != DOM_NO_ERR) {
return false;
}
 
dom_event_target_dispatch_event(node, event, &ret);
 
}
 
if (ret == JS_TRUE) {
return true;
}
return false;
}
 
struct js_dom_event_private {
JSContext *cx; /* javascript context */
jsval funcval; /* javascript function to call */
struct dom_node *node; /* dom node event listening on */
dom_string *type; /* event type */
dom_event_listener *listener; /* the listener containing this */
};
 
static void
js_dom_event_listener(struct dom_event *event, void *pw)
{
struct js_dom_event_private *private = pw;
jsval event_argv[1];
jsval event_rval;
JSObject *jsevent;
 
JSLOG("WOOT dom event with %p", private);
 
if (!JSVAL_IS_VOID(private->funcval)) {
jsevent = jsapi_new_Event(private->cx, NULL, NULL, event);
if (jsevent != NULL) {
 
/* dispatch event at the window object */
event_argv[0] = OBJECT_TO_JSVAL(jsevent);
 
JS_CallFunctionValue(private->cx,
NULL,
private->funcval,
1,
event_argv,
&event_rval);
}
}
}
 
/* add a listener to a dom node
*
* 1. Create a dom_event_listener From a handle_event function pointer
* and a private word In a document context
*
* 2. Register for your events on a target (dom nodes are targets)
* dom_event_target_add_event_listener(node, evt_name, listener,
* capture_or_not)
*
*/
 
bool
js_dom_event_add_listener(jscontext *ctx,
struct dom_document *document,
struct dom_node *node,
struct dom_string *event_type_dom,
void *js_funcval)
{
JSContext *cx = (JSContext *)ctx;
dom_exception exc;
struct js_dom_event_private *private;
 
private = malloc(sizeof(struct js_dom_event_private));
if (private == NULL) {
return false;
}
 
exc = dom_event_listener_create(document,
js_dom_event_listener,
private,
&private->listener);
if (exc != DOM_NO_ERR) {
return false;
}
 
private->cx = cx;
private->funcval = *(jsval *)js_funcval;
private->node = node;
private->type = event_type_dom;
 
JSLOG("adding %p to listener", private);
 
JSAPI_ADD_VALUE_ROOT(cx, &private->funcval);
exc = dom_event_target_add_event_listener(private->node,
private->type,
private->listener,
true);
if (exc != DOM_NO_ERR) {
JSLOG("failed to add listener");
JSAPI_REMOVE_VALUE_ROOT(cx, &private->funcval);
}
 
return true;
}
/programs/network/netsurf/netsurf/javascript/jsapi.h
0,0 → 1,385
/*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* spidermonkey jsapi compatability glue.
*/
 
#ifndef _NETSURF_JAVASCRIPT_JSAPI_H_
#define _NETSURF_JAVASCRIPT_JSAPI_H_
 
#ifdef WITH_MOZJS
#include "js/jsapi.h"
#else
#include "mozjs/jsapi.h"
#endif
 
#if JS_VERSION < 180
 
/************************** Spidermonkey 1.7.0 **************************/
 
#include <string.h>
 
#ifndef JSVERSION_LATEST
#define JSVERSION_LATEST JS_VERSION
#endif
 
#ifndef JSOPTION_JIT
#define JSOPTION_JIT 0
#endif
 
/* *CAUTION* these native function macros introduce and use jsapi_this
* and jsapi_rval variables, native function code should not conflict
* with these
*/
 
/* native function definition with five parameters */
#define JSAPI_FUNC(name, cx, argc, vp) \
jsapi_func_##name(cx, JSObject *jsapi_this, argc, vp, jsval *jsapi_rval)
 
/* native function return value - No macro available */
#define JSAPI_FUNC_RVAL(cx, vp) (jsapi_rval)
 
/* native function return value setter - No macro available */
#define JSAPI_FUNC_SET_RVAL(cx, vp, v) (*jsapi_rval = (v))
 
/* arguments */
#define JSAPI_FUNC_ARGV(cx, vp) (vp)
 
/* check if a jsval is an object */
#define JSAPI_JSVAL_IS_OBJECT(v) JSVAL_IS_OBJECT(v)
 
/* native function specifier with five parameters and no JS_FS macro */
#define JSAPI_FS(name, nargs, flags) \
{ #name, jsapi_func_##name, nargs, flags, 0 }
 
/* native function specifier list end */
#define JSAPI_FS_END { NULL, NULL, 0, 0, 0 }
 
 
 
 
/* native proprty definition */
#define JSAPI_PROP(name, cx, obj, vp) \
jsapi_property_##name(cx, obj, jsval jsapi_id, vp)
#define JSAPI_STRICTPROP JSAPI_PROP
 
/* native property return value */
#define JSAPI_PROP_RVAL(cx, vp) (*(vp))
 
/* native property getter return value */
#define JSAPI_PROP_SET_RVAL(cx, vp, v) (*(vp) = (v))
 
/* native property ID value as a jsval */
#define JSAPI_PROP_IDVAL(cx, vp) (*(vp) = jsapi_id)
 
/* native property specifier */
#define JSAPI_PS(name, fnname, tinyid, flags) \
{ name , tinyid , flags , jsapi_property_##fnname##_get , jsapi_property_##fnname##_set }
 
/* native property specifier with no setter */
#define JSAPI_PS_RO(name, fnname, tinyid, flags) \
{ name , tinyid , flags | JSPROP_READONLY, jsapi_property_##fnname##_get , NULL }
 
/* native property specifier list end */
#define JSAPI_PS_END { NULL, 0, 0, NULL, NULL }
 
#define JS_StrictPropertyStub JS_PropertyStub
 
 
 
 
/* The object instance in a native call */
/* "this" JSObject getter */
JSObject * js_ComputeThis(JSContext *cx, JSObject *thisp, void *argv);
#define JSAPI_THIS_OBJECT(cx, vp) \
js_ComputeThis(cx, JSVAL_TO_OBJECT(vp[-1]), vp)
 
static inline JSObject *
JS_NewCompartmentAndGlobalObject(JSContext *cx,
JSClass *jsclass,
JSPrincipals *principals)
{
JSObject *global;
global = JS_NewObject(cx, jsclass, NULL, NULL);
if (global == NULL) {
return NULL;
}
return global;
}
 
 
#define JSString_to_char(injsstring, outchar, outlen) \
outchar = JS_GetStringBytes(injsstring); \
outlen = strlen(outchar)
 
/* string type cast */
#define JSAPI_STRING_TO_JSVAL(str) ((str == NULL)?JSVAL_NULL:STRING_TO_JSVAL(str))
 
#define JSAPI_CLASS_NO_INTERNAL_MEMBERS NULL
 
/* Garbage Collector */
 
/* macros for GC marking */
#define JSAPI_JSCLASS_MARK_IS_TRACE 0
 
#define JSAPI_JSCLASS_MARKOP(x) (x)
 
#define JSAPI_MARKOP(name) uint32_t name(JSContext *cx, JSObject *obj, void *arg)
 
#define JSAPI_MARKCX cx
 
#define JSAPI_GCMARK(thing) JS_MarkGCThing(cx, thing, "object", arg)
 
/* Macros for manipulating GC root */
 
#define JSAPI_ADD_OBJECT_ROOT(cx, obj) JS_AddRoot(cx, obj)
#define JSAPI_REMOVE_OBJECT_ROOT(cx, obj) JS_RemoveRoot(cx, obj)
 
#define JSAPI_ADD_VALUE_ROOT(cx, obj) JS_AddRoot(cx, obj)
#define JSAPI_REMOVE_VALUE_ROOT(cx, obj) JS_RemoveRoot(cx, obj)
 
#elif JS_VERSION == 180
 
/************************** Spidermonkey 1.8.0 **************************/
 
#include <string.h>
 
/* *CAUTION* these macros introduce and use jsapi_this and jsapi_rval
* parameters, native function code should not conflict with these
*/
 
/* five parameter jsapi native call */
#define JSAPI_FUNC(name, cx, argc, vp) \
jsapi_func_##name(cx, JSObject *jsapi_this, argc, vp, jsval *jsapi_rval)
 
/* five parameter function descriptor */
#define JSAPI_FS(name, nargs, flags) \
JS_FS(#name, jsapi_func_##name, nargs, flags, 0)
 
/* function descriptor end */
#define JSAPI_FS_END JS_FS_END
 
/* return value */
#define JSAPI_RVAL(cx, vp) JS_RVAL(cx, jsapi_rval)
 
/* return value setter */
#define JSAPI_FUNC_SET_RVAL(cx, vp, v) JS_SET_RVAL(cx, jsapi_rval, v)
 
/* arguments */
#define JSAPI_FUNC_ARGV(cx, vp) (vp)
 
/* check if a jsval is an object */
#define JSAPI_JSVAL_IS_OBJECT(v) JSVAL_IS_OBJECT(v)
 
/* The object instance in a native call */
#define JSAPI_THIS_OBJECT(cx,vp) jsapi_this
 
 
 
/* proprty native calls */
#define JSAPI_PROP(name, cx, obj, vp) \
jsapi_property_##name(cx, obj, jsval jsapi_id, vp)
#define JSAPI_STRICTPROP JSAPI_PROP
 
/* native property return value */
#define JSAPI_PROP_RVAL JS_RVAL
 
/* native property return value setter */
#define JSAPI_PROP_SET_RVAL JS_SET_RVAL
 
/* native property ID value as a jsval */
#define JSAPI_PROP_IDVAL(cx, vp) (*(vp) = jsapi_id)
 
/* property specifier */
#define JSAPI_PS(name, fnname, tinyid, flags) \
{ name , tinyid , flags , jsapi_property_##fnname##_get , jsapi_property_##fnname##_set }
 
#define JSAPI_PS_RO(name, fnname, tinyid, flags) \
{ name , tinyid , flags | JSPROP_READONLY, jsapi_property_##fnname##_get , NULL }
 
#define JSAPI_PS_END { NULL, 0, 0, NULL, NULL }
 
 
 
 
static inline JSObject *
JS_NewCompartmentAndGlobalObject(JSContext *cx,
JSClass *jsclass,
JSPrincipals *principals)
{
JSObject *global;
global = JS_NewObject(cx, jsclass, NULL, NULL);
if (global == NULL) {
return NULL;
}
return global;
}
 
#define JS_StrictPropertyStub JS_PropertyStub
 
#define JSString_to_char(injsstring, outchar, outlen) \
outchar = JS_GetStringBytes(injsstring); \
outlen = strlen(outchar)
 
/* string type cast */
#define JSAPI_STRING_TO_JSVAL(str) ((str == NULL)?JSVAL_NULL:STRING_TO_JSVAL(str))
 
#define JSAPI_CLASS_NO_INTERNAL_MEMBERS NULL
 
/* Garbage Collector */
 
/* GC marking */
#ifdef JSCLASS_MARK_IS_TRACE
/* mark function pointer requires casting */
#define JSAPI_JSCLASS_MARK_IS_TRACE JSCLASS_MARK_IS_TRACE
#define JSAPI_JSCLASS_MARKOP(x) ((JSMarkOp)x)
#else
/* mark function pointer does not require casting */
#define JSAPI_JSCLASS_MARK_IS_TRACE 0
#define JSAPI_JSCLASS_MARKOP(x) (x)
#endif
 
#define JSAPI_MARKOP(name) JSBool name(JSTracer *trc, JSObject *obj)
 
#define JSAPI_MARKCX trc->context
 
#define JSAPI_GCMARK(thing) JS_CallTracer(trc, thing, JSTRACE_OBJECT);
 
/* Macros for manipulating GC root */
#define JSAPI_ADD_OBJECT_ROOT(cx, obj) JS_AddRoot(cx, obj)
#define JSAPI_REMOVE_OBJECT_ROOT(cx, obj) JS_RemoveRoot(cx, obj)
 
#define JSAPI_ADD_VALUE_ROOT(cx, obj) JS_AddRoot(cx, obj)
#define JSAPI_REMOVE_VALUE_ROOT(cx, obj) JS_RemoveRoot(cx, obj)
 
 
#else /* #if JS_VERSION == 180 */
 
/************************** Spidermonkey 1.8.5 **************************/
 
/* three parameter jsapi native call */
#define JSAPI_FUNC(name, cx, argc, vp) jsapi_func_##name(cx, argc, vp)
 
/* three parameter function descriptor */
#define JSAPI_FS(name, nargs, flags) \
JS_FS(#name, jsapi_func_##name, nargs, flags)
 
/* function descriptor end */
#define JSAPI_FS_END JS_FS_END
 
/* return value */
#define JSAPI_RVAL JS_RVAL
 
/* return value setter */
#define JSAPI_FUNC_SET_RVAL JS_SET_RVAL
 
/* arguments */
#define JSAPI_FUNC_ARGV(cx, vp) JS_ARGV(cx,vp)
 
/* check if a jsval is an object */
#define JSAPI_JSVAL_IS_OBJECT(v) JSVAL_IS_OBJECT(v)
/* The docuemntation says this is obsolete and should be
* ((JSVAL_IS_NULL(v)) || (JSVAL_IS_PRIMITIVE(v)))
* which doesnt work
*/
 
 
/* The object instance in a native call */
#define JSAPI_THIS_OBJECT(cx,vp) JS_THIS_OBJECT(cx,vp)
 
/* proprty native calls */
#define JSAPI_PROP(name, cx, obj, vp) \
jsapi_property_##name(cx, obj, jsid jsapi_id, vp)
#define JSAPI_STRICTPROP(name, cx, obj, vp) \
jsapi_property_##name(cx, obj, jsid jsapi_id, JSBool strict, vp)
 
/* native property return value */
#define JSAPI_PROP_RVAL JS_RVAL
 
/* native property getter return value */
#define JSAPI_PROP_SET_RVAL JS_SET_RVAL
 
/* native property ID value as a jsval */
#define JSAPI_PROP_IDVAL(cx, vp) JS_IdToValue(cx, jsapi_id, vp)
 
/* property specifier */
#define JSAPI_PS(name, fnname, tinyid, flags) { \
name, \
tinyid, \
flags, \
jsapi_property_##fnname##_get, \
jsapi_property_##fnname##_set \
}
 
#define JSAPI_PS_RO(name, fnname, tinyid, flags) { \
name, \
tinyid, \
flags | JSPROP_READONLY, \
jsapi_property_##fnname##_get, \
NULL \
}
 
#define JSAPI_PS_END { NULL, 0, 0, NULL, NULL }
 
 
#define JSString_to_char(injsstring, outchar, outlen) \
outlen = JS_GetStringLength(injsstring); \
outchar = alloca(sizeof(char)*(outlen+1)); \
JS_EncodeStringToBuffer(injsstring, outchar, outlen); \
outchar[outlen] = '\0'
 
/* string type cast */
#define JSAPI_STRING_TO_JSVAL(str) ((str == NULL)?JSVAL_NULL:STRING_TO_JSVAL(str))
 
#define JSAPI_CLASS_NO_INTERNAL_MEMBERS JSCLASS_NO_INTERNAL_MEMBERS
 
/* GC marking */
#ifdef JSCLASS_MARK_IS_TRACE
/* mark requires casting */
#define JSAPI_JSCLASS_MARK_IS_TRACE JSCLASS_MARK_IS_TRACE
#define JSAPI_JSCLASS_MARKOP(x) ((JSMarkOp)x)
#else
/* mark does not require casting */
#define JSAPI_JSCLASS_MARK_IS_TRACE 0
#define JSAPI_JSCLASS_MARKOP(x) (x)
#endif
 
#define JSAPI_MARKOP(name) JSBool name(JSTracer *trc, JSObject *obj)
 
#define JSAPI_MARKCX trc->context
 
#define JSAPI_GCMARK(thing) JS_CallTracer(trc, thing, JSTRACE_OBJECT);
 
/* Macros for manipulating GC root */
#define JSAPI_ADD_OBJECT_ROOT(cx, obj) JS_AddObjectRoot(cx, obj)
#define JSAPI_REMOVE_OBJECT_ROOT(cx, obj) JS_RemoveObjectRoot(cx, obj)
 
#define JSAPI_ADD_VALUE_ROOT(cx, val) JS_AddValueRoot(cx, val)
#define JSAPI_REMOVE_VALUE_ROOT(cx, val) JS_RemoveValueRoot(cx, val)
 
#endif
 
#define JSLOG(args...) LOG((args))
#ifdef ENABLE_VERBOSE_JS_DEBUG
#define JSDBG(args...) LOG((args))
#else
#define JSDBG(args...)
#endif
 
#endif
/programs/network/netsurf/netsurf/javascript/make.js
0,0 → 1,21
CFLAGS += -O2
NETSURF_FB_FRONTEND := sdl
NETSURF_FB_FONTLIB := internal
 
NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
 
# Default resource install path
NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
 
# Default framebuffer search path
NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
 
# freetype compiled in font serch path
NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
OBJS := none.o
 
 
OUTFILE = TEST.o
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include
include $(MENUETDEV)/makefiles/Makefile_for_o_lib
/programs/network/netsurf/netsurf/javascript/none.c
0,0 → 1,60
/*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Dummy implementation of javascript engine functions.
*/
 
#include "content/content.h"
#include "desktop/options.h"
 
#include "javascript/js.h"
#include "utils/log.h"
 
void js_initialise(void)
{
nsoption_set_bool(enable_javascript, false);
}
 
void js_finalise(void)
{
}
 
jscontext *js_newcontext(void)
{
return NULL;
}
 
void js_destroycontext(jscontext *ctx)
{
}
 
jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv)
{
return NULL;
}
 
bool js_exec(jscontext *ctx, const char *txt, size_t txtlen)
{
return true;
}
 
bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc, struct dom_node *target)
{
return true;
}
/programs/network/netsurf/netsurf/objs/divdi3.c
0,0 → 1,345
/* 64-bit multiplication and division
Copyright (C) 1989, 1992-1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of the GNU C Library.
 
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
 
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
 
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
 
#include <endian.h>
#include <stdlib.h>
 
#define __WORDSIZE 32
#define __i386__
 
#if __WORDSIZE == 32
 
typedef unsigned int UQItype __attribute__ ((mode (QI)));
typedef int SItype __attribute__ ((mode (SI)));
typedef unsigned int USItype __attribute__ ((mode (SI)));
typedef int DItype __attribute__ ((mode (DI)));
typedef unsigned int UDItype __attribute__ ((mode (DI)));
#define Wtype SItype
#define HWtype SItype
#define DWtype DItype
#define UWtype USItype
#define UHWtype USItype
#define UDWtype UDItype
#define W_TYPE_SIZE 32
 
#include "longlong.h"
 
const
unsigned char __clz_tab[] =
{
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
};
 
#if __BYTE_ORDER == __BIG_ENDIAN
struct DWstruct { Wtype high, low;};
#elif __BYTE_ORDER == __LITTLE_ENDIAN
struct DWstruct { Wtype low, high;};
#else
#error Unhandled endianity
#endif
typedef union { struct DWstruct s; DWtype ll; } DWunion;
 
/* Prototypes of exported functions. */
extern DWtype __divdi3 (DWtype u, DWtype v);
extern DWtype __moddi3 (DWtype u, DWtype v);
extern UDWtype __udivdi3 (UDWtype u, UDWtype v);
extern UDWtype __umoddi3 (UDWtype u, UDWtype v);
 
static UDWtype
__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
{
DWunion ww;
DWunion nn, dd;
DWunion rr;
UWtype d0, d1, n0, n1, n2;
UWtype q0, q1;
UWtype b, bm;
 
nn.ll = n;
dd.ll = d;
 
d0 = dd.s.low;
d1 = dd.s.high;
n0 = nn.s.low;
n1 = nn.s.high;
 
#if !UDIV_NEEDS_NORMALIZATION
if (d1 == 0)
{
if (d0 > n1)
{
/* 0q = nn / 0D */
 
udiv_qrnnd (q0, n0, n1, n0, d0);
q1 = 0;
 
/* Remainder in n0. */
}
else
{
/* qq = NN / 0d */
 
if (d0 == 0)
d0 = 1 / d0; /* Divide intentionally by zero. */
 
udiv_qrnnd (q1, n1, 0, n1, d0);
udiv_qrnnd (q0, n0, n1, n0, d0);
 
/* Remainder in n0. */
}
 
if (rp != 0)
{
rr.s.low = n0;
rr.s.high = 0;
*rp = rr.ll;
}
}
 
#else /* UDIV_NEEDS_NORMALIZATION */
 
if (d1 == 0)
{
if (d0 > n1)
{
/* 0q = nn / 0D */
 
count_leading_zeros (bm, d0);
 
if (bm != 0)
{
/* Normalize, i.e. make the most significant bit of the
denominator set. */
 
d0 = d0 << bm;
n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
n0 = n0 << bm;
}
 
udiv_qrnnd (q0, n0, n1, n0, d0);
q1 = 0;
 
/* Remainder in n0 >> bm. */
}
else
{
/* qq = NN / 0d */
 
if (d0 == 0)
d0 = 1 / d0; /* Divide intentionally by zero. */
 
count_leading_zeros (bm, d0);
 
if (bm == 0)
{
/* From (n1 >= d0) /\ (the most significant bit of d0 is set),
conclude (the most significant bit of n1 is set) /\ (the
leading quotient digit q1 = 1).
 
This special case is necessary, not an optimization.
(Shifts counts of W_TYPE_SIZE are undefined.) */
 
n1 -= d0;
q1 = 1;
}
else
{
/* Normalize. */
 
b = W_TYPE_SIZE - bm;
 
d0 = d0 << bm;
n2 = n1 >> b;
n1 = (n1 << bm) | (n0 >> b);
n0 = n0 << bm;
 
udiv_qrnnd (q1, n1, n2, n1, d0);
}
 
/* n1 != d0... */
 
udiv_qrnnd (q0, n0, n1, n0, d0);
 
/* Remainder in n0 >> bm. */
}
 
if (rp != 0)
{
rr.s.low = n0 >> bm;
rr.s.high = 0;
*rp = rr.ll;
}
}
#endif /* UDIV_NEEDS_NORMALIZATION */
 
else
{
if (d1 > n1)
{
/* 00 = nn / DD */
 
q0 = 0;
q1 = 0;
 
/* Remainder in n1n0. */
if (rp != 0)
{
rr.s.low = n0;
rr.s.high = n1;
*rp = rr.ll;
}
}
else
{
/* 0q = NN / dd */
 
count_leading_zeros (bm, d1);
if (bm == 0)
{
/* From (n1 >= d1) /\ (the most significant bit of d1 is set),
conclude (the most significant bit of n1 is set) /\ (the
quotient digit q0 = 0 or 1).
 
This special case is necessary, not an optimization. */
 
/* The condition on the next line takes advantage of that
n1 >= d1 (true due to program flow). */
if (n1 > d1 || n0 >= d0)
{
q0 = 1;
sub_ddmmss (n1, n0, n1, n0, d1, d0);
}
else
q0 = 0;
 
q1 = 0;
 
if (rp != 0)
{
rr.s.low = n0;
rr.s.high = n1;
*rp = rr.ll;
}
}
else
{
UWtype m1, m0;
/* Normalize. */
 
b = W_TYPE_SIZE - bm;
 
d1 = (d1 << bm) | (d0 >> b);
d0 = d0 << bm;
n2 = n1 >> b;
n1 = (n1 << bm) | (n0 >> b);
n0 = n0 << bm;
 
udiv_qrnnd (q0, n1, n2, n1, d1);
umul_ppmm (m1, m0, q0, d0);
 
if (m1 > n1 || (m1 == n1 && m0 > n0))
{
q0--;
sub_ddmmss (m1, m0, m1, m0, d1, d0);
}
 
q1 = 0;
 
/* Remainder in (n1n0 - m1m0) >> bm. */
if (rp != 0)
{
sub_ddmmss (n1, n0, n1, n0, m1, m0);
rr.s.low = (n1 << b) | (n0 >> bm);
rr.s.high = n1 >> bm;
*rp = rr.ll;
}
}
}
}
 
ww.s.low = q0;
ww.s.high = q1;
return ww.ll;
}
 
DWtype
__divdi3 (DWtype u, DWtype v)
{
Wtype c = 0;
DWtype w;
 
if (u < 0)
{
c = ~c;
u = -u;
}
if (v < 0)
{
c = ~c;
v = -v;
}
w = __udivmoddi4 (u, v, NULL);
if (c)
w = -w;
return w;
}
 
DWtype
__moddi3 (DWtype u, DWtype v)
{
Wtype c = 0;
DWtype w;
 
if (u < 0)
{
c = ~c;
u = -u;
}
if (v < 0)
v = -v;
__udivmoddi4 (u, v, &w);
if (c)
w = -w;
return w;
}
 
UDWtype
__udivdi3 (UDWtype u, UDWtype v)
{
return __udivmoddi4 (u, v, NULL);
}
 
UDWtype
__umoddi3 (UDWtype u, UDWtype v)
{
UDWtype w;
 
__udivmoddi4 (u, v, &w);
return w;
}
 
#endif
/programs/network/netsurf/netsurf/objs/longlong.h
0,0 → 1,1333
/* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000
Free Software Foundation, Inc.
 
This file is part of the GNU C Library.
 
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
 
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
 
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
 
/* You have to define the following before including this file:
 
UWtype -- An unsigned type, default type for operations (typically a "word")
UHWtype -- An unsigned type, at least half the size of UWtype.
UDWtype -- An unsigned type, at least twice as large a UWtype
W_TYPE_SIZE -- size in bits of UWtype
 
UQItype -- Unsigned 8 bit type.
SItype, USItype -- Signed and unsigned 32 bit types.
DItype, UDItype -- Signed and unsigned 64 bit types.
 
On a 32 bit machine UWtype should typically be USItype;
on a 64 bit machine, UWtype should typically be UDItype.
*/
 
#define __BITS4 (W_TYPE_SIZE / 4)
#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
 
#ifndef W_TYPE_SIZE
#define W_TYPE_SIZE 32
#define UWtype USItype
#define UHWtype USItype
#define UDWtype UDItype
#endif
 
/* Define auxiliary asm macros.
 
1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two
UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype
word product in HIGH_PROD and LOW_PROD.
 
2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a
UDWtype product. This is just a variant of umul_ppmm.
 
3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
denominator) divides a UDWtype, composed by the UWtype integers
HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient
in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less
than DENOMINATOR for correct operation. If, in addition, the most
significant bit of DENOMINATOR must be 1, then the pre-processor symbol
UDIV_NEEDS_NORMALIZATION is defined to 1.
 
4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
denominator). Like udiv_qrnnd but the numbers are signed. The quotient
is rounded towards 0.
 
5) count_leading_zeros(count, x) counts the number of zero-bits from the
msb to the first nonzero bit in the UWtype X. This is the number of
steps X needs to be shifted left to set the msb. Undefined for X == 0,
unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value.
 
6) count_trailing_zeros(count, x) like count_leading_zeros, but counts
from the least significant end.
 
7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
high_addend_2, low_addend_2) adds two UWtype integers, composed by
HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2
respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow
(i.e. carry out) is not stored anywhere, and is lost.
 
8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend,
high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers,
composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and
LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE
and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere,
and is lost.
 
If any of these macros are left undefined for a particular CPU,
C macros are used. */
 
/* The CPUs come in alphabetical order below.
 
Please add support for more CPUs here, or improve the current support
for the CPUs below!
(E.g. WE32100, IBM360.) */
 
#if defined (__GNUC__) && !defined (NO_ASM)
 
/* We sometimes need to clobber "cc" with gcc2, but that would not be
understood by gcc1. Use cpp to avoid major code duplication. */
#if __GNUC__ < 2
#define __CLOBBER_CC
#define __AND_CLOBBER_CC
#else /* __GNUC__ >= 2 */
#define __CLOBBER_CC : "cc"
#define __AND_CLOBBER_CC , "cc"
#endif /* __GNUC__ < 2 */
 
#if defined (__alpha) && W_TYPE_SIZE == 64
#define umul_ppmm(ph, pl, m0, m1) \
do { \
UDItype __m0 = (m0), __m1 = (m1); \
__asm__ ("umulh %r1,%2,%0" \
: "=r" ((UDItype) ph) \
: "%rJ" (__m0), \
"rI" (__m1)); \
(pl) = __m0 * __m1; \
} while (0)
#define UMUL_TIME 46
#ifndef LONGLONG_STANDALONE
#define udiv_qrnnd(q, r, n1, n0, d) \
do { UDItype __r; \
(q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \
(r) = __r; \
} while (0)
extern UDItype __udiv_qrnnd (UDItype *, UDItype, UDItype, UDItype);
#define UDIV_TIME 220
#endif /* LONGLONG_STANDALONE */
#ifdef __alpha_cix__
#define count_leading_zeros(COUNT,X) \
__asm__("ctlz %1,%0" : "=r"(COUNT) : "r"(X))
#define count_trailing_zeros(COUNT,X) \
__asm__("cttz %1,%0" : "=r"(COUNT) : "r"(X))
#define COUNT_LEADING_ZEROS_0 64
#else
extern const UQItype __clz_tab[];
#define count_leading_zeros(COUNT,X) \
do { \
UDItype __xr = (X), __t, __a; \
__asm__("cmpbge $31,%1,%0" : "=r"(__t) : "r"(__xr)); \
__a = __clz_tab[__t ^ 0xff] - 1; \
__asm__("extbl %1,%2,%0" : "=r"(__t) : "r"(__xr), "r"(__a)); \
(COUNT) = 64 - (__clz_tab[__t] + __a*8); \
} while (0)
#define count_trailing_zeros(COUNT,X) \
do { \
UDItype __xr = (X), __t, __a; \
__asm__("cmpbge $31,%1,%0" : "=r"(__t) : "r"(__xr)); \
__t = ~__t & -~__t; \
__a = ((__t & 0xCC) != 0) * 2; \
__a += ((__t & 0xF0) != 0) * 4; \
__a += ((__t & 0xAA) != 0); \
__asm__("extbl %1,%2,%0" : "=r"(__t) : "r"(__xr), "r"(__a)); \
__a <<= 3; \
__t &= -__t; \
__a += ((__t & 0xCC) != 0) * 2; \
__a += ((__t & 0xF0) != 0) * 4; \
__a += ((__t & 0xAA) != 0); \
(COUNT) = __a; \
} while (0)
#endif /* __alpha_cix__ */
#endif /* __alpha */
 
#if defined (__arc__) && W_TYPE_SIZE == 32
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("add.f %1, %4, %5\n\tadc %0, %2, %3" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "%r" ((USItype) (ah)), \
"rIJ" ((USItype) (bh)), \
"%r" ((USItype) (al)), \
"rIJ" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("sub.f %1, %4, %5\n\tsbc %0, %2, %3" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "r" ((USItype) (ah)), \
"rIJ" ((USItype) (bh)), \
"r" ((USItype) (al)), \
"rIJ" ((USItype) (bl)))
/* Call libgcc routine. */
#define umul_ppmm(w1, w0, u, v) \
do { \
DWunion __w; \
__w.ll = __umulsidi3 (u, v); \
w1 = __w.s.high; \
w0 = __w.s.low; \
} while (0)
#define __umulsidi3 __umulsidi3
UDItype __umulsidi3 (USItype, USItype);
#endif
 
#if defined (__arm__) && W_TYPE_SIZE == 32
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("adds %1, %4, %5\n\tadc %0, %2, %3" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "%r" ((USItype) (ah)), \
"rI" ((USItype) (bh)), \
"%r" ((USItype) (al)), \
"rI" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subs %1, %4, %5\n\tsbc %0, %2, %3" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "r" ((USItype) (ah)), \
"rI" ((USItype) (bh)), \
"r" ((USItype) (al)), \
"rI" ((USItype) (bl)))
#define umul_ppmm(xh, xl, a, b) \
{register USItype __t0, __t1, __t2; \
__asm__ ("%@ Inlined umul_ppmm\n" \
" mov %2, %5, lsr #16\n" \
" mov %0, %6, lsr #16\n" \
" bic %3, %5, %2, lsl #16\n" \
" bic %4, %6, %0, lsl #16\n" \
" mul %1, %3, %4\n" \
" mul %4, %2, %4\n" \
" mul %3, %0, %3\n" \
" mul %0, %2, %0\n" \
" adds %3, %4, %3\n" \
" addcs %0, %0, #65536\n" \
" adds %1, %1, %3, lsl #16\n" \
" adc %0, %0, %3, lsr #16" \
: "=&r" ((USItype) (xh)), \
"=r" ((USItype) (xl)), \
"=&r" (__t0), "=&r" (__t1), "=r" (__t2) \
: "r" ((USItype) (a)), \
"r" ((USItype) (b)));}
#define UMUL_TIME 20
#define UDIV_TIME 100
#endif /* __arm__ */
 
#if defined (__hppa) && W_TYPE_SIZE == 32
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("add %4,%5,%1\n\taddc %2,%3,%0" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "%rM" ((USItype) (ah)), \
"rM" ((USItype) (bh)), \
"%rM" ((USItype) (al)), \
"rM" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("sub %4,%5,%1\n\tsubb %2,%3,%0" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "rM" ((USItype) (ah)), \
"rM" ((USItype) (bh)), \
"rM" ((USItype) (al)), \
"rM" ((USItype) (bl)))
#if defined (_PA_RISC1_1)
#define umul_ppmm(w1, w0, u, v) \
do { \
union \
{ \
UDItype __f; \
struct {USItype __w1, __w0;} __w1w0; \
} __t; \
__asm__ ("xmpyu %1,%2,%0" \
: "=x" (__t.__f) \
: "x" ((USItype) (u)), \
"x" ((USItype) (v))); \
(w1) = __t.__w1w0.__w1; \
(w0) = __t.__w1w0.__w0; \
} while (0)
#define UMUL_TIME 8
#else
#define UMUL_TIME 30
#endif
#define UDIV_TIME 40
#define count_leading_zeros(count, x) \
do { \
USItype __tmp; \
__asm__ ( \
"ldi 1,%0\n" \
" extru,= %1,15,16,%%r0 ; Bits 31..16 zero?\n" \
" extru,tr %1,15,16,%1 ; No. Shift down, skip add.\n"\
" ldo 16(%0),%0 ; Yes. Perform add.\n" \
" extru,= %1,23,8,%%r0 ; Bits 15..8 zero?\n" \
" extru,tr %1,23,8,%1 ; No. Shift down, skip add.\n"\
" ldo 8(%0),%0 ; Yes. Perform add.\n" \
" extru,= %1,27,4,%%r0 ; Bits 7..4 zero?\n" \
" extru,tr %1,27,4,%1 ; No. Shift down, skip add.\n"\
" ldo 4(%0),%0 ; Yes. Perform add.\n" \
" extru,= %1,29,2,%%r0 ; Bits 3..2 zero?\n" \
" extru,tr %1,29,2,%1 ; No. Shift down, skip add.\n"\
" ldo 2(%0),%0 ; Yes. Perform add.\n" \
" extru %1,30,1,%1 ; Extract bit 1.\n" \
" sub %0,%1,%0 ; Subtract it.\n" \
: "=r" (count), "=r" (__tmp) : "1" (x)); \
} while (0)
#endif
 
#if (defined (__i370__) || defined (__mvs__)) && W_TYPE_SIZE == 32
#define umul_ppmm(xh, xl, m0, m1) \
do { \
union {UDItype __ll; \
struct {USItype __h, __l;} __i; \
} __xx; \
USItype __m0 = (m0), __m1 = (m1); \
__asm__ ("mr %0,%3" \
: "=r" (__xx.__i.__h), \
"=r" (__xx.__i.__l) \
: "%1" (__m0), \
"r" (__m1)); \
(xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
(xh) += ((((SItype) __m0 >> 31) & __m1) \
+ (((SItype) __m1 >> 31) & __m0)); \
} while (0)
#define smul_ppmm(xh, xl, m0, m1) \
do { \
union {DItype __ll; \
struct {USItype __h, __l;} __i; \
} __xx; \
__asm__ ("mr %0,%3" \
: "=r" (__xx.__i.__h), \
"=r" (__xx.__i.__l) \
: "%1" (m0), \
"r" (m1)); \
(xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
} while (0)
#define sdiv_qrnnd(q, r, n1, n0, d) \
do { \
union {DItype __ll; \
struct {USItype __h, __l;} __i; \
} __xx; \
__xx.__i.__h = n1; __xx.__i.__l = n0; \
__asm__ ("dr %0,%2" \
: "=r" (__xx.__ll) \
: "0" (__xx.__ll), "r" (d)); \
(q) = __xx.__i.__l; (r) = __xx.__i.__h; \
} while (0)
#endif
 
#if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("addl %5,%1\n\tadcl %3,%0" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "%0" ((USItype) (ah)), \
"g" ((USItype) (bh)), \
"%1" ((USItype) (al)), \
"g" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subl %5,%1\n\tsbbl %3,%0" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "0" ((USItype) (ah)), \
"g" ((USItype) (bh)), \
"1" ((USItype) (al)), \
"g" ((USItype) (bl)))
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("mull %3" \
: "=a" ((USItype) (w0)), \
"=d" ((USItype) (w1)) \
: "%0" ((USItype) (u)), \
"rm" ((USItype) (v)))
#define udiv_qrnnd(q, r, n1, n0, dv) \
__asm__ ("divl %4" \
: "=a" ((USItype) (q)), \
"=d" ((USItype) (r)) \
: "0" ((USItype) (n0)), \
"1" ((USItype) (n1)), \
"rm" ((USItype) (dv)))
#define count_leading_zeros(count, x) \
do { \
USItype __cbtmp; \
__asm__ ("bsrl %1,%0" \
: "=r" (__cbtmp) : "rm" ((USItype) (x))); \
(count) = __cbtmp ^ 31; \
} while (0)
#define count_trailing_zeros(count, x) \
__asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x)))
#define UMUL_TIME 40
#define UDIV_TIME 40
#endif /* 80x86 */
 
#if defined (__i960__) && W_TYPE_SIZE == 32
#define umul_ppmm(w1, w0, u, v) \
({union {UDItype __ll; \
struct {USItype __l, __h;} __i; \
} __xx; \
__asm__ ("emul %2,%1,%0" \
: "=d" (__xx.__ll) \
: "%dI" ((USItype) (u)), \
"dI" ((USItype) (v))); \
(w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
#define __umulsidi3(u, v) \
({UDItype __w; \
__asm__ ("emul %2,%1,%0" \
: "=d" (__w) \
: "%dI" ((USItype) (u)), \
"dI" ((USItype) (v))); \
__w; })
#endif /* __i960__ */
 
#if defined (__M32R__) && W_TYPE_SIZE == 32
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
/* The cmp clears the condition bit. */ \
__asm__ ("cmp %0,%0\n\taddx %%5,%1\n\taddx %%3,%0" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "%0" ((USItype) (ah)), \
"r" ((USItype) (bh)), \
"%1" ((USItype) (al)), \
"r" ((USItype) (bl)) \
: "cbit")
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
/* The cmp clears the condition bit. */ \
__asm__ ("cmp %0,%0\n\tsubx %5,%1\n\tsubx %3,%0" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "0" ((USItype) (ah)), \
"r" ((USItype) (bh)), \
"1" ((USItype) (al)), \
"r" ((USItype) (bl)) \
: "cbit")
#endif /* __M32R__ */
 
#if defined (__mc68000__) && W_TYPE_SIZE == 32
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("add%.l %5,%1\n\taddx%.l %3,%0" \
: "=d" ((USItype) (sh)), \
"=&d" ((USItype) (sl)) \
: "%0" ((USItype) (ah)), \
"d" ((USItype) (bh)), \
"%1" ((USItype) (al)), \
"g" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("sub%.l %5,%1\n\tsubx%.l %3,%0" \
: "=d" ((USItype) (sh)), \
"=&d" ((USItype) (sl)) \
: "0" ((USItype) (ah)), \
"d" ((USItype) (bh)), \
"1" ((USItype) (al)), \
"g" ((USItype) (bl)))
 
/* The '020, '030, '040 and CPU32 have 32x32->64 and 64/32->32q-32r. */
#if defined (__mc68020__) || defined(mc68020) \
|| defined(__mc68030__) || defined(mc68030) \
|| defined(__mc68040__) || defined(mc68040) \
|| defined(__mcpu32__) || defined(mcpu32)
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("mulu%.l %3,%1:%0" \
: "=d" ((USItype) (w0)), \
"=d" ((USItype) (w1)) \
: "%0" ((USItype) (u)), \
"dmi" ((USItype) (v)))
#define UMUL_TIME 45
#define udiv_qrnnd(q, r, n1, n0, d) \
__asm__ ("divu%.l %4,%1:%0" \
: "=d" ((USItype) (q)), \
"=d" ((USItype) (r)) \
: "0" ((USItype) (n0)), \
"1" ((USItype) (n1)), \
"dmi" ((USItype) (d)))
#define UDIV_TIME 90
#define sdiv_qrnnd(q, r, n1, n0, d) \
__asm__ ("divs%.l %4,%1:%0" \
: "=d" ((USItype) (q)), \
"=d" ((USItype) (r)) \
: "0" ((USItype) (n0)), \
"1" ((USItype) (n1)), \
"dmi" ((USItype) (d)))
 
#else /* not mc68020 */
#if !defined(__mcf5200__)
/* %/ inserts REGISTER_PREFIX, %# inserts IMMEDIATE_PREFIX. */
#define umul_ppmm(xh, xl, a, b) \
__asm__ ("| Inlined umul_ppmm\n" \
" move%.l %2,%/d0\n" \
" move%.l %3,%/d1\n" \
" move%.l %/d0,%/d2\n" \
" swap %/d0\n" \
" move%.l %/d1,%/d3\n" \
" swap %/d1\n" \
" move%.w %/d2,%/d4\n" \
" mulu %/d3,%/d4\n" \
" mulu %/d1,%/d2\n" \
" mulu %/d0,%/d3\n" \
" mulu %/d0,%/d1\n" \
" move%.l %/d4,%/d0\n" \
" eor%.w %/d0,%/d0\n" \
" swap %/d0\n" \
" add%.l %/d0,%/d2\n" \
" add%.l %/d3,%/d2\n" \
" jcc 1f\n" \
" add%.l %#65536,%/d1\n" \
"1: swap %/d2\n" \
" moveq %#0,%/d0\n" \
" move%.w %/d2,%/d0\n" \
" move%.w %/d4,%/d2\n" \
" move%.l %/d2,%1\n" \
" add%.l %/d1,%/d0\n" \
" move%.l %/d0,%0" \
: "=g" ((USItype) (xh)), \
"=g" ((USItype) (xl)) \
: "g" ((USItype) (a)), \
"g" ((USItype) (b)) \
: "d0", "d1", "d2", "d3", "d4")
#define UMUL_TIME 100
#define UDIV_TIME 400
#endif /* not mcf5200 */
#endif /* not mc68020 */
 
/* The '020, '030, '040 and '060 have bitfield insns. */
#if defined (__mc68020__) || defined(mc68020) \
|| defined(__mc68030__) || defined(mc68030) \
|| defined(__mc68040__) || defined(mc68040) \
|| defined(__mc68060__) || defined(mc68060)
#define count_leading_zeros(count, x) \
__asm__ ("bfffo %1{%b2:%b2},%0" \
: "=d" ((USItype) (count)) \
: "od" ((USItype) (x)), "n" (0))
#endif
#endif /* mc68000 */
 
#if defined (__m88000__) && W_TYPE_SIZE == 32
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("addu.co %1,%r4,%r5\n\taddu.ci %0,%r2,%r3" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "%rJ" ((USItype) (ah)), \
"rJ" ((USItype) (bh)), \
"%rJ" ((USItype) (al)), \
"rJ" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subu.co %1,%r4,%r5\n\tsubu.ci %0,%r2,%r3" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "rJ" ((USItype) (ah)), \
"rJ" ((USItype) (bh)), \
"rJ" ((USItype) (al)), \
"rJ" ((USItype) (bl)))
#define count_leading_zeros(count, x) \
do { \
USItype __cbtmp; \
__asm__ ("ff1 %0,%1" \
: "=r" (__cbtmp) \
: "r" ((USItype) (x))); \
(count) = __cbtmp ^ 31; \
} while (0)
#define COUNT_LEADING_ZEROS_0 63 /* sic */
#if defined (__mc88110__)
#define umul_ppmm(wh, wl, u, v) \
do { \
union {UDItype __ll; \
struct {USItype __h, __l;} __i; \
} __xx; \
__asm__ ("mulu.d %0,%1,%2" \
: "=r" (__xx.__ll) \
: "r" ((USItype) (u)), \
"r" ((USItype) (v))); \
(wh) = __xx.__i.__h; \
(wl) = __xx.__i.__l; \
} while (0)
#define udiv_qrnnd(q, r, n1, n0, d) \
({union {UDItype __ll; \
struct {USItype __h, __l;} __i; \
} __xx; \
USItype __q; \
__xx.__i.__h = (n1); __xx.__i.__l = (n0); \
__asm__ ("divu.d %0,%1,%2" \
: "=r" (__q) \
: "r" (__xx.__ll), \
"r" ((USItype) (d))); \
(r) = (n0) - __q * (d); (q) = __q; })
#define UMUL_TIME 5
#define UDIV_TIME 25
#else
#define UMUL_TIME 17
#define UDIV_TIME 150
#endif /* __mc88110__ */
#endif /* __m88000__ */
 
#if defined (__mips__) && W_TYPE_SIZE == 32
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("multu %2,%3" \
: "=l" ((USItype) (w0)), \
"=h" ((USItype) (w1)) \
: "d" ((USItype) (u)), \
"d" ((USItype) (v)))
#define UMUL_TIME 10
#define UDIV_TIME 100
#endif /* __mips__ */
 
#if defined (__ns32000__) && W_TYPE_SIZE == 32
#define umul_ppmm(w1, w0, u, v) \
({union {UDItype __ll; \
struct {USItype __l, __h;} __i; \
} __xx; \
__asm__ ("meid %2,%0" \
: "=g" (__xx.__ll) \
: "%0" ((USItype) (u)), \
"g" ((USItype) (v))); \
(w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
#define __umulsidi3(u, v) \
({UDItype __w; \
__asm__ ("meid %2,%0" \
: "=g" (__w) \
: "%0" ((USItype) (u)), \
"g" ((USItype) (v))); \
__w; })
#define udiv_qrnnd(q, r, n1, n0, d) \
({union {UDItype __ll; \
struct {USItype __l, __h;} __i; \
} __xx; \
__xx.__i.__h = (n1); __xx.__i.__l = (n0); \
__asm__ ("deid %2,%0" \
: "=g" (__xx.__ll) \
: "0" (__xx.__ll), \
"g" ((USItype) (d))); \
(r) = __xx.__i.__l; (q) = __xx.__i.__h; })
#define count_trailing_zeros(count,x) \
do { \
__asm__ ("ffsd %2,%0" \
: "=r" ((USItype) (count)) \
: "0" ((USItype) 0), \
"r" ((USItype) (x))); \
} while (0)
#endif /* __ns32000__ */
 
/* FIXME: We should test _IBMR2 here when we add assembly support for the
system vendor compilers.
FIXME: What's needed for gcc PowerPC VxWorks? __vxworks__ is not good
enough, since that hits ARM and m68k too. */
#if (defined (_ARCH_PPC) /* AIX */ \
|| defined (_ARCH_PWR) /* AIX */ \
|| defined (_ARCH_COM) /* AIX */ \
|| defined (__powerpc__) /* gcc */ \
|| defined (__POWERPC__) /* BEOS */ \
|| defined (__ppc__) /* Darwin */ \
|| defined (PPC) /* GNU/Linux, SysV */ \
) && W_TYPE_SIZE == 32
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
do { \
if (__builtin_constant_p (bh) && (bh) == 0) \
__asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \
: "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\
else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \
__asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \
: "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\
else \
__asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \
: "=r" (sh), "=&r" (sl) \
: "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \
} while (0)
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
do { \
if (__builtin_constant_p (ah) && (ah) == 0) \
__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \
: "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\
else if (__builtin_constant_p (ah) && (ah) == ~(USItype) 0) \
__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \
: "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\
else if (__builtin_constant_p (bh) && (bh) == 0) \
__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \
: "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\
else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \
__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \
: "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\
else \
__asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \
: "=r" (sh), "=&r" (sl) \
: "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \
} while (0)
#define count_leading_zeros(count, x) \
__asm__ ("{cntlz|cntlzw} %0,%1" : "=r" (count) : "r" (x))
#define COUNT_LEADING_ZEROS_0 32
#if defined (_ARCH_PPC) || defined (__powerpc__) || defined (__POWERPC__) \
|| defined (__ppc__) || defined (PPC) || defined (__vxworks__)
#define umul_ppmm(ph, pl, m0, m1) \
do { \
USItype __m0 = (m0), __m1 = (m1); \
__asm__ ("mulhwu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \
(pl) = __m0 * __m1; \
} while (0)
#define UMUL_TIME 15
#define smul_ppmm(ph, pl, m0, m1) \
do { \
SItype __m0 = (m0), __m1 = (m1); \
__asm__ ("mulhw %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \
(pl) = __m0 * __m1; \
} while (0)
#define SMUL_TIME 14
#define UDIV_TIME 120
#elif defined (_ARCH_PWR)
#define UMUL_TIME 8
#define smul_ppmm(xh, xl, m0, m1) \
__asm__ ("mul %0,%2,%3" : "=r" (xh), "=q" (xl) : "r" (m0), "r" (m1))
#define SMUL_TIME 4
#define sdiv_qrnnd(q, r, nh, nl, d) \
__asm__ ("div %0,%2,%4" : "=r" (q), "=q" (r) : "r" (nh), "1" (nl), "r" (d))
#define UDIV_TIME 100
#endif
#endif /* 32-bit POWER architecture variants. */
 
/* We should test _IBMR2 here when we add assembly support for the system
vendor compilers. */
#if (defined (_ARCH_PPC64) || defined (__powerpc64__)) && W_TYPE_SIZE == 64
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
do { \
if (__builtin_constant_p (bh) && (bh) == 0) \
__asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \
: "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\
else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \
__asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \
: "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\
else \
__asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \
: "=r" (sh), "=&r" (sl) \
: "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \
} while (0)
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
do { \
if (__builtin_constant_p (ah) && (ah) == 0) \
__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \
: "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\
else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0) \
__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \
: "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\
else if (__builtin_constant_p (bh) && (bh) == 0) \
__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \
: "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\
else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \
__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \
: "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\
else \
__asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \
: "=r" (sh), "=&r" (sl) \
: "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \
} while (0)
#define count_leading_zeros(count, x) \
__asm__ ("cntlzd %0,%1" : "=r" (count) : "r" (x))
#define COUNT_LEADING_ZEROS_0 64
#define umul_ppmm(ph, pl, m0, m1) \
do { \
UDItype __m0 = (m0), __m1 = (m1); \
__asm__ ("mulhdu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \
(pl) = __m0 * __m1; \
} while (0)
#define UMUL_TIME 15
#define smul_ppmm(ph, pl, m0, m1) \
do { \
DItype __m0 = (m0), __m1 = (m1); \
__asm__ ("mulhd %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \
(pl) = __m0 * __m1; \
} while (0)
#define SMUL_TIME 14 /* ??? */
#define UDIV_TIME 120 /* ??? */
#endif /* 64-bit PowerPC. */
 
#if defined (__ibm032__) /* RT/ROMP */ && W_TYPE_SIZE == 32
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("a %1,%5\n\tae %0,%3" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "%0" ((USItype) (ah)), \
"r" ((USItype) (bh)), \
"%1" ((USItype) (al)), \
"r" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("s %1,%5\n\tse %0,%3" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "0" ((USItype) (ah)), \
"r" ((USItype) (bh)), \
"1" ((USItype) (al)), \
"r" ((USItype) (bl)))
#define umul_ppmm(ph, pl, m0, m1) \
do { \
USItype __m0 = (m0), __m1 = (m1); \
__asm__ ( \
"s r2,r2\n" \
" mts r10,%2\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" m r2,%3\n" \
" cas %0,r2,r0\n" \
" mfs r10,%1" \
: "=r" ((USItype) (ph)), \
"=r" ((USItype) (pl)) \
: "%r" (__m0), \
"r" (__m1) \
: "r2"); \
(ph) += ((((SItype) __m0 >> 31) & __m1) \
+ (((SItype) __m1 >> 31) & __m0)); \
} while (0)
#define UMUL_TIME 20
#define UDIV_TIME 200
#define count_leading_zeros(count, x) \
do { \
if ((x) >= 0x10000) \
__asm__ ("clz %0,%1" \
: "=r" ((USItype) (count)) \
: "r" ((USItype) (x) >> 16)); \
else \
{ \
__asm__ ("clz %0,%1" \
: "=r" ((USItype) (count)) \
: "r" ((USItype) (x))); \
(count) += 16; \
} \
} while (0)
#endif
 
#if defined (__sh2__) && W_TYPE_SIZE == 32
#define umul_ppmm(w1, w0, u, v) \
__asm__ ( \
"dmulu.l %2,%3\n\tsts macl,%1\n\tsts mach,%0" \
: "=r" ((USItype)(w1)), \
"=r" ((USItype)(w0)) \
: "r" ((USItype)(u)), \
"r" ((USItype)(v)) \
: "macl", "mach")
#define UMUL_TIME 5
#endif
 
#if defined (__SH5__) && __SHMEDIA__ && W_TYPE_SIZE == 32
#define __umulsidi3(u,v) ((UDItype)(USItype)u*(USItype)v)
#define count_leading_zeros(count, x) \
do \
{ \
UDItype x_ = (USItype)(x); \
SItype c_; \
\
__asm__ ("nsb %1, %0" : "=r" (c_) : "r" (x_)); \
(count) = c_ - 31; \
} \
while (0)
#define COUNT_LEADING_ZEROS_0 32
#endif
 
#if defined (__sparc__) && !defined (__arch64__) && !defined (__sparcv9) \
&& W_TYPE_SIZE == 32
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("addcc %r4,%5,%1\n\taddx %r2,%3,%0" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "%rJ" ((USItype) (ah)), \
"rI" ((USItype) (bh)), \
"%rJ" ((USItype) (al)), \
"rI" ((USItype) (bl)) \
__CLOBBER_CC)
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subcc %r4,%5,%1\n\tsubx %r2,%3,%0" \
: "=r" ((USItype) (sh)), \
"=&r" ((USItype) (sl)) \
: "rJ" ((USItype) (ah)), \
"rI" ((USItype) (bh)), \
"rJ" ((USItype) (al)), \
"rI" ((USItype) (bl)) \
__CLOBBER_CC)
#if defined (__sparc_v8__)
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("umul %2,%3,%1;rd %%y,%0" \
: "=r" ((USItype) (w1)), \
"=r" ((USItype) (w0)) \
: "r" ((USItype) (u)), \
"r" ((USItype) (v)))
#define udiv_qrnnd(__q, __r, __n1, __n0, __d) \
__asm__ ("mov %2,%%y;nop;nop;nop;udiv %3,%4,%0;umul %0,%4,%1;sub %3,%1,%1"\
: "=&r" ((USItype) (__q)), \
"=&r" ((USItype) (__r)) \
: "r" ((USItype) (__n1)), \
"r" ((USItype) (__n0)), \
"r" ((USItype) (__d)))
#else
#if defined (__sparclite__)
/* This has hardware multiply but not divide. It also has two additional
instructions scan (ffs from high bit) and divscc. */
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("umul %2,%3,%1;rd %%y,%0" \
: "=r" ((USItype) (w1)), \
"=r" ((USItype) (w0)) \
: "r" ((USItype) (u)), \
"r" ((USItype) (v)))
#define udiv_qrnnd(q, r, n1, n0, d) \
__asm__ ("! Inlined udiv_qrnnd\n" \
" wr %%g0,%2,%%y ! Not a delayed write for sparclite\n" \
" tst %%g0\n" \
" divscc %3,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%%g1\n" \
" divscc %%g1,%4,%0\n" \
" rd %%y,%1\n" \
" bl,a 1f\n" \
" add %1,%4,%1\n" \
"1: ! End of inline udiv_qrnnd" \
: "=r" ((USItype) (q)), \
"=r" ((USItype) (r)) \
: "r" ((USItype) (n1)), \
"r" ((USItype) (n0)), \
"rI" ((USItype) (d)) \
: "g1" __AND_CLOBBER_CC)
#define UDIV_TIME 37
#define count_leading_zeros(count, x) \
do { \
__asm__ ("scan %1,1,%0" \
: "=r" ((USItype) (count)) \
: "r" ((USItype) (x))); \
} while (0)
/* Early sparclites return 63 for an argument of 0, but they warn that future
implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0
undefined. */
#else
/* SPARC without integer multiplication and divide instructions.
(i.e. at least Sun4/20,40,60,65,75,110,260,280,330,360,380,470,490) */
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("! Inlined umul_ppmm\n" \
" wr %%g0,%2,%%y ! SPARC has 0-3 delay insn after a wr\n"\
" sra %3,31,%%o5 ! Don't move this insn\n" \
" and %2,%%o5,%%o5 ! Don't move this insn\n" \
" andcc %%g0,0,%%g1 ! Don't move this insn\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,%3,%%g1\n" \
" mulscc %%g1,0,%%g1\n" \
" add %%g1,%%o5,%0\n" \
" rd %%y,%1" \
: "=r" ((USItype) (w1)), \
"=r" ((USItype) (w0)) \
: "%rI" ((USItype) (u)), \
"r" ((USItype) (v)) \
: "g1", "o5" __AND_CLOBBER_CC)
#define UMUL_TIME 39 /* 39 instructions */
/* It's quite necessary to add this much assembler for the sparc.
The default udiv_qrnnd (in C) is more than 10 times slower! */
#define udiv_qrnnd(__q, __r, __n1, __n0, __d) \
__asm__ ("! Inlined udiv_qrnnd\n" \
" mov 32,%%g1\n" \
" subcc %1,%2,%%g0\n" \
"1: bcs 5f\n" \
" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \
" sub %1,%2,%1 ! this kills msb of n\n" \
" addx %1,%1,%1 ! so this can't give carry\n" \
" subcc %%g1,1,%%g1\n" \
"2: bne 1b\n" \
" subcc %1,%2,%%g0\n" \
" bcs 3f\n" \
" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \
" b 3f\n" \
" sub %1,%2,%1 ! this kills msb of n\n" \
"4: sub %1,%2,%1\n" \
"5: addxcc %1,%1,%1\n" \
" bcc 2b\n" \
" subcc %%g1,1,%%g1\n" \
"! Got carry from n. Subtract next step to cancel this carry.\n" \
" bne 4b\n" \
" addcc %0,%0,%0 ! shift n1n0 and a 0-bit in lsb\n" \
" sub %1,%2,%1\n" \
"3: xnor %0,0,%0\n" \
" ! End of inline udiv_qrnnd" \
: "=&r" ((USItype) (__q)), \
"=&r" ((USItype) (__r)) \
: "r" ((USItype) (__d)), \
"1" ((USItype) (__n1)), \
"0" ((USItype) (__n0)) : "g1" __AND_CLOBBER_CC)
#define UDIV_TIME (3+7*32) /* 7 instructions/iteration. 32 iterations. */
#endif /* __sparclite__ */
#endif /* __sparc_v8__ */
#endif /* sparc32 */
 
#if ((defined (__sparc__) && defined (__arch64__)) || defined (__sparcv9)) \
&& W_TYPE_SIZE == 64
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("addcc %r4,%5,%1\n\t" \
"add %r2,%3,%0\n\t" \
"bcs,a,pn %%xcc, 1f\n\t" \
"add %0, 1, %0\n" \
"1:" \
: "=r" ((UDItype)(sh)), \
"=&r" ((UDItype)(sl)) \
: "%rJ" ((UDItype)(ah)), \
"rI" ((UDItype)(bh)), \
"%rJ" ((UDItype)(al)), \
"rI" ((UDItype)(bl)) \
__CLOBBER_CC)
 
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subcc %r4,%5,%1\n\t" \
"sub %r2,%3,%0\n\t" \
"bcs,a,pn %%xcc, 1f\n\t" \
"sub %0, 1, %0\n\t" \
"1:" \
: "=r" ((UDItype)(sh)), \
"=&r" ((UDItype)(sl)) \
: "rJ" ((UDItype)(ah)), \
"rI" ((UDItype)(bh)), \
"rJ" ((UDItype)(al)), \
"rI" ((UDItype)(bl)) \
__CLOBBER_CC)
 
#define umul_ppmm(wh, wl, u, v) \
do { \
UDItype tmp1, tmp2, tmp3, tmp4; \
__asm__ __volatile__ ( \
"srl %7,0,%3\n\t" \
"mulx %3,%6,%1\n\t" \
"srlx %6,32,%2\n\t" \
"mulx %2,%3,%4\n\t" \
"sllx %4,32,%5\n\t" \
"srl %6,0,%3\n\t" \
"sub %1,%5,%5\n\t" \
"srlx %5,32,%5\n\t" \
"addcc %4,%5,%4\n\t" \
"srlx %7,32,%5\n\t" \
"mulx %3,%5,%3\n\t" \
"mulx %2,%5,%5\n\t" \
"sethi %%hi(0x80000000),%2\n\t" \
"addcc %4,%3,%4\n\t" \
"srlx %4,32,%4\n\t" \
"add %2,%2,%2\n\t" \
"movcc %%xcc,%%g0,%2\n\t" \
"addcc %5,%4,%5\n\t" \
"sllx %3,32,%3\n\t" \
"add %1,%3,%1\n\t" \
"add %5,%2,%0" \
: "=r" ((UDItype)(wh)), \
"=&r" ((UDItype)(wl)), \
"=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \
: "r" ((UDItype)(u)), \
"r" ((UDItype)(v)) \
__CLOBBER_CC); \
} while (0)
#define UMUL_TIME 96
#define UDIV_TIME 230
#endif /* sparc64 */
 
#if defined (__vax__) && W_TYPE_SIZE == 32
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("addl2 %5,%1\n\tadwc %3,%0" \
: "=g" ((USItype) (sh)), \
"=&g" ((USItype) (sl)) \
: "%0" ((USItype) (ah)), \
"g" ((USItype) (bh)), \
"%1" ((USItype) (al)), \
"g" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subl2 %5,%1\n\tsbwc %3,%0" \
: "=g" ((USItype) (sh)), \
"=&g" ((USItype) (sl)) \
: "0" ((USItype) (ah)), \
"g" ((USItype) (bh)), \
"1" ((USItype) (al)), \
"g" ((USItype) (bl)))
#define umul_ppmm(xh, xl, m0, m1) \
do { \
union { \
UDItype __ll; \
struct {USItype __l, __h;} __i; \
} __xx; \
USItype __m0 = (m0), __m1 = (m1); \
__asm__ ("emul %1,%2,$0,%0" \
: "=r" (__xx.__ll) \
: "g" (__m0), \
"g" (__m1)); \
(xh) = __xx.__i.__h; \
(xl) = __xx.__i.__l; \
(xh) += ((((SItype) __m0 >> 31) & __m1) \
+ (((SItype) __m1 >> 31) & __m0)); \
} while (0)
#define sdiv_qrnnd(q, r, n1, n0, d) \
do { \
union {DItype __ll; \
struct {SItype __l, __h;} __i; \
} __xx; \
__xx.__i.__h = n1; __xx.__i.__l = n0; \
__asm__ ("ediv %3,%2,%0,%1" \
: "=g" (q), "=g" (r) \
: "g" (__xx.__ll), "g" (d)); \
} while (0)
#endif /* __vax__ */
 
#if defined (__z8000__) && W_TYPE_SIZE == 16
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("add %H1,%H5\n\tadc %H0,%H3" \
: "=r" ((unsigned int)(sh)), \
"=&r" ((unsigned int)(sl)) \
: "%0" ((unsigned int)(ah)), \
"r" ((unsigned int)(bh)), \
"%1" ((unsigned int)(al)), \
"rQR" ((unsigned int)(bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("sub %H1,%H5\n\tsbc %H0,%H3" \
: "=r" ((unsigned int)(sh)), \
"=&r" ((unsigned int)(sl)) \
: "0" ((unsigned int)(ah)), \
"r" ((unsigned int)(bh)), \
"1" ((unsigned int)(al)), \
"rQR" ((unsigned int)(bl)))
#define umul_ppmm(xh, xl, m0, m1) \
do { \
union {long int __ll; \
struct {unsigned int __h, __l;} __i; \
} __xx; \
unsigned int __m0 = (m0), __m1 = (m1); \
__asm__ ("mult %S0,%H3" \
: "=r" (__xx.__i.__h), \
"=r" (__xx.__i.__l) \
: "%1" (__m0), \
"rQR" (__m1)); \
(xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
(xh) += ((((signed int) __m0 >> 15) & __m1) \
+ (((signed int) __m1 >> 15) & __m0)); \
} while (0)
#endif /* __z8000__ */
 
#endif /* __GNUC__ */
 
/* If this machine has no inline assembler, use C macros. */
 
#if !defined (add_ssaaaa)
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
do { \
UWtype __x; \
__x = (al) + (bl); \
(sh) = (ah) + (bh) + (__x < (al)); \
(sl) = __x; \
} while (0)
#endif
 
#if !defined (sub_ddmmss)
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
do { \
UWtype __x; \
__x = (al) - (bl); \
(sh) = (ah) - (bh) - (__x > (al)); \
(sl) = __x; \
} while (0)
#endif
 
#if !defined (umul_ppmm)
#define umul_ppmm(w1, w0, u, v) \
do { \
UWtype __x0, __x1, __x2, __x3; \
UHWtype __ul, __vl, __uh, __vh; \
\
__ul = __ll_lowpart (u); \
__uh = __ll_highpart (u); \
__vl = __ll_lowpart (v); \
__vh = __ll_highpart (v); \
\
__x0 = (UWtype) __ul * __vl; \
__x1 = (UWtype) __ul * __vh; \
__x2 = (UWtype) __uh * __vl; \
__x3 = (UWtype) __uh * __vh; \
\
__x1 += __ll_highpart (__x0);/* this can't give carry */ \
__x1 += __x2; /* but this indeed can */ \
if (__x1 < __x2) /* did we get it? */ \
__x3 += __ll_B; /* yes, add it in the proper pos. */ \
\
(w1) = __x3 + __ll_highpart (__x1); \
(w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \
} while (0)
#endif
 
#if !defined (__umulsidi3)
#define __umulsidi3(u, v) \
({DWunion __w; \
umul_ppmm (__w.s.high, __w.s.low, u, v); \
__w.ll; })
#endif
 
/* Define this unconditionally, so it can be used for debugging. */
#define __udiv_qrnnd_c(q, r, n1, n0, d) \
do { \
UWtype __d1, __d0, __q1, __q0; \
UWtype __r1, __r0, __m; \
__d1 = __ll_highpart (d); \
__d0 = __ll_lowpart (d); \
\
__r1 = (n1) % __d1; \
__q1 = (n1) / __d1; \
__m = (UWtype) __q1 * __d0; \
__r1 = __r1 * __ll_B | __ll_highpart (n0); \
if (__r1 < __m) \
{ \
__q1--, __r1 += (d); \
if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
if (__r1 < __m) \
__q1--, __r1 += (d); \
} \
__r1 -= __m; \
\
__r0 = __r1 % __d1; \
__q0 = __r1 / __d1; \
__m = (UWtype) __q0 * __d0; \
__r0 = __r0 * __ll_B | __ll_lowpart (n0); \
if (__r0 < __m) \
{ \
__q0--, __r0 += (d); \
if (__r0 >= (d)) \
if (__r0 < __m) \
__q0--, __r0 += (d); \
} \
__r0 -= __m; \
\
(q) = (UWtype) __q1 * __ll_B | __q0; \
(r) = __r0; \
} while (0)
 
/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through
__udiv_w_sdiv (defined in libgcc or elsewhere). */
#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd)
#define udiv_qrnnd(q, r, nh, nl, d) \
do { \
USItype __r; \
(q) = __udiv_w_sdiv (&__r, nh, nl, d); \
(r) = __r; \
} while (0)
#endif
 
/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */
#if !defined (udiv_qrnnd)
#define UDIV_NEEDS_NORMALIZATION 1
#define udiv_qrnnd __udiv_qrnnd_c
#endif
 
#if !defined (count_leading_zeros)
extern const UQItype __clz_tab[];
#define count_leading_zeros(count, x) \
do { \
UWtype __xr = (x); \
UWtype __a; \
\
if (W_TYPE_SIZE <= 32) \
{ \
__a = __xr < ((UWtype)1<<2*__BITS4) \
? (__xr < ((UWtype)1<<__BITS4) ? 0 : __BITS4) \
: (__xr < ((UWtype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \
} \
else \
{ \
for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \
if (((__xr >> __a) & 0xff) != 0) \
break; \
} \
\
(count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \
} while (0)
#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE
#endif
 
#if !defined (count_trailing_zeros)
/* Define count_trailing_zeros using count_leading_zeros. The latter might be
defined in asm, but if it is not, the C version above is good enough. */
#define count_trailing_zeros(count, x) \
do { \
UWtype __ctz_x = (x); \
UWtype __ctz_c; \
count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \
(count) = W_TYPE_SIZE - 1 - __ctz_c; \
} while (0)
#endif
 
#ifndef UDIV_NEEDS_NORMALIZATION
#define UDIV_NEEDS_NORMALIZATION 0
#endif
/programs/network/netsurf/netsurf/objs/make.all
0,0 → 1,32
OBJS = about.o base64.o bitmap_fbtk.o bitmap.o bmp.o box_construct.o \
box_normalise.o box.o browser.o caret_image.o challenge.o clipboard.o \
content-disposition.o content_factory.o content.o content-type.o \
cookies.o corestrings.o css.o curl.o data.o dirlist.o download.o \
dump.o event.o fbtk.o fetch.o filename.o file.o filepath.o filetype.o \
fill.o findfile.o font_freetype.o font.o form.o framebuffer.o frames.o \
generics.o gif.o gui.o hand_image.o hashtable.o history_core.o \
history_global_core.o history_image_g.o history_image.o hlcache.o \
hotlist.o html_forms.o html_interaction.o html.o html_redraw.o \
html_script.o ico.o image_cache.o imagemap.o image.o internal.o \
jpeg.o knockout.o layout.o left_arrow_g.o left_arrow.o libdom.o \
list.o llcache.o locale.o localhistory.o login.o log.o menu_image.o \
messages.o mimesniff.o misc.o mouse.o move_image.o netsurf.o none.o \
nsfont_bold.o nsfont_italic_bold.o nsfont_italic.o nsfont_regular.o \
nsurl.o options.o osk_image.o osk.o parameter.o plot_style.o png.o \
pointer_image.o primitives.o print.o progress_image.o reload_g.o \
reload.o resource.o right_arrow_g.o right_arrow.o save_complete.o \
save_text.o schedule.o scrollbar.o scrolld.o scrolll.o scroll.o \
scrollr.o scrollu.o search.o search_ren.o searchweb.o selection.o \
select.o sslcert.o stop_image_g.o stop_image.o system_colour.o \
table.o talloc.o textarea.o textinput.o textinput_r.o text.o \
textplain.o throbber0.o throbber1.o throbber2.o throbber3.o \
throbber4.o throbber5.o throbber6.o throbber7.o throbber8.o \
thumb_ddesk.o thumbnail.o tree_ddesk.o tree.o tree_url_node.o \
urldb.o url.o useragent.o user.o utf8.o utils.o utils_utils.o \
version.o window.o www-authenticate.o snprintf.o stubs.o divdi3.o
 
LIBS += -lm -lcurl -liconv -lnsbmp -lnsgif -lpng -ljpeg -lz -lnsfb -lSDL -lwapcaplet -lcss -ldom -lhubbub -lparserutils -lfreetype2
 
OUTFILE = _netsurf
 
include $(MENUETDEV)/makefiles/Makefile_for_program
/programs/network/netsurf/netsurf/objs/snprintf.c
0,0 → 1,1025
/*
* snprintf.c - a portable implementation of snprintf
*
* AUTHOR
* Mark Martinec <mark.martinec@ijs.si>, April 1999.
*
* Copyright 1999, Mark Martinec. All rights reserved.
*
* TERMS AND CONDITIONS
* This program is free software; you can redistribute it and/or modify
* it under the terms of the "Frontier Artistic License" which comes
* with this Kit.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Frontier Artistic License for more details.
*
* You should have received a copy of the Frontier Artistic License
* with this Kit in the file named LICENSE.txt .
* If not, I'll be glad to provide one.
*
* FEATURES
* - careful adherence to specs regarding flags, field width and precision;
* - good performance for large string handling (large format, large
* argument or large paddings). Performance is similar to system's sprintf
* and in several cases significantly better (make sure you compile with
* optimizations turned on, tell the compiler the code is strict ANSI
* if necessary to give it more freedom for optimizations);
* - return value semantics per ISO/IEC 9899:1999 ("ISO C99");
* - written in standard ISO/ANSI C - requires an ANSI C compiler.
*
* SUPPORTED CONVERSION SPECIFIERS AND DATA TYPES
*
* This snprintf only supports the following conversion specifiers:
* s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below)
* with flags: '-', '+', ' ', '0' and '#'.
* An asterisk is supported for field width as well as precision.
*
* Length modifiers 'h' (short int), 'l' (long int),
* and 'll' (long long int) are supported.
* NOTE:
* If macro SNPRINTF_LONGLONG_SUPPORT is not defined (default) the
* length modifier 'll' is recognized but treated the same as 'l',
* which may cause argument value truncation! Defining
* SNPRINTF_LONGLONG_SUPPORT requires that your system's sprintf also
* handles length modifier 'll'. long long int is a language extension
* which may not be portable.
*
* Conversion of numeric data (conversion specifiers d, u, o, x, X, p)
* with length modifiers (none or h, l, ll) is left to the system routine
* sprintf, but all handling of flags, field width and precision as well as
* c and s conversions is done very carefully by this portable routine.
* If a string precision (truncation) is specified (e.g. %.8s) it is
* guaranteed the string beyond the specified precision will not be referenced.
*
* Length modifiers h, l and ll are ignored for c and s conversions (data
* types wint_t and wchar_t are not supported).
*
* The following common synonyms for conversion characters are supported:
* - i is a synonym for d
* - D is a synonym for ld, explicit length modifiers are ignored
* - U is a synonym for lu, explicit length modifiers are ignored
* - O is a synonym for lo, explicit length modifiers are ignored
* The D, O and U conversion characters are nonstandard, they are supported
* for backward compatibility only, and should not be used for new code.
*
* The following is specifically NOT supported:
* - flag ' (thousands' grouping character) is recognized but ignored
* - numeric conversion specifiers: f, e, E, g, G and synonym F,
* as well as the new a and A conversion specifiers
* - length modifier 'L' (long double) and 'q' (quad - use 'll' instead)
* - wide character/string conversions: lc, ls, and nonstandard
* synonyms C and S
* - writeback of converted string length: conversion character n
* - the n$ specification for direct reference to n-th argument
* - locales
*
* It is permitted for str_m to be zero, and it is permitted to specify NULL
* pointer for resulting string argument if str_m is zero (as per ISO C99).
*
* The return value is the number of characters which would be generated
* for the given input, excluding the trailing null. If this value
* is greater or equal to str_m, not all characters from the result
* have been stored in str, output bytes beyond the (str_m-1) -th character
* are discarded. If str_m is greater than zero it is guaranteed
* the resulting string will be null-terminated.
*
* NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1,
* but is different from some older and vendor implementations,
* and is also different from XPG, XSH5, SUSv2 specifications.
* For historical discussion on changes in the semantics and standards
* of snprintf see printf(3) man page in the Linux programmers manual.
*
* Routines asprintf and vasprintf return a pointer (in the ptr argument)
* to a buffer sufficiently large to hold the resulting string. This pointer
* should be passed to free(3) to release the allocated storage when it is
* no longer needed. If sufficient space cannot be allocated, these functions
* will return -1 and set ptr to be a NULL pointer. These two routines are a
* GNU C library extensions (glibc).
*
* Routines asnprintf and vasnprintf are similar to asprintf and vasprintf,
* yet, like snprintf and vsnprintf counterparts, will write at most str_m-1
* characters into the allocated output string, the last character in the
* allocated buffer then gets the terminating null. If the formatted string
* length (the return value) is greater than or equal to the str_m argument,
* the resulting string was truncated and some of the formatted characters
* were discarded. These routines present a handy way to limit the amount
* of allocated memory to some sane value.
*
* AVAILABILITY
* http://www.ijs.si/software/snprintf/
*
* REVISION HISTORY
* 1999-04 V0.9 Mark Martinec
* - initial version, some modifications after comparing printf
* man pages for Digital Unix 4.0, Solaris 2.6 and HPUX 10,
* and checking how Perl handles sprintf (differently!);
* 1999-04-09 V1.0 Mark Martinec <mark.martinec@ijs.si>
* - added main test program, fixed remaining inconsistencies,
* added optional (long long int) support;
* 1999-04-12 V1.1 Mark Martinec <mark.martinec@ijs.si>
* - support the 'p' conversion (pointer to void);
* - if a string precision is specified
* make sure the string beyond the specified precision
* will not be referenced (e.g. by strlen);
* 1999-04-13 V1.2 Mark Martinec <mark.martinec@ijs.si>
* - support synonyms %D=%ld, %U=%lu, %O=%lo;
* - speed up the case of long format string with few conversions;
* 1999-06-30 V1.3 Mark Martinec <mark.martinec@ijs.si>
* - fixed runaway loop (eventually crashing when str_l wraps
* beyond 2^31) while copying format string without
* conversion specifiers to a buffer that is too short
* (thanks to Edwin Young <edwiny@autonomy.com> for
* spotting the problem);
* - added macros PORTABLE_SNPRINTF_VERSION_(MAJOR|MINOR)
* to snprintf.h
* 2000-02-14 V2.0 (never released) Mark Martinec <mark.martinec@ijs.si>
* - relaxed license terms: The Artistic License now applies.
* You may still apply the GNU GENERAL PUBLIC LICENSE
* as was distributed with previous versions, if you prefer;
* - changed REVISION HISTORY dates to use ISO 8601 date format;
* - added vsnprintf (patch also independently proposed by
* Caolan McNamara 2000-05-04, and Keith M Willenson 2000-06-01)
* 2000-06-27 V2.1 Mark Martinec <mark.martinec@ijs.si>
* - removed POSIX check for str_m<1; value 0 for str_m is
* allowed by ISO C99 (and GNU C library 2.1) - (pointed out
* on 2000-05-04 by Caolan McNamara, caolan@ csn dot ul dot ie).
* Besides relaxed license this change in standards adherence
* is the main reason to bump up the major version number;
* - added nonstandard routines asnprintf, vasnprintf, asprintf,
* vasprintf that dynamically allocate storage for the
* resulting string; these routines are not compiled by default,
* see comments where NEED_V?ASN?PRINTF macros are defined;
* - autoconf contributed by Caolan McNamara
* 2000-10-06 V2.2 Mark Martinec <mark.martinec@ijs.si>
* - BUG FIX: the %c conversion used a temporary variable
* that was no longer in scope when referenced,
* possibly causing incorrect resulting character;
* - BUG FIX: make precision and minimal field width unsigned
* to handle huge values (2^31 <= n < 2^32) correctly;
* also be more careful in the use of signed/unsigned/size_t
* internal variables - probably more careful than many
* vendor implementations, but there may still be a case
* where huge values of str_m, precision or minimal field
* could cause incorrect behaviour;
* - use separate variables for signed/unsigned arguments,
* and for short/int, long, and long long argument lengths
* to avoid possible incompatibilities on certain
* computer architectures. Also use separate variable
* arg_sign to hold sign of a numeric argument,
* to make code more transparent;
* - some fiddling with zero padding and "0x" to make it
* Linux compatible;
* - systematically use macros fast_memcpy and fast_memset
* instead of case-by-case hand optimization; determine some
* breakeven string lengths for different architectures;
* - terminology change: 'format' -> 'conversion specifier',
* 'C9x' -> 'ISO/IEC 9899:1999 ("ISO C99")',
* 'alternative form' -> 'alternate form',
* 'data type modifier' -> 'length modifier';
* - several comments rephrased and new ones added;
* - make compiler not complain about 'credits' defined but
* not used;
*/
 
 
/* Define HAVE_SNPRINTF if your system already has snprintf and vsnprintf.
*
* If HAVE_SNPRINTF is defined this module will not produce code for
* snprintf and vsnprintf, unless PREFER_PORTABLE_SNPRINTF is defined as well,
* causing this portable version of snprintf to be called portable_snprintf
* (and portable_vsnprintf).
*/
/* #define HAVE_SNPRINTF */
 
/* Define PREFER_PORTABLE_SNPRINTF if your system does have snprintf and
* vsnprintf but you would prefer to use the portable routine(s) instead.
* In this case the portable routine is declared as portable_snprintf
* (and portable_vsnprintf) and a macro 'snprintf' (and 'vsnprintf')
* is defined to expand to 'portable_v?snprintf' - see file snprintf.h .
* Defining this macro is only useful if HAVE_SNPRINTF is also defined,
* but does does no harm if defined nevertheless.
*/
/* #define PREFER_PORTABLE_SNPRINTF */
 
/* Define SNPRINTF_LONGLONG_SUPPORT if you want to support
* data type (long long int) and length modifier 'll' (e.g. %lld).
* If undefined, 'll' is recognized but treated as a single 'l'.
*
* If the system's sprintf does not handle 'll'
* the SNPRINTF_LONGLONG_SUPPORT must not be defined!
*
* This is off by default as (long long int) is a language extension.
*/
/* #define SNPRINTF_LONGLONG_SUPPORT */
 
/* Define NEED_SNPRINTF_ONLY if you only need snprintf, and not vsnprintf.
* If NEED_SNPRINTF_ONLY is defined, the snprintf will be defined directly,
* otherwise both snprintf and vsnprintf routines will be defined
* and snprintf will be a simple wrapper around vsnprintf, at the expense
* of an extra procedure call.
*/
/* #define NEED_SNPRINTF_ONLY */
 
/* Define NEED_V?ASN?PRINTF macros if you need library extension
* routines asprintf, vasprintf, asnprintf, vasnprintf respectively,
* and your system library does not provide them. They are all small
* wrapper routines around portable_vsnprintf. Defining any of the four
* NEED_V?ASN?PRINTF macros automatically turns off NEED_SNPRINTF_ONLY
* and turns on PREFER_PORTABLE_SNPRINTF.
*
* Watch for name conflicts with the system library if these routines
* are already present there.
*
* NOTE: vasprintf and vasnprintf routines need va_copy() from stdarg.h, as
* specified by C99, to be able to traverse the same list of arguments twice.
* I don't know of any other standard and portable way of achieving the same.
* With some versions of gcc you may use __va_copy(). You might even get away
* with "ap2 = ap", in this case you must not call va_end(ap2) !
* #define va_copy(ap2,ap) ap2 = ap
*/
/* #define NEED_ASPRINTF */
/* #define NEED_ASNPRINTF */
/* #define NEED_VASPRINTF */
/* #define NEED_VASNPRINTF */
 
 
/* Define the following macros if desired:
* SOLARIS_COMPATIBLE, SOLARIS_BUG_COMPATIBLE,
* HPUX_COMPATIBLE, HPUX_BUG_COMPATIBLE, LINUX_COMPATIBLE,
* DIGITAL_UNIX_COMPATIBLE, DIGITAL_UNIX_BUG_COMPATIBLE,
* PERL_COMPATIBLE, PERL_BUG_COMPATIBLE,
*
* - For portable applications it is best not to rely on peculiarities
* of a given implementation so it may be best not to define any
* of the macros that select compatibility and to avoid features
* that vary among the systems.
*
* - Selecting compatibility with more than one operating system
* is not strictly forbidden but is not recommended.
*
* - 'x'_BUG_COMPATIBLE implies 'x'_COMPATIBLE .
*
* - 'x'_COMPATIBLE refers to (and enables) a behaviour that is
* documented in a sprintf man page on a given operating system
* and actually adhered to by the system's sprintf (but not on
* most other operating systems). It may also refer to and enable
* a behaviour that is declared 'undefined' or 'implementation specific'
* in the man page but a given implementation behaves predictably
* in a certain way.
*
* - 'x'_BUG_COMPATIBLE refers to (and enables) a behaviour of system's sprintf
* that contradicts the sprintf man page on the same operating system.
*
* - I do not claim that the 'x'_COMPATIBLE and 'x'_BUG_COMPATIBLE
* conditionals take into account all idiosyncrasies of a particular
* implementation, there may be other incompatibilities.
*/
 
 
/* ============================================= */
/* NO USER SERVICABLE PARTS FOLLOWING THIS POINT */
/* ============================================= */
 
#define PORTABLE_SNPRINTF_VERSION_MAJOR 2
#define PORTABLE_SNPRINTF_VERSION_MINOR 2
 
#if defined(NEED_ASPRINTF) || defined(NEED_ASNPRINTF) || defined(NEED_VASPRINTF) || defined(NEED_VASNPRINTF)
# if defined(NEED_SNPRINTF_ONLY)
# undef NEED_SNPRINTF_ONLY
# endif
# if !defined(PREFER_PORTABLE_SNPRINTF)
# define PREFER_PORTABLE_SNPRINTF
# endif
#endif
 
#if defined(SOLARIS_BUG_COMPATIBLE) && !defined(SOLARIS_COMPATIBLE)
#define SOLARIS_COMPATIBLE
#endif
 
#if defined(HPUX_BUG_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
#define HPUX_COMPATIBLE
#endif
 
#if defined(DIGITAL_UNIX_BUG_COMPATIBLE) && !defined(DIGITAL_UNIX_COMPATIBLE)
#define DIGITAL_UNIX_COMPATIBLE
#endif
 
#if defined(PERL_BUG_COMPATIBLE) && !defined(PERL_COMPATIBLE)
#define PERL_COMPATIBLE
#endif
 
#if defined(LINUX_BUG_COMPATIBLE) && !defined(LINUX_COMPATIBLE)
#define LINUX_COMPATIBLE
#endif
 
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <errno.h>
 
#ifdef isdigit
#undef isdigit
#endif
#define isdigit(c) ((c) >= '0' && (c) <= '9')
 
/* For copying strings longer or equal to 'breakeven_point'
* it is more efficient to call memcpy() than to do it inline.
* The value depends mostly on the processor architecture,
* but also on the compiler and its optimization capabilities.
* The value is not critical, some small value greater than zero
* will be just fine if you don't care to squeeze every drop
* of performance out of the code.
*
* Small values favor memcpy, large values favor inline code.
*/
#if defined(__alpha__) || defined(__alpha)
# define breakeven_point 2 /* AXP (DEC Alpha) - gcc or cc or egcs */
#endif
#if defined(__i386__) || defined(__i386)
# define breakeven_point 12 /* Intel Pentium/Linux - gcc 2.96 */
#endif
#if defined(__hppa)
# define breakeven_point 10 /* HP-PA - gcc */
#endif
#if defined(__sparc__) || defined(__sparc)
# define breakeven_point 33 /* Sun Sparc 5 - gcc 2.8.1 */
#endif
 
/* some other values of possible interest: */
/* #define breakeven_point 8 */ /* VAX 4000 - vaxc */
/* #define breakeven_point 19 */ /* VAX 4000 - gcc 2.7.0 */
 
#ifndef breakeven_point
# define breakeven_point 6 /* some reasonable one-size-fits-all value */
#endif
 
#define fast_memcpy(d,s,n) \
{ register size_t nn = (size_t)(n); \
if (nn >= breakeven_point) memcpy((d), (s), nn); \
else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
register char *dd; register const char *ss; \
for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } }
 
#define fast_memset(d,c,n) \
{ register size_t nn = (size_t)(n); \
if (nn >= breakeven_point) memset((d), (int)(c), nn); \
else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
register char *dd; register const int cc=(int)(c); \
for (dd=(d); nn>0; nn--) *dd++ = cc; } }
 
/* prototypes */
 
#if defined(NEED_ASPRINTF)
int asprintf (char **ptr, const char *fmt, /*args*/ ...);
#endif
#if defined(NEED_VASPRINTF)
int vasprintf (char **ptr, const char *fmt, va_list ap);
#endif
#if defined(NEED_ASNPRINTF)
int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...);
#endif
#if defined(NEED_VASNPRINTF)
int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap);
#endif
 
#if defined(HAVE_SNPRINTF)
/* declare our portable snprintf routine under name portable_snprintf */
/* declare our portable vsnprintf routine under name portable_vsnprintf */
#else
/* declare our portable routines under names snprintf and vsnprintf */
#define portable_snprintf snprintf
#if !defined(NEED_SNPRINTF_ONLY)
#define portable_vsnprintf vsnprintf
#endif
#endif
 
#if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)
int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...);
#if !defined(NEED_SNPRINTF_ONLY)
int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap);
#endif
#endif
 
/* declarations */
 
static char credits[] = "\n\
@(#)snprintf.c, v2.2: Mark Martinec, <mark.martinec@ijs.si>\n\
@(#)snprintf.c, v2.2: Copyright 1999, Mark Martinec. Frontier Artistic License applies.\n\
@(#)snprintf.c, v2.2: http://www.ijs.si/software/snprintf/\n";
 
#if defined(NEED_ASPRINTF)
int asprintf(char **ptr, const char *fmt, /*args*/ ...) {
va_list ap;
size_t str_m;
int str_l;
 
*ptr = NULL;
va_start(ap, fmt); /* measure the required size */
str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap);
va_end(ap);
assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */
*ptr = (char *) malloc(str_m = (size_t)str_l + 1);
if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
else {
int str_l2;
va_start(ap, fmt);
str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
va_end(ap);
assert(str_l2 == str_l);
}
return str_l;
}
#endif
 
#if defined(NEED_VASPRINTF)
int vasprintf(char **ptr, const char *fmt, va_list ap) {
size_t str_m;
int str_l;
 
*ptr = NULL;
{ va_list ap2;
va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */
str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
va_end(ap2);
}
assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */
*ptr = (char *) malloc(str_m = (size_t)str_l + 1);
if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
else {
int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
assert(str_l2 == str_l);
}
return str_l;
}
#endif
 
#if defined(NEED_ASNPRINTF)
int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...) {
va_list ap;
int str_l;
 
*ptr = NULL;
va_start(ap, fmt); /* measure the required size */
str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap);
va_end(ap);
assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */
if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */
/* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
if (str_m == 0) { /* not interested in resulting string, just return size */
} else {
*ptr = (char *) malloc(str_m);
if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
else {
int str_l2;
va_start(ap, fmt);
str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
va_end(ap);
assert(str_l2 == str_l);
}
}
return str_l;
}
#endif
 
#if defined(NEED_VASNPRINTF)
int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) {
int str_l;
 
*ptr = NULL;
{ va_list ap2;
va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */
str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
va_end(ap2);
}
assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */
if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */
/* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
if (str_m == 0) { /* not interested in resulting string, just return size */
} else {
*ptr = (char *) malloc(str_m);
if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
else {
int str_l2 = portable_vsnprintf(*ptr, str_m, fmt, ap);
assert(str_l2 == str_l);
}
}
return str_l;
}
#endif
 
/*
* If the system does have snprintf and the portable routine is not
* specifically required, this module produces no code for snprintf/vsnprintf.
*/
#if !defined(HAVE_SNPRINTF) || defined(PREFER_PORTABLE_SNPRINTF)
 
#if !defined(NEED_SNPRINTF_ONLY)
int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) {
va_list ap;
int str_l;
 
va_start(ap, fmt);
str_l = portable_vsnprintf(str, str_m, fmt, ap);
va_end(ap);
return str_l;
}
#endif
 
#if defined(NEED_SNPRINTF_ONLY)
int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...) {
#else
int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
#endif
 
#if defined(NEED_SNPRINTF_ONLY)
va_list ap;
#endif
size_t str_l = 0;
const char *p = fmt;
 
/* In contrast with POSIX, the ISO C99 now says
* that str can be NULL and str_m can be 0.
* This is more useful than the old: if (str_m < 1) return -1; */
 
#if defined(NEED_SNPRINTF_ONLY)
va_start(ap, fmt);
#endif
if (!p) p = "";
while (*p) {
if (*p != '%') {
/* if (str_l < str_m) str[str_l++] = *p++; -- this would be sufficient */
/* but the following code achieves better performance for cases
* where format string is long and contains few conversions */
const char *q = strchr(p+1,'%');
size_t n = !q ? strlen(p) : (q-p);
if (str_l < str_m) {
size_t avail = str_m-str_l;
fast_memcpy(str+str_l, p, (n>avail?avail:n));
}
p += n; str_l += n;
} else {
const char *starting_p;
size_t min_field_width = 0, precision = 0;
int zero_padding = 0, precision_specified = 0, justify_left = 0;
int alternate_form = 0, force_sign = 0;
int space_for_positive = 1; /* If both the ' ' and '+' flags appear,
the ' ' flag should be ignored. */
char length_modifier = '\0'; /* allowed values: \0, h, l, L */
char tmp[32];/* temporary buffer for simple numeric->string conversion */
 
const char *str_arg; /* string address in case of string argument */
size_t str_arg_l; /* natural field width of arg without padding
and sign */
unsigned char uchar_arg;
/* unsigned char argument value - only defined for c conversion.
N.B. standard explicitly states the char argument for
the c conversion is unsigned */
 
size_t number_of_zeros_to_pad = 0;
/* number of zeros to be inserted for numeric conversions
as required by the precision or minimal field width */
 
size_t zero_padding_insertion_ind = 0;
/* index into tmp where zero padding is to be inserted */
 
char fmt_spec = '\0';
/* current conversion specifier character */
 
str_arg = credits;/* just to make compiler happy (defined but not used)*/
str_arg = NULL;
starting_p = p; p++; /* skip '%' */
/* parse flags */
while (*p == '0' || *p == '-' || *p == '+' ||
*p == ' ' || *p == '#' || *p == '\'') {
switch (*p) {
case '0': zero_padding = 1; break;
case '-': justify_left = 1; break;
case '+': force_sign = 1; space_for_positive = 0; break;
case ' ': force_sign = 1;
/* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */
#ifdef PERL_COMPATIBLE
/* ... but in Perl the last of ' ' and '+' applies */
space_for_positive = 1;
#endif
break;
case '#': alternate_form = 1; break;
case '\'': break;
}
p++;
}
/* If the '0' and '-' flags both appear, the '0' flag should be ignored. */
 
/* parse field width */
if (*p == '*') {
int j;
p++; j = va_arg(ap, int);
if (j >= 0) min_field_width = j;
else { min_field_width = -j; justify_left = 1; }
} else if (isdigit((int)(*p))) {
/* size_t could be wider than unsigned int;
make sure we treat argument like common implementations do */
unsigned int uj = *p++ - '0';
while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
min_field_width = uj;
}
/* parse precision */
if (*p == '.') {
p++; precision_specified = 1;
if (*p == '*') {
int j = va_arg(ap, int);
p++;
if (j >= 0) precision = j;
else {
precision_specified = 0; precision = 0;
/* NOTE:
* Solaris 2.6 man page claims that in this case the precision
* should be set to 0. Digital Unix 4.0, HPUX 10 and BSD man page
* claim that this case should be treated as unspecified precision,
* which is what we do here.
*/
}
} else if (isdigit((int)(*p))) {
/* size_t could be wider than unsigned int;
make sure we treat argument like common implementations do */
unsigned int uj = *p++ - '0';
while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
precision = uj;
}
}
/* parse 'h', 'l' and 'll' length modifiers */
if (*p == 'h' || *p == 'l') {
length_modifier = *p; p++;
if (length_modifier == 'l' && *p == 'l') { /* double l = long long */
#ifdef SNPRINTF_LONGLONG_SUPPORT
length_modifier = '2'; /* double l encoded as '2' */
#else
length_modifier = 'l'; /* treat it as a single 'l' */
#endif
p++;
}
}
fmt_spec = *p;
/* common synonyms: */
switch (fmt_spec) {
case 'i': fmt_spec = 'd'; break;
case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
default: break;
}
/* get parameter value, do initial processing */
switch (fmt_spec) {
case '%': /* % behaves similar to 's' regarding flags and field widths */
case 'c': /* c behaves similar to 's' regarding flags and field widths */
case 's':
length_modifier = '\0'; /* wint_t and wchar_t not supported */
/* the result of zero padding flag with non-numeric conversion specifier*/
/* is undefined. Solaris and HPUX 10 does zero padding in this case, */
/* Digital Unix and Linux does not. */
#if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
zero_padding = 0; /* turn zero padding off for string conversions */
#endif
str_arg_l = 1;
switch (fmt_spec) {
case '%':
str_arg = p; break;
case 'c': {
int j = va_arg(ap, int);
uchar_arg = (unsigned char) j; /* standard demands unsigned char */
str_arg = (const char *) &uchar_arg;
break;
}
case 's':
str_arg = va_arg(ap, const char *);
if (!str_arg) str_arg_l = 0;
/* make sure not to address string beyond the specified precision !!! */
else if (!precision_specified) str_arg_l = strlen(str_arg);
/* truncate string if necessary as requested by precision */
else if (precision == 0) str_arg_l = 0;
else {
/* memchr on HP does not like n > 2^31 !!! */
const char *q = memchr(str_arg, '\0',
precision <= 0x7fffffff ? precision : 0x7fffffff);
str_arg_l = !q ? precision : (q-str_arg);
}
break;
default: break;
}
break;
case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
/* NOTE: the u, o, x, X and p conversion specifiers imply
the value is unsigned; d implies a signed value */
 
int arg_sign = 0;
/* 0 if numeric argument is zero (or if pointer is NULL for 'p'),
+1 if greater than zero (or nonzero for unsigned arguments),
-1 if negative (unsigned argument is never negative) */
 
int int_arg = 0; unsigned int uint_arg = 0;
/* only defined for length modifier h, or for no length modifiers */
 
long int long_arg = 0; unsigned long int ulong_arg = 0;
/* only defined for length modifier l */
 
void *ptr_arg = NULL;
/* pointer argument value -only defined for p conversion */
 
#ifdef SNPRINTF_LONGLONG_SUPPORT
long long int long_long_arg = 0;
unsigned long long int ulong_long_arg = 0;
/* only defined for length modifier ll */
#endif
if (fmt_spec == 'p') {
/* HPUX 10: An l, h, ll or L before any other conversion character
* (other than d, i, u, o, x, or X) is ignored.
* Digital Unix:
* not specified, but seems to behave as HPUX does.
* Solaris: If an h, l, or L appears before any other conversion
* specifier (other than d, i, u, o, x, or X), the behavior
* is undefined. (Actually %hp converts only 16-bits of address
* and %llp treats address as 64-bit data which is incompatible
* with (void *) argument on a 32-bit system).
*/
#ifdef SOLARIS_COMPATIBLE
# ifdef SOLARIS_BUG_COMPATIBLE
/* keep length modifiers even if it represents 'll' */
# else
if (length_modifier == '2') length_modifier = '\0';
# endif
#else
length_modifier = '\0';
#endif
ptr_arg = va_arg(ap, void *);
if (ptr_arg != NULL) arg_sign = 1;
} else if (fmt_spec == 'd') { /* signed */
switch (length_modifier) {
case '\0':
case 'h':
/* It is non-portable to specify a second argument of char or short
* to va_arg, because arguments seen by the called function
* are not char or short. C converts char and short arguments
* to int before passing them to a function.
*/
int_arg = va_arg(ap, int);
if (int_arg > 0) arg_sign = 1;
else if (int_arg < 0) arg_sign = -1;
break;
case 'l':
long_arg = va_arg(ap, long int);
if (long_arg > 0) arg_sign = 1;
else if (long_arg < 0) arg_sign = -1;
break;
#ifdef SNPRINTF_LONGLONG_SUPPORT
case '2':
long_long_arg = va_arg(ap, long long int);
if (long_long_arg > 0) arg_sign = 1;
else if (long_long_arg < 0) arg_sign = -1;
break;
#endif
}
} else { /* unsigned */
switch (length_modifier) {
case '\0':
case 'h':
uint_arg = va_arg(ap, unsigned int);
if (uint_arg) arg_sign = 1;
break;
case 'l':
ulong_arg = va_arg(ap, unsigned long int);
if (ulong_arg) arg_sign = 1;
break;
#ifdef SNPRINTF_LONGLONG_SUPPORT
case '2':
ulong_long_arg = va_arg(ap, unsigned long long int);
if (ulong_long_arg) arg_sign = 1;
break;
#endif
}
}
str_arg = tmp; str_arg_l = 0;
/* NOTE:
* For d, i, u, o, x, and X conversions, if precision is specified,
* the '0' flag should be ignored. This is so with Solaris 2.6,
* Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
*/
#ifndef PERL_COMPATIBLE
if (precision_specified) zero_padding = 0;
#endif
if (fmt_spec == 'd') {
if (force_sign && arg_sign >= 0)
tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
/* leave negative numbers for sprintf to handle,
to avoid handling tricky cases like (short int)(-32768) */
#ifdef LINUX_COMPATIBLE
} else if (fmt_spec == 'p' && force_sign && arg_sign > 0) {
tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
#endif
} else if (alternate_form) {
if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') )
{ tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; }
/* alternate form should have no effect for p conversion, but ... */
#ifdef HPUX_COMPATIBLE
else if (fmt_spec == 'p'
/* HPUX 10: for an alternate form of p conversion,
* a nonzero result is prefixed by 0x. */
#ifndef HPUX_BUG_COMPATIBLE
/* Actually it uses 0x prefix even for a zero value. */
&& arg_sign != 0
#endif
) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; }
#endif
}
zero_padding_insertion_ind = str_arg_l;
if (!precision_specified) precision = 1; /* default precision is 1 */
if (precision == 0 && arg_sign == 0
#if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE)
&& fmt_spec != 'p'
/* HPUX 10 man page claims: With conversion character p the result of
* converting a zero value with a precision of zero is a null string.
* Actually HP returns all zeroes, and Linux returns "(nil)". */
#endif
) {
/* converted to null string */
/* When zero value is formatted with an explicit precision 0,
the resulting formatted string is empty (d, i, u, o, x, X, p). */
} else {
char f[5]; int f_l = 0;
f[f_l++] = '%'; /* construct a simple format string for sprintf */
if (!length_modifier) { }
else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; }
else f[f_l++] = length_modifier;
f[f_l++] = fmt_spec; f[f_l++] = '\0';
if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg);
else if (fmt_spec == 'd') { /* signed */
switch (length_modifier) {
case '\0':
case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg); break;
case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break;
#ifdef SNPRINTF_LONGLONG_SUPPORT
case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break;
#endif
}
} else { /* unsigned */
switch (length_modifier) {
case '\0':
case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg); break;
case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break;
#ifdef SNPRINTF_LONGLONG_SUPPORT
case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg);break;
#endif
}
}
/* include the optional minus sign and possible "0x"
in the region before the zero padding insertion point */
if (zero_padding_insertion_ind < str_arg_l &&
tmp[zero_padding_insertion_ind] == '-') {
zero_padding_insertion_ind++;
}
if (zero_padding_insertion_ind+1 < str_arg_l &&
tmp[zero_padding_insertion_ind] == '0' &&
(tmp[zero_padding_insertion_ind+1] == 'x' ||
tmp[zero_padding_insertion_ind+1] == 'X') ) {
zero_padding_insertion_ind += 2;
}
}
{ size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
if (alternate_form && fmt_spec == 'o'
#ifdef HPUX_COMPATIBLE /* ("%#.o",0) -> "" */
&& (str_arg_l > 0)
#endif
#ifdef DIGITAL_UNIX_BUG_COMPATIBLE /* ("%#o",0) -> "00" */
#else
/* unless zero is already the first character */
&& !(zero_padding_insertion_ind < str_arg_l
&& tmp[zero_padding_insertion_ind] == '0')
#endif
) { /* assure leading zero for alternate-form octal numbers */
if (!precision_specified || precision < num_of_digits+1) {
/* precision is increased to force the first character to be zero,
except if a zero value is formatted with an explicit precision
of zero */
precision = num_of_digits+1; precision_specified = 1;
}
}
/* zero padding to specified precision? */
if (num_of_digits < precision)
number_of_zeros_to_pad = precision - num_of_digits;
}
/* zero padding to specified minimal field width? */
if (!justify_left && zero_padding) {
int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
if (n > 0) number_of_zeros_to_pad += n;
}
break;
}
default: /* unrecognized conversion specifier, keep format string as-is*/
zero_padding = 0; /* turn zero padding off for non-numeric convers. */
#ifndef DIGITAL_UNIX_COMPATIBLE
justify_left = 1; min_field_width = 0; /* reset flags */
#endif
#if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE)
/* keep the entire format string unchanged */
str_arg = starting_p; str_arg_l = p - starting_p;
/* well, not exactly so for Linux, which does something inbetween,
* and I don't feel an urge to imitate it: "%+++++hy" -> "%+y" */
#else
/* discard the unrecognized conversion, just keep *
* the unrecognized conversion character */
str_arg = p; str_arg_l = 0;
#endif
if (*p) str_arg_l++; /* include invalid conversion specifier unchanged
if not at end-of-string */
break;
}
if (*p) p++; /* step over the just processed conversion specifier */
/* insert padding to the left as requested by min_field_width;
this does not include the zero padding in case of numerical conversions*/
if (!justify_left) { /* left padding with blank or zero */
int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
if (n > 0) {
if (str_l < str_m) {
size_t avail = str_m-str_l;
fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n));
}
str_l += n;
}
}
/* zero padding as requested by the precision or by the minimal field width
* for numeric conversions required? */
if (number_of_zeros_to_pad <= 0) {
/* will not copy first part of numeric right now, *
* force it to be copied later in its entirety */
zero_padding_insertion_ind = 0;
} else {
/* insert first part of numerics (sign or '0x') before zero padding */
int n = zero_padding_insertion_ind;
if (n > 0) {
if (str_l < str_m) {
size_t avail = str_m-str_l;
fast_memcpy(str+str_l, str_arg, (n>avail?avail:n));
}
str_l += n;
}
/* insert zero padding as requested by the precision or min field width */
n = number_of_zeros_to_pad;
if (n > 0) {
if (str_l < str_m) {
size_t avail = str_m-str_l;
fast_memset(str+str_l, '0', (n>avail?avail:n));
}
str_l += n;
}
}
/* insert formatted string
* (or as-is conversion specifier for unknown conversions) */
{ int n = str_arg_l - zero_padding_insertion_ind;
if (n > 0) {
if (str_l < str_m) {
size_t avail = str_m-str_l;
fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind,
(n>avail?avail:n));
}
str_l += n;
}
}
/* insert right padding */
if (justify_left) { /* right blank padding to the field width */
int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
if (n > 0) {
if (str_l < str_m) {
size_t avail = str_m-str_l;
fast_memset(str+str_l, ' ', (n>avail?avail:n));
}
str_l += n;
}
}
}
}
#if defined(NEED_SNPRINTF_ONLY)
va_end(ap);
#endif
if (str_m > 0) { /* make sure the string is null-terminated
even at the expense of overwriting the last character
(shouldn't happen, but just in case) */
str[str_l <= str_m-1 ? str_l : str_m-1] = '\0';
}
/* Return the number of characters formatted (excluding trailing null
* character), that is, the number of characters that would have been
* written to the buffer if it were large enough.
*
* The value of str_l should be returned, but str_l is of unsigned type
* size_t, and snprintf is int, possibly leading to an undetected
* integer overflow, resulting in a negative return value, which is illegal.
* Both XSH5 and ISO C99 (at least the draft) are silent on this issue.
* Should errno be set to EOVERFLOW and EOF returned in this case???
*/
return (int) str_l;
}
#endif
/programs/network/netsurf/netsurf/objs/snprintf.h
0,0 → 1,26
#ifndef _PORTABLE_SNPRINTF_H_
#define _PORTABLE_SNPRINTF_H_
 
#define PORTABLE_SNPRINTF_VERSION_MAJOR 2
#define PORTABLE_SNPRINTF_VERSION_MINOR 2
 
#ifdef HAVE_SNPRINTF
#include <stdio.h>
#else
extern int snprintf(char *, size_t, const char *, /*args*/ ...);
extern int vsnprintf(char *, size_t, const char *, va_list);
#endif
 
#if defined(HAVE_SNPRINTF) && defined(PREFER_PORTABLE_SNPRINTF)
extern int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...);
extern int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap);
#define snprintf portable_snprintf
#define vsnprintf portable_vsnprintf
#endif
 
extern int asprintf (char **ptr, const char *fmt, /*args*/ ...);
extern int vasprintf (char **ptr, const char *fmt, va_list ap);
extern int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...);
extern int vasnprintf(char **ptr, size_t str_m, const char *fmt, va_list ap);
 
#endif
/programs/network/netsurf/netsurf/objs/src
0,0 → 1,26
OBJS = about.o base64.o bitmap_fbtk.o bitmap.o bmp.o box_construct.o \
box_normalise.o box.o browser.o caret_image.o challenge.o clipboard.o \
content-disposition.o content_factory.o content.o content-type.o \
cookies.o corestrings.o css.o curl.o data.o dirlist.o download.o \
dump.o event.o fbtk.o fetch.o filename.o file.o filepath.o filetype.o \
fill.o findfile.o font_internal.o font.o form.o framebuffer.o frames.o \
generics.o gif.o gui.o hand_image.o hashtable.o history_core.o \
history_global_core.o history_image_g.o history_image.o hlcache.o \
hotlist.o html_forms.o html_interaction.o html.o html_redraw.o \
html_script.o ico.o image_cache.o imagemap.o image.o internal.o \
jpeg.o knockout.o layout.o left_arrow_g.o left_arrow.o libdom.o \
list.o llcache.o locale.o localhistory.o login.o log.o menu_image.o \
messages.o mimesniff.o misc.o mouse.o move_image.o netsurf.o none.o \
nsfont_bold.o nsfont_italic_bold.o nsfont_italic.o nsfont_regular.o \
nsurl.o options.o osk_image.o osk.o parameter.o plot_style.o png.o \
pointer_image.o primitives.o print.o progress_image.o reload_g.o \
reload.o resource.o right_arrow_g.o right_arrow.o save_complete.o \
save_text.o schedule.o scrollbar.o scrolld.o scrolll.o scroll.o \
scrollr.o scrollu.o search.o search_ren.o searchweb.o selection.o \
select.o sslcert.o stop_image_g.o stop_image.o system_colour.o \
table.o talloc.o textarea.o textinput.o textinput_r.o text.o \
textplain.o throbber0.o throbber1.o throbber2.o throbber3.o \
throbber4.o throbber5.o throbber6.o throbber7.o throbber8.o \
thumb_ddesk.o thumbnail.o tree_ddesk.o tree.o tree_url_node.o \
urldb.o url.o useragent.o user.o utf8.o utils.o utils_utils.o \
version.o window.o www-authenticate.o
/programs/network/netsurf/netsurf/objs/stubs.c
0,0 → 1,151
#include <menuet/os.h>
#include <math.h>
#include <time.h>
 
 
/*
long int __divdi3(long int a, long int b) {
//__menuet__debug_out("divdi3\n");
return 0;}
*/
 
/*
long long int __divdi3(long long int a, long long int b) {
__menuet__debug_out("divdi3\n");
return a/b;}
*/
 
 
char * locale_charset(){
__menuet__debug_out("Charset is US\n");
return "US-ASCII";}
 
float strtof(const char* str, char** endptr){
__menuet__debug_out("STRTOOOF\n");
return 0.0f;}
char *realpath(const char *path, char *resolved_path){
char zuup[1024];
int i;
char *zoo;
char *boo;
char n, s;
if (resolved_path==0) {
__menuet__debug_out("ResPath is null");
resolved_path=malloc(strlen(path)+1);
}
zoo=resolved_path;
boo=path;
memcpy(zoo,boo,strlen(boo));
zoo[strlen(boo)]=0;
for (i=0; i<strlen(boo); i++) {
n=*path;
path++;
s=*path;
if ((n=='/' && s!='/') || (n!='/') ) {
*resolved_path=n;
resolved_path++;
}
}
*resolved_path=0;
__menuet__debug_out("Real path is... \n");
sprintf (zuup, "A:%s\n", boo);
__menuet__debug_out(zuup);
sprintf (zuup, "B:%s\n", zoo);
__menuet__debug_out(zuup);
//memcpy(resolved_path, path, strlen(path));
return zoo;
}
 
#include <stdint.h>
#include <netinet/in.h>
 
int inet_aton(const char *cp, struct in_addr *inp){
__menuet__debug_out("No IP\n");
return 0;
}
 
#include <stdarg.h>
 
void va_copy(va_list dest, va_list src){ //WHAA
dest=src;
__menuet__debug_out("Some shit...\n");
}
 
 
 
void timeradd(struct timeval *a, struct timeval *b,
struct timeval *res){
(res)->tv_sec = (a)->tv_sec + (b)->tv_sec;
(res)->tv_usec = (a)->tv_usec + (b)->tv_usec;
if ((res)->tv_usec >= 1000000) {
(res)->tv_sec++;
(res)->tv_usec -= 1000000;
}
//__menuet__debug_out("Timeradd\n");
}
 
void timersub(struct timeval *a, struct timeval *b,
struct timeval *res){
res->tv_sec=a->tv_sec - b->tv_sec;
res->tv_usec=a->tv_usec - b->tv_usec;
if ((res)->tv_usec < 0) {
(res)->tv_sec--;
(res)->tv_usec += 1000000;
}
// __menuet__debug_out("Timersub\n");
}
 
 
int timerisset(struct timeval *tvp){
//__menuet__debug_out("Timer is set?\n");
return ((tvp)->tv_sec || (tvp)->tv_usec);
}
 
int timercmp(struct timeval *a, struct timeval *b, int z){
//__menuet__debug_out("Timercmp is a MACRO \n");
if (a->tv_sec > b->tv_sec) return 1; //was 1
return 0;}
 
int wctomb(char *s, int wchar){
__menuet__debug_out("wctomb\n");
return 0;}
int wcrtomb(char * s, int wc, int * ps){
__menuet__debug_out("wcrtomb\n");
return 0;
}
 
int mbrtowc(int * pwc, const char * s,
int n, int * ps){
__menuet__debug_out("mbrtowc\n");
return 0;}
 
int johab_hangul_decompose( const char * s){
__menuet__debug_out("hanguul?\n");
return 0;}
/programs/network/netsurf/netsurf/render/box.c
0,0 → 1,1116
/*
* Copyright 2005-2007 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Box tree manipulation (implementation).
*/
 
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <dom/dom.h>
#include "content/content_protected.h"
#include "content/hlcache.h"
#include "css/css.h"
#include "css/utils.h"
#include "css/dump.h"
#include "desktop/scrollbar.h"
#include "desktop/options.h"
#include "render/box.h"
#include "render/form.h"
#include "render/html_internal.h"
#include "utils/log.h"
#include "utils/talloc.h"
#include "utils/utils.h"
 
static bool box_contains_point(struct box *box, int x, int y, bool *physically);
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);
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);
 
#define box_is_float(box) (box->type == BOX_FLOAT_LEFT || \
box->type == BOX_FLOAT_RIGHT)
 
/**
* Allocator
*
* \param ptr Pointer to reallocate, or NULL for new allocation
* \param size Number of bytes requires
* \param pw Allocation context
* \return Pointer to allocated block, or NULL on failure
*/
void *box_style_alloc(void *ptr, size_t len, void *pw)
{
if (len == 0) {
free(ptr);
return NULL;
}
 
return realloc(ptr, len);
}
 
/**
* Destructor for box nodes which own styles
*
* \param b The box being destroyed.
* \return 0 to allow talloc to continue destroying the tree.
*/
static int box_talloc_destructor(struct box *b)
{
if ((b->flags & STYLE_OWNED) && b->style != NULL) {
css_computed_style_destroy(b->style);
b->style = NULL;
}
if (b->styles != NULL) {
css_select_results_destroy(b->styles);
b->styles = NULL;
}
 
if (b->href != NULL)
nsurl_unref(b->href);
 
if (b->id != NULL) {
lwc_string_unref(b->id);
}
 
if (b->node != NULL) {
dom_node_unref(b->node);
}
 
return 0;
}
 
/**
* Create a box tree node.
*
* \param styles selection results for the box, or NULL
* \param style computed style for the box (not copied), or 0
* \param style_owned whether style is owned by this box
* \param href href for the box (copied), or 0
* \param target target for the box (not copied), or 0
* \param title title for the box (not copied), or 0
* \param id id for the box (not copied), or 0
* \param context context for allocations
* \return allocated and initialised box, or 0 on memory exhaustion
*
* styles is always owned by the box, if it is set.
* style is only owned by the box in the case of implied boxes.
*/
 
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)
{
unsigned int i;
struct box *box;
 
box = talloc(context, struct box);
if (!box) {
return 0;
}
 
talloc_set_destructor(box, box_talloc_destructor);
 
box->type = BOX_INLINE;
box->flags = 0;
box->flags = style_owned ? (box->flags | STYLE_OWNED) : box->flags;
box->styles = styles;
box->style = style;
box->x = box->y = 0;
box->width = UNKNOWN_WIDTH;
box->height = 0;
box->descendant_x0 = box->descendant_y0 = 0;
box->descendant_x1 = box->descendant_y1 = 0;
for (i = 0; i != 4; i++)
box->margin[i] = box->padding[i] = box->border[i].width = 0;
box->scroll_x = box->scroll_y = NULL;
box->min_width = 0;
box->max_width = UNKNOWN_MAX_WIDTH;
box->byte_offset = 0;
box->text = NULL;
box->length = 0;
box->space = 0;
box->href = (href == NULL) ? NULL : nsurl_ref(href);
box->target = target;
box->title = title;
box->columns = 1;
box->rows = 1;
box->start_column = 0;
box->next = NULL;
box->prev = NULL;
box->children = NULL;
box->last = NULL;
box->parent = NULL;
box->inline_end = NULL;
box->float_children = NULL;
box->float_container = NULL;
box->next_float = NULL;
box->list_marker = NULL;
box->col = NULL;
box->gadget = NULL;
box->usemap = NULL;
box->id = id;
box->background = NULL;
box->object = NULL;
box->object_params = NULL;
box->iframe = NULL;
box->node = NULL;
 
return box;
}
 
/**
* Add a child to a box tree node.
*
* \param parent box giving birth
* \param child box to link as last child of parent
*/
 
void box_add_child(struct box *parent, struct box *child)
{
assert(parent);
assert(child);
 
if (parent->children != 0) { /* has children already */
parent->last->next = child;
child->prev = parent->last;
} else { /* this is the first child */
parent->children = child;
child->prev = 0;
}
 
parent->last = child;
child->parent = parent;
}
 
 
/**
* Insert a new box as a sibling to a box in a tree.
*
* \param box box already in tree
* \param new_box box to link into tree as next sibling
*/
 
void box_insert_sibling(struct box *box, struct box *new_box)
{
new_box->parent = box->parent;
new_box->prev = box;
new_box->next = box->next;
box->next = new_box;
if (new_box->next)
new_box->next->prev = new_box;
else if (new_box->parent)
new_box->parent->last = new_box;
}
 
 
/**
* Unlink a box from the box tree and then free it recursively.
*
* \param box box to unlink and free recursively.
*/
 
void box_unlink_and_free(struct box *box)
{
struct box *parent = box->parent;
struct box *next = box->next;
struct box *prev = box->prev;
 
if (parent) {
if (parent->children == box)
parent->children = next;
if (parent->last == box)
parent->last = next ? next : prev;
}
 
if (prev)
prev->next = next;
if (next)
next->prev = prev;
 
box_free(box);
}
 
 
/**
* Free a box tree recursively.
*
* \param box box to free recursively
*
* The box and all its children is freed.
*/
 
void box_free(struct box *box)
{
struct box *child, *next;
 
/* free children first */
for (child = box->children; child; child = next) {
next = child->next;
box_free(child);
}
 
/* last this box */
box_free_box(box);
}
 
 
/**
* Free the data in a single box structure.
*
* \param box box to free
*/
 
void box_free_box(struct box *box)
{
if (!(box->flags & CLONE)) {
if (box->gadget)
form_free_control(box->gadget);
if (box->scroll_x != NULL)
scrollbar_destroy(box->scroll_x);
if (box->scroll_y != NULL)
scrollbar_destroy(box->scroll_y);
if (box->styles != NULL)
css_select_results_destroy(box->styles);
}
 
talloc_free(box);
}
 
 
/**
* Find the absolute coordinates of a box.
*
* \param box the box to calculate coordinates of
* \param x updated to x coordinate
* \param y updated to y coordinate
*/
 
void box_coords(struct box *box, int *x, int *y)
{
*x = box->x;
*y = box->y;
while (box->parent) {
if (box_is_float(box)) {
do {
box = box->parent;
} while (!box->float_children);
} else
box = box->parent;
*x += box->x - scrollbar_get_offset(box->scroll_x);
*y += box->y - scrollbar_get_offset(box->scroll_y);
}
}
 
 
/**
* Find the bounds of a box.
*
* \param box the box to calculate bounds of
* \param r receives bounds
*/
 
void box_bounds(struct box *box, struct rect *r)
{
int width, height;
 
box_coords(box, &r->x0, &r->y0);
 
width = box->padding[LEFT] + box->width + box->padding[RIGHT];
height = box->padding[TOP] + box->height + box->padding[BOTTOM];
 
r->x1 = r->x0 + width;
r->y1 = r->y0 + height;
}
 
 
/**
* Find the boxes at a point.
*
* \param box box to search children of
* \param x point to find, in global document coordinates
* \param y point to find, in global document coordinates
* \param box_x position of box, in global document coordinates, updated
* to position of returned box, if any
* \param box_y position of box, in global document coordinates, updated
* to position of returned box, if any
* \return box at given point, or 0 if none found
*
* To find all the boxes in the hierarchy at a certain point, use code like
* this:
* \code
* struct box *box = top_of_document_to_search;
* int box_x = 0, box_y = 0;
*
* while ((box = box_at_point(box, x, y, &box_x, &box_y))) {
* // process box
* }
* \endcode
*/
 
struct box *box_at_point(struct box *box, const int x, const int y,
int *box_x, int *box_y)
{
int bx = *box_x, by = *box_y;
struct box *child, *sibling;
bool physically;
 
assert(box);
 
/* consider floats first, since they will often overlap other boxes */
for (child = box->float_children; child; child = child->next_float) {
if (box_contains_point(child, x - bx, y - by, &physically)) {
*box_x = bx + child->x -
scrollbar_get_offset(child->scroll_x);
*box_y = by + child->y -
scrollbar_get_offset(child->scroll_y);
 
if (physically)
return child;
else
return box_at_point(child, x, y, box_x, box_y);
}
}
 
non_float_children:
/* non-float children */
for (child = box->children; child; child = child->next) {
if (box_is_float(child))
continue;
if (box_contains_point(child, x - bx, y - by, &physically)) {
*box_x = bx + child->x -
scrollbar_get_offset(child->scroll_x);
*box_y = by + child->y -
scrollbar_get_offset(child->scroll_y);
 
if (physically)
return child;
else
return box_at_point(child, x, y, box_x, box_y);
}
}
 
/* marker boxes */
if (box->list_marker) {
if (box_contains_point(box->list_marker, x - bx, y - by,
&physically)) {
*box_x = bx + box->list_marker->x;
*box_y = by + box->list_marker->y;
return box->list_marker;
}
}
 
/* siblings and siblings of ancestors */
while (box) {
if (box_is_float(box)) {
bx -= box->x - scrollbar_get_offset(box->scroll_x);
by -= box->y - scrollbar_get_offset(box->scroll_y);
for (sibling = box->next_float; sibling;
sibling = sibling->next_float) {
if (box_contains_point(sibling,
x - bx, y - by, &physically)) {
*box_x = bx + sibling->x -
scrollbar_get_offset(
sibling->scroll_x);
*box_y = by + sibling->y -
scrollbar_get_offset(
sibling->scroll_y);
 
if (physically)
return sibling;
else
return box_at_point(sibling,
x, y,
box_x, box_y);
}
}
/* ascend to float's parent */
do {
box = box->parent;
} while (!box->float_children);
/* process non-float children of float's parent */
goto non_float_children;
 
} else {
bx -= box->x - scrollbar_get_offset(box->scroll_x);
by -= box->y - scrollbar_get_offset(box->scroll_y);
for (sibling = box->next; sibling;
sibling = sibling->next) {
if (box_is_float(sibling))
continue;
if (box_contains_point(sibling, x - bx, y - by,
&physically)) {
*box_x = bx + sibling->x -
scrollbar_get_offset(
sibling->scroll_x);
*box_y = by + sibling->y -
scrollbar_get_offset(
sibling->scroll_y);
 
if (physically)
return sibling;
else
return box_at_point(sibling,
x, y,
box_x, box_y);
}
}
box = box->parent;
}
}
 
return 0;
}
 
 
/**
* Determine if a point lies within a box.
*
* \param box box to consider
* \param x coordinate relative to box parent
* \param y coordinate relative to box parent
* \param physically if function returning true, physically is set true if
* point is within the box's physical dimensions and false
* if the point is not within the box's physical dimensions
* but is in the area defined by the box's descendants.
* if function returning false, physically is undefined.
* \return true if the point is within the box or a descendant box
*
* This is a helper function for box_at_point().
*/
 
bool box_contains_point(struct box *box, int x, int y, bool *physically)
{
css_computed_clip_rect css_rect;
 
if (box->style != NULL &&
css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE &&
css_computed_clip(box->style, &css_rect) ==
CSS_CLIP_RECT) {
/* We have an absolutly positioned box with a clip rect */
struct rect r = {
.x0 = box->x - box->border[LEFT].width,
.y0 = box->y - box->border[TOP].width,
.x1 = box->x + box->padding[LEFT] + box->width +
box->border[RIGHT].width +
box->padding[RIGHT],
.y1 = box->y + box->padding[TOP] + box->height +
box->border[BOTTOM].width +
box->padding[BOTTOM]
};
if (x >= r.x0 && x < r.x1 && y >= r.y0 && y < r.y1)
*physically = true;
else
*physically = false;
 
/* Adjust rect to css clip region */
if (css_rect.left_auto == false) {
r.x0 += FIXTOINT(nscss_len2px(
css_rect.left, css_rect.lunit,
box->style));
}
if (css_rect.top_auto == false) {
r.y0 += FIXTOINT(nscss_len2px(
css_rect.top, css_rect.tunit,
box->style));
}
if (css_rect.right_auto == false) {
r.x1 = box->x - box->border[LEFT].width +
FIXTOINT(nscss_len2px(
css_rect.right,
css_rect.runit,
box->style));
}
if (css_rect.bottom_auto == false) {
r.y1 = box->y - box->border[TOP].width +
FIXTOINT(nscss_len2px(
css_rect.bottom,
css_rect.bunit,
box->style));
}
 
/* Test if point is in clipped box */
if (x >= r.x0 && x < r.x1 && y >= r.y0 && y < r.y1) {
/* inside clip area */
return true;
}
 
/* Not inside clip area */
return false;
}
if (box->x <= x + box->border[LEFT].width &&
x < box->x + box->padding[LEFT] + box->width +
box->border[RIGHT].width + box->padding[RIGHT] &&
box->y <= y + box->border[TOP].width &&
y < box->y + box->padding[TOP] + box->height +
box->border[BOTTOM].width + box->padding[BOTTOM]) {
*physically = true;
return true;
}
if (box->list_marker && box->list_marker->x <= x +
box->list_marker->border[LEFT].width &&
x < box->list_marker->x +
box->list_marker->padding[LEFT] +
box->list_marker->width +
box->list_marker->border[RIGHT].width +
box->list_marker->padding[RIGHT] &&
box->list_marker->y <= y +
box->list_marker->border[TOP].width &&
y < box->list_marker->y +
box->list_marker->padding[TOP] +
box->list_marker->height +
box->list_marker->border[BOTTOM].width +
box->list_marker->padding[BOTTOM]) {
*physically = true;
return true;
}
if ((box->style && css_computed_overflow(box->style) ==
CSS_OVERFLOW_VISIBLE) || !box->style) {
if (box->x + box->descendant_x0 <= x &&
x < box->x + box->descendant_x1 &&
box->y + box->descendant_y0 <= y &&
y < box->y + box->descendant_y1) {
*physically = false;
return true;
}
}
return false;
}
 
 
/**
* Check whether box is nearer mouse coordinates than current nearest box
*
* \param box box to test
* \param bx position of box, in global document coordinates
* \param by position of box, in global document coordinates
* \param x mouse point, in global document coordinates
* \param y mouse point, in global document coordinates
* \param dir direction in which to search (-1 = above-left,
* +1 = below-right)
* \param nearest nearest text box found, or NULL if none
* updated if box is nearer than existing nearest
* \param tx position of text_box, in global document coordinates
* updated if box is nearer than existing nearest
* \param ty position of text_box, in global document coordinates
* updated if box is nearer than existing nearest
* \param nr_xd distance to nearest text box found
* updated if box is nearer than existing nearest
* \param ny_yd distance to nearest text box found
* updated if box is nearer than existing nearest
* \return true if mouse point is inside box
*/
 
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)
{
int w = box->padding[LEFT] + box->width + box->padding[RIGHT];
int h = box->padding[TOP] + box->height + box->padding[BOTTOM];
int y1 = by + h;
int x1 = bx + w;
int yd = INT_MAX;
int xd = INT_MAX;
 
if (x >= bx && x1 > x && y >= by && y1 > y) {
*nearest = box;
*tx = bx;
*ty = by;
return true;
}
 
if (box->parent->list_marker != box) {
if (dir < 0) {
/* consider only those children (partly) above-left */
if (by <= y && bx < x) {
yd = y <= y1 ? 0 : y - y1;
xd = x <= x1 ? 0 : x - x1;
}
} else {
/* consider only those children (partly) below-right */
if (y1 > y && x1 > x) {
yd = y > by ? 0 : by - y;
xd = x > bx ? 0 : bx - x;
}
}
 
/* give y displacement precedence over x */
if (yd < *nr_yd || (yd == *nr_yd && xd <= *nr_xd)) {
*nr_yd = yd;
*nr_xd = xd;
*nearest = box;
*tx = bx;
*ty = by;
}
}
return false;
}
 
 
/**
* Pick the text box child of 'box' that is closest to and above-left
* (dir -ve) or below-right (dir +ve) of the point 'x,y'
*
* \param box parent box
* \param bx position of box, in global document coordinates
* \param by position of box, in global document coordinates
* \param fx position of float parent, in global document coordinates
* \param fy position of float parent, in global document coordinates
* \param x mouse point, in global document coordinates
* \param y mouse point, in global document coordinates
* \param dir direction in which to search (-1 = above-left,
* +1 = below-right)
* \param nearest nearest text box found, or NULL if none
* updated if a descendant of box is nearer than old nearest
* \param tx position of nearest, in global document coordinates
* updated if a descendant of box is nearer than old nearest
* \param ty position of nearest, in global document coordinates
* updated if a descendant of box is nearer than old nearest
* \param nr_xd distance to nearest text box found
* updated if a descendant of box is nearer than old nearest
* \param ny_yd distance to nearest text box found
* updated if a descendant of box is nearer than old nearest
* \return true if mouse point is inside text_box
*/
 
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)
{
struct box *child = box->children;
int c_bx, c_by;
int c_fx, c_fy;
bool in_box = false;
 
if (*nearest == NULL) {
*nr_xd = INT_MAX / 2; /* displacement of 'nearest so far' */
*nr_yd = INT_MAX / 2;
}
if (box->type == BOX_INLINE_CONTAINER) {
int bw = box->padding[LEFT] + box->width + box->padding[RIGHT];
int bh = box->padding[TOP] + box->height + box->padding[BOTTOM];
int b_y1 = by + bh;
int b_x1 = bx + bw;
if (x >= bx && b_x1 > x && y >= by && b_y1 > y) {
in_box = true;
}
}
 
while (child) {
if (child->type == BOX_FLOAT_LEFT ||
child->type == BOX_FLOAT_RIGHT) {
c_bx = fx + child->x -
scrollbar_get_offset(child->scroll_x);
c_by = fy + child->y -
scrollbar_get_offset(child->scroll_y);
} else {
c_bx = bx + child->x -
scrollbar_get_offset(child->scroll_x);
c_by = by + child->y -
scrollbar_get_offset(child->scroll_y);
}
if (child->float_children) {
c_fx = c_bx;
c_fy = c_by;
} else {
c_fx = fx;
c_fy = fy;
}
if (in_box && child->text && !child->object) {
if (box_nearer_text_box(child,
c_bx, c_by, x, y, dir, nearest,
tx, ty, nr_xd, nr_yd))
return true;
} else {
if (child->list_marker) {
if (box_nearer_text_box(
child->list_marker,
c_bx + child->list_marker->x,
c_by + child->list_marker->y,
x, y, dir, nearest,
tx, ty, nr_xd, nr_yd))
return true;
}
if (box_nearest_text_box(child, c_bx, c_by,
c_fx, c_fy, x, y, dir, nearest, tx, ty,
nr_xd, nr_yd))
return true;
}
child = child->next;
}
 
return false;
}
 
 
/**
* 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.
*
* \param html an HTML content
* \param x coordinate of mouse
* \param y coordinate of mouse
* \param dir direction to search (-1 = above-left, +1 = below-right)
* \param dx receives x ordinate of mouse relative to text box
* \param dy receives y ordinate of mouse relative to text box
*/
 
struct box *box_pick_text_box(struct html_content *html,
int x, int y, int dir, int *dx, int *dy)
{
struct box *text_box = NULL;
struct box *box;
int nr_xd, nr_yd;
int bx, by;
int fx, fy;
int tx, ty;
 
if (html == NULL)
return NULL;
 
box = html->layout;
bx = box->margin[LEFT];
by = box->margin[TOP];
fx = bx;
fy = by;
 
if (!box_nearest_text_box(box, bx, by, fx, fy, x, y,
dir, &text_box, &tx, &ty, &nr_xd, &nr_yd)) {
if (text_box && text_box->text && !text_box->object) {
int w = (text_box->padding[LEFT] +
text_box->width +
text_box->padding[RIGHT]);
int h = (text_box->padding[TOP] +
text_box->height +
text_box->padding[BOTTOM]);
int x1, y1;
 
y1 = ty + h;
x1 = tx + w;
 
/* ensure point lies within the text box */
if (x < tx) x = tx;
if (y < ty) y = ty;
if (y > y1) y = y1;
if (x > x1) x = x1;
}
}
 
/* return coordinates relative to box */
*dx = x - tx;
*dy = y - ty;
 
return text_box;
}
 
 
/**
* Find a box based upon its id attribute.
*
* \param box box tree to search
* \param id id to look for
* \return the box or 0 if not found
*/
 
struct box *box_find_by_id(struct box *box, lwc_string *id)
{
struct box *a, *b;
bool m;
 
if (box->id != NULL &&
lwc_string_isequal(id, box->id, &m) == lwc_error_ok &&
m == true)
return box;
 
for (a = box->children; a; a = a->next) {
if ((b = box_find_by_id(a, id)) != NULL)
return b;
}
 
return NULL;
}
 
 
/**
* Determine if a box is visible when the tree is rendered.
*
* \param box box to check
* \return true iff the box is rendered
*/
 
bool box_visible(struct box *box)
{
/* visibility: hidden */
if (box->style && css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)
return false;
 
return true;
}
 
 
/**
* Print a box tree to a file.
*/
 
void box_dump(FILE *stream, struct box *box, unsigned int depth)
{
unsigned int i;
struct box *c, *prev;
 
for (i = 0; i != depth; i++)
fprintf(stream, " ");
 
fprintf(stream, "%p ", box);
fprintf(stream, "x%i y%i w%i h%i ", box->x, box->y,
box->width, box->height);
if (box->max_width != UNKNOWN_MAX_WIDTH)
fprintf(stream, "min%i max%i ", box->min_width, box->max_width);
fprintf(stream, "(%i %i %i %i) ",
box->descendant_x0, box->descendant_y0,
box->descendant_x1, box->descendant_y1);
 
fprintf(stream, "m(%i %i %i %i) ",
box->margin[TOP], box->margin[LEFT],
box->margin[BOTTOM], box->margin[RIGHT]);
 
switch (box->type) {
case BOX_BLOCK: fprintf(stream, "BLOCK "); break;
case BOX_INLINE_CONTAINER: fprintf(stream, "INLINE_CONTAINER "); break;
case BOX_INLINE: fprintf(stream, "INLINE "); break;
case BOX_INLINE_END: fprintf(stream, "INLINE_END "); break;
case BOX_INLINE_BLOCK: fprintf(stream, "INLINE_BLOCK "); break;
case BOX_TABLE: fprintf(stream, "TABLE [columns %i] ",
box->columns); break;
case BOX_TABLE_ROW: fprintf(stream, "TABLE_ROW "); break;
case BOX_TABLE_CELL: fprintf(stream, "TABLE_CELL [columns %i, "
"start %i, rows %i] ", box->columns,
box->start_column, box->rows); break;
case BOX_TABLE_ROW_GROUP: fprintf(stream, "TABLE_ROW_GROUP "); break;
case BOX_FLOAT_LEFT: fprintf(stream, "FLOAT_LEFT "); break;
case BOX_FLOAT_RIGHT: fprintf(stream, "FLOAT_RIGHT "); break;
case BOX_BR: fprintf(stream, "BR "); break;
case BOX_TEXT: fprintf(stream, "TEXT "); break;
default: fprintf(stream, "Unknown box type ");
}
 
if (box->text)
fprintf(stream, "%li '%.*s' ", (unsigned long) box->byte_offset,
(int) box->length, box->text);
if (box->space)
fprintf(stream, "space ");
if (box->object) {
fprintf(stream, "(object '%s') ",
nsurl_access(hlcache_handle_get_url(box->object)));
}
if (box->iframe) {
fprintf(stream, "(iframe) ");
}
if (box->gadget)
fprintf(stream, "(gadget) ");
if (box->style)
nscss_dump_computed_style(stream, box->style);
if (box->href)
fprintf(stream, " -> '%s'", nsurl_access(box->href));
if (box->target)
fprintf(stream, " |%s|", box->target);
if (box->title)
fprintf(stream, " [%s]", box->title);
if (box->id)
fprintf(stream, " <%s>", lwc_string_data(box->id));
if (box->type == BOX_INLINE || box->type == BOX_INLINE_END)
fprintf(stream, " inline_end %p", box->inline_end);
if (box->float_children)
fprintf(stream, " float_children %p", box->float_children);
if (box->next_float)
fprintf(stream, " next_float %p", box->next_float);
if (box->col) {
fprintf(stream, " (columns");
for (i = 0; i != box->columns; i++)
fprintf(stream, " (%s %s %i %i %i)",
((const char *[]) {"UNKNOWN", "FIXED",
"AUTO", "PERCENT", "RELATIVE"})
[box->col[i].type],
((const char *[]) {"normal",
"positioned"})
[box->col[i].positioned],
box->col[i].width,
box->col[i].min, box->col[i].max);
fprintf(stream, ")");
}
fprintf(stream, "\n");
 
if (box->list_marker) {
for (i = 0; i != depth; i++)
fprintf(stream, " ");
fprintf(stream, "list_marker:\n");
box_dump(stream, box->list_marker, depth + 1);
}
 
for (c = box->children; c && c->next; c = c->next)
;
if (box->last != c)
fprintf(stream, "warning: box->last %p (should be %p) "
"(box %p)\n", box->last, c, box);
for (prev = 0, c = box->children; c; prev = c, c = c->next) {
if (c->parent != box)
fprintf(stream, "warning: box->parent %p (should be "
"%p) (box on next line)\n",
c->parent, box);
if (c->prev != prev)
fprintf(stream, "warning: box->prev %p (should be "
"%p) (box on next line)\n",
c->prev, prev);
box_dump(stream, c, depth + 1);
}
}
 
/**
* Applies the given scroll setup to a box. This includes scroll
* creation/deletion as well as scroll dimension updates.
*
* \param c content in which the box is located
* \param box the box to handle the scrolls for
* \param bottom whether the horizontal scrollbar should be present
* \param right whether the vertical scrollbar should be present
* \return true on success false otherwise
*/
bool box_handle_scrollbars(struct content *c, struct box *box,
bool bottom, bool right)
{
struct html_scrollbar_data *data;
int visible_width, visible_height;
int full_width, full_height;
 
if (!bottom && box->scroll_x != NULL) {
data = scrollbar_get_data(box->scroll_x);
scrollbar_destroy(box->scroll_x);
free(data);
box->scroll_x = NULL;
}
 
if (!right && box->scroll_y != NULL) {
data = scrollbar_get_data(box->scroll_y);
scrollbar_destroy(box->scroll_y);
free(data);
box->scroll_y = NULL;
}
 
if (!bottom && !right)
return true;
 
visible_width = box->width + box->padding[RIGHT] + box->padding[LEFT];
visible_height = box->height + box->padding[TOP] + box->padding[BOTTOM];
 
full_width = ((box->descendant_x1 - box->border[RIGHT].width) >
visible_width) ?
box->descendant_x1 + box->padding[RIGHT] :
visible_width;
full_height = ((box->descendant_y1 - box->border[BOTTOM].width) >
visible_height) ?
box->descendant_y1 + box->padding[BOTTOM] :
visible_height;
 
if (right) {
if (box->scroll_y == NULL) {
data = malloc(sizeof(struct html_scrollbar_data));
if (data == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
return false;
}
data->c = c;
data->box = box;
if (!scrollbar_create(false, visible_height,
full_height, visible_height,
data, html_overflow_scroll_callback,
&(box->scroll_y)))
return false;
} else {
scrollbar_set_extents(box->scroll_y, visible_height,
visible_height, full_height);
}
}
if (bottom) {
if (box->scroll_x == NULL) {
data = malloc(sizeof(struct html_scrollbar_data));
if (data == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
return false;
}
data->c = c;
data->box = box;
if (!scrollbar_create(true,
visible_width -
(right ? SCROLLBAR_WIDTH : 0),
full_width, visible_width,
data, html_overflow_scroll_callback,
&box->scroll_x))
return false;
} else {
scrollbar_set_extents(box->scroll_x,
visible_width -
(right ? SCROLLBAR_WIDTH : 0),
visible_width, full_width);
}
}
if (right && bottom)
scrollbar_make_pair(box->scroll_x, box->scroll_y);
return true;
}
 
/**
* Determine if a box has a vertical scrollbar.
*
* \param box scrolling box
* \return the box has a vertical scrollbar
*/
 
bool box_vscrollbar_present(const struct box * const box)
{
return box->padding[TOP] + box->height + box->padding[BOTTOM] +
box->border[BOTTOM].width < box->descendant_y1;
}
 
 
/**
* Determine if a box has a horizontal scrollbar.
*
* \param box scrolling box
* \return the box has a horizontal scrollbar
*/
 
bool box_hscrollbar_present(const struct box * const box)
{
return box->padding[LEFT] + box->width + box->padding[RIGHT] +
box->border[RIGHT].width < box->descendant_x1;
}
 
/programs/network/netsurf/netsurf/render/box.h
0,0 → 1,351
/*
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
typedef unsigned int uint32_t;
 
/** \file
* Box tree construction and manipulation (interface).
*
* This stage of rendering converts a tree of dom_nodes (produced by libdom)
* to a tree of struct box. The box tree represents the structure of the
* document as given by the CSS display and float properties.
*
* For example, consider the following HTML:
* \code
* <h1>Example Heading</h1>
* <p>Example paragraph <em>with emphasised text</em> etc.</p> \endcode
*
* This would produce approximately the following box tree with default CSS
* rules:
* \code
* BOX_BLOCK (corresponds to h1)
* BOX_INLINE_CONTAINER
* BOX_INLINE "Example Heading"
* BOX_BLOCK (p)
* BOX_INLINE_CONTAINER
* BOX_INLINE "Example paragraph "
* BOX_INLINE "with emphasised text" (em)
* BOX_INLINE "etc." \endcode
*
* Note that the em has been collapsed into the INLINE_CONTAINER.
*
* If these CSS rules were applied:
* \code
* h1 { display: table-cell }
* p { display: table-cell }
* em { float: left; width: 5em } \endcode
*
* then the box tree would instead look like this:
* \code
* BOX_TABLE
* BOX_TABLE_ROW_GROUP
* BOX_TABLE_ROW
* BOX_TABLE_CELL (h1)
* BOX_INLINE_CONTAINER
* BOX_INLINE "Example Heading"
* BOX_TABLE_CELL (p)
* BOX_INLINE_CONTAINER
* BOX_INLINE "Example paragraph "
* BOX_FLOAT_LEFT (em)
* BOX_BLOCK
* BOX_INLINE_CONTAINER
* BOX_INLINE "with emphasised text"
* BOX_INLINE "etc." \endcode
*
* Here implied boxes have been added and a float is present.
*
* A box tree is "normalized" if the following is satisfied:
* \code
* parent permitted child nodes
* BLOCK, INLINE_BLOCK BLOCK, INLINE_CONTAINER, TABLE
* INLINE_CONTAINER INLINE, INLINE_BLOCK, FLOAT_LEFT, FLOAT_RIGHT, BR, TEXT,
* INLINE_END
* INLINE none
* TABLE at least 1 TABLE_ROW_GROUP
* TABLE_ROW_GROUP at least 1 TABLE_ROW
* TABLE_ROW at least 1 TABLE_CELL
* TABLE_CELL BLOCK, INLINE_CONTAINER, TABLE (same as BLOCK)
* FLOAT_(LEFT|RIGHT) exactly 1 BLOCK or TABLE
* \endcode
*/
 
#ifndef _NETSURF_RENDER_BOX_H_
#define _NETSURF_RENDER_BOX_H_
 
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
 
#include "css/css.h"
#include "utils/nsurl.h"
#include "utils/types.h"
 
struct box;
struct browser_window;
struct column;
struct object_params;
struct object_param;
struct html_content;
 
struct dom_node;
 
#define UNKNOWN_WIDTH INT_MAX
#define UNKNOWN_MAX_WIDTH INT_MAX
 
typedef void (*box_construct_complete_cb)(struct html_content *c, bool success);
 
/** Type of a struct box. */
typedef enum {
BOX_BLOCK, BOX_INLINE_CONTAINER, BOX_INLINE,
BOX_TABLE, BOX_TABLE_ROW, BOX_TABLE_CELL,
BOX_TABLE_ROW_GROUP,
BOX_FLOAT_LEFT, BOX_FLOAT_RIGHT,
BOX_INLINE_BLOCK, BOX_BR, BOX_TEXT,
BOX_INLINE_END, BOX_NONE
} box_type;
 
 
/** Flags for a struct box. */
typedef enum {
NEW_LINE = 1 << 0, /* first inline on a new line */
STYLE_OWNED = 1 << 1, /* style is owned by this box */
PRINTED = 1 << 2, /* box has already been printed */
PRE_STRIP = 1 << 3, /* PRE tag needing leading newline stripped */
CLONE = 1 << 4, /* continuation of previous box from wrapping */
MEASURED = 1 << 5, /* text box width has been measured */
HAS_HEIGHT = 1 << 6, /* box has height (perhaps due to children) */
MAKE_HEIGHT = 1 << 7, /* box causes its own height */
NEED_MIN = 1 << 8, /* minimum width is required for layout */
REPLACE_DIM = 1 << 9, /* replaced element has given dimensions */
IFRAME = 1 << 10, /* box contains an iframe */
CONVERT_CHILDREN = 1 << 11 /* wanted children converting */
} box_flags;
 
/* Sides of a box */
enum box_side { TOP, RIGHT, BOTTOM, LEFT };
 
/**
* Container for box border details
*/
struct box_border {
enum css_border_style_e style; /**< border-style */
css_color c; /**< border-color value */
int width; /**< border-width (pixels) */
};
 
/** Node in box tree. All dimensions are in pixels. */
struct box {
/** Type of box. */
box_type type;
 
/** Box flags */
box_flags flags;
 
/** Computed styles for elements and their pseudo elements. NULL on
* non-element boxes. */
css_select_results *styles;
 
/** Style for this box. 0 for INLINE_CONTAINER and FLOAT_*. Pointer into
* a box's 'styles' select results, except for implied boxes, where it
* is a pointer to an owned computed style. */
css_computed_style *style;
 
/** Coordinate of left padding edge relative to parent box, or relative
* to ancestor that contains this box in float_children for FLOAT_. */
int x;
/** Coordinate of top padding edge, relative as for x. */
int y;
 
int width; /**< Width of content box (excluding padding etc.). */
int height; /**< Height of content box (excluding padding etc.). */
 
/* These four variables determine the maximum extent of a box's
* descendants. They are relative to the x,y coordinates of the box.
*
* Their use depends on the overflow CSS property:
*
* Overflow: Usage:
* visible The content of the box is displayed within these
* dimensions.
* hidden These are ignored. Content is plotted within the box
* dimensions.
* scroll These are used to determine the extent of the
* scrollable area.
* auto As "scroll".
*/
int descendant_x0; /**< left edge of descendants */
int descendant_y0; /**< top edge of descendants */
int descendant_x1; /**< right edge of descendants */
int descendant_y1; /**< bottom edge of descendants */
 
int margin[4]; /**< Margin: TOP, RIGHT, BOTTOM, LEFT. */
int padding[4]; /**< Padding: TOP, RIGHT, BOTTOM, LEFT. */
struct box_border border[4]; /**< Border: TOP, RIGHT, BOTTOM, LEFT. */
 
struct scrollbar *scroll_x; /**< Horizontal scroll. */
struct scrollbar *scroll_y; /**< Vertical scroll. */
 
/** Width of box taking all line breaks (including margins etc). Must
* be non-negative. */
int min_width;
/** Width that would be taken with no line breaks. Must be
* non-negative. */
int max_width;
 
/**< Byte offset within a textual representation of this content. */
size_t byte_offset;
 
char *text; /**< Text, or 0 if none. Unterminated. */
size_t length; /**< Length of text. */
 
/** Width of space after current text (depends on font and size). */
int space;
 
nsurl *href; /**< Link, or 0. */
const char *target; /**< Link target, or 0. */
const char *title; /**< Title, or 0. */
 
unsigned int columns; /**< Number of columns for TABLE / TABLE_CELL. */
unsigned int rows; /**< Number of rows for TABLE only. */
unsigned int start_column; /**< Start column for TABLE_CELL only. */
 
struct box *next; /**< Next sibling box, or 0. */
struct box *prev; /**< Previous sibling box, or 0. */
struct box *children; /**< First child box, or 0. */
struct box *last; /**< Last child box, or 0. */
struct box *parent; /**< Parent box, or 0. */
/** INLINE_END box corresponding to this INLINE box, or INLINE box
* corresponding to this INLINE_END box. */
struct box *inline_end;
 
/** First float child box, or 0. Float boxes are in the tree twice, in
* this list for the block box which defines the area for floats, and
* also in the standard tree given by children, next, prev, etc. */
struct box *float_children;
/** Next sibling float box. */
struct box *next_float;
/** If box is a float, points to box's containing block */
struct box *float_container;
/** Level below which subsequent floats must be cleared.
* This is used only for boxes with float_children */
int clear_level;
 
/** List marker box if this is a list-item, or 0. */
struct box *list_marker;
 
struct column *col; /**< Array of table column data for TABLE only. */
 
/** Form control data, or 0 if not a form control. */
struct form_control* gadget;
 
char *usemap; /** (Image)map to use with this object, or 0 if none */
lwc_string *id; /**< value of id attribute (or name for anchors) */
 
/** Background image for this box, or 0 if none */
struct hlcache_handle *background;
 
/** Object in this box (usually an image), or 0 if none. */
struct hlcache_handle* object;
/** Parameters for the object, or 0. */
struct object_params *object_params;
 
/** Iframe's browser_window, or NULL if none */
struct browser_window *iframe;
 
struct dom_node *node; /**< DOM node that generated this box or NULL */
};
 
/** Table column data. */
struct column {
/** Type of column. */
enum { COLUMN_WIDTH_UNKNOWN, COLUMN_WIDTH_FIXED,
COLUMN_WIDTH_AUTO, COLUMN_WIDTH_PERCENT,
COLUMN_WIDTH_RELATIVE } type;
/** Preferred width of column. Pixels for FIXED, percentage for PERCENT,
* relative units for RELATIVE, unused for AUTO. */
int width;
/** Minimum width of content. */
int min;
/** Maximum width of content. */
int max;
/** Whether all of column's cells are css positioned. */
bool positioned;
};
 
/** Parameters for object element and similar elements. */
struct object_params {
nsurl *data;
char *type;
char *codetype;
nsurl *codebase;
nsurl *classid;
struct object_param *params;
};
 
/** Linked list of object element parameters. */
struct object_param {
char *name;
char *value;
char *type;
char *valuetype;
struct object_param *next;
};
 
/** Frame target names (constant pointers to save duplicating the strings many
* times). We convert _blank to _top for user-friendliness. */
extern const char *TARGET_SELF;
extern const char *TARGET_PARENT;
extern const char *TARGET_TOP;
extern const char *TARGET_BLANK;
 
 
 
void *box_style_alloc(void *ptr, size_t len, void *pw);
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);
void box_add_child(struct box *parent, struct box *child);
void box_insert_sibling(struct box *box, struct box *new_box);
void box_unlink_and_free(struct box *box);
void box_free(struct box *box);
void box_free_box(struct box *box);
void box_bounds(struct box *box, struct rect *r);
void box_coords(struct box *box, int *x, int *y);
struct box *box_at_point(struct box *box, const int x, const int y,
int *box_x, int *box_y);
struct box *box_pick_text_box(struct html_content *html,
int x, int y, int dir, int *dx, int *dy);
struct box *box_find_by_id(struct box *box, lwc_string *id);
bool box_visible(struct box *box);
void box_dump(FILE *stream, struct box *box, unsigned int depth);
bool box_extract_link(const char *rel, nsurl *base, nsurl **result);
 
bool box_handle_scrollbars(struct content *c, struct box *box,
bool bottom, bool right);
bool box_vscrollbar_present(const struct box *box);
bool box_hscrollbar_present(const struct box *box);
 
nserror box_construct_init(void);
void box_construct_fini(void);
nserror dom_to_box(struct dom_node *n, struct html_content *c,
box_construct_complete_cb cb);
 
bool box_normalise_block(struct box *block, struct html_content *c);
 
#endif
/programs/network/netsurf/netsurf/render/box_construct.c
0,0 → 1,3312
/*
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2006 Richard Wilson <info@tinct.net>
* Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Conversion of XML tree to box tree (implementation).
*/
 
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "utils/config.h"
#include "content/content_protected.h"
#include "css/css.h"
#include "css/utils.h"
#include "css/select.h"
#include "desktop/options.h"
#include "render/box.h"
#include "render/form.h"
#include "render/html_internal.h"
#include "utils/corestrings.h"
#include "utils/locale.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/schedule.h"
#include "utils/talloc.h"
#include "utils/url.h"
#include "utils/utils.h"
 
/**
* Context for box tree construction
*/
struct box_construct_ctx {
html_content *content; /**< Content we're constructing for */
 
dom_node *n; /**< Current node to process */
 
struct box *root_box; /**< Root box in the tree */
 
box_construct_complete_cb cb; /**< Callback to invoke on completion */
 
int *bctx; /**< talloc context */
};
 
/**
* Transient properties for construction of current node
*/
struct box_construct_props {
/** Style from which to inherit, or NULL if none */
const css_computed_style *parent_style;
/** Current link target, or NULL if none */
nsurl *href;
/** Current frame target, or NULL if none */
const char *target;
/** Current title attribute, or NULL if none */
const char *title;
/** Identity of the current block-level container */
struct box *containing_block;
/** Current container for inlines, or NULL if none
* \note If non-NULL, will be the last child of containing_block */
struct box *inline_container;
/** Whether the current node is the root of the DOM tree */
bool node_is_root;
};
 
static const content_type image_types = CONTENT_IMAGE;
 
/* the strings are not important, since we just compare the pointers */
const char *TARGET_SELF = "_self";
const char *TARGET_PARENT = "_parent";
const char *TARGET_TOP = "_top";
const char *TARGET_BLANK = "_blank";
 
static void convert_xml_to_box(struct box_construct_ctx *ctx);
static bool box_construct_element(struct box_construct_ctx *ctx,
bool *convert_children);
static void box_construct_element_after(dom_node *n, html_content *content);
static bool box_construct_text(struct box_construct_ctx *ctx);
static css_select_results * box_get_style(html_content *c,
const css_computed_style *parent_style, dom_node *n);
static void box_text_transform(char *s, unsigned int len,
enum css_text_transform_e tt);
#define BOX_SPECIAL_PARAMS dom_node *n, html_content *content, \
struct box *box, bool *convert_children
static bool box_a(BOX_SPECIAL_PARAMS);
static bool box_body(BOX_SPECIAL_PARAMS);
static bool box_br(BOX_SPECIAL_PARAMS);
static bool box_image(BOX_SPECIAL_PARAMS);
static bool box_textarea(BOX_SPECIAL_PARAMS);
static bool box_select(BOX_SPECIAL_PARAMS);
static bool box_input(BOX_SPECIAL_PARAMS);
static bool box_input_text(BOX_SPECIAL_PARAMS, bool password);
static bool box_button(BOX_SPECIAL_PARAMS);
static bool box_frameset(BOX_SPECIAL_PARAMS);
static bool box_create_frameset(struct content_html_frames *f, dom_node *n,
html_content *content);
static bool box_select_add_option(struct form_control *control, dom_node *n);
static bool box_noscript(BOX_SPECIAL_PARAMS);
static bool box_object(BOX_SPECIAL_PARAMS);
static bool box_embed(BOX_SPECIAL_PARAMS);
static bool box_pre(BOX_SPECIAL_PARAMS);
static bool box_iframe(BOX_SPECIAL_PARAMS);
static bool box_get_attribute(dom_node *n, const char *attribute,
void *context, char **value);
static struct frame_dimension *box_parse_multi_lengths(const char *s,
unsigned int *count);
 
/* element_table must be sorted by name */
struct element_entry {
char name[10]; /* element type */
bool (*convert)(BOX_SPECIAL_PARAMS);
};
static const struct element_entry element_table[] = {
{"a", box_a},
{"body", box_body},
{"br", box_br},
{"button", box_button},
{"embed", box_embed},
{"frameset", box_frameset},
{"iframe", box_iframe},
{"image", box_image},
{"img", box_image},
{"input", box_input},
{"noscript", box_noscript},
{"object", box_object},
{"pre", box_pre},
{"select", box_select},
{"textarea", box_textarea}
};
#define ELEMENT_TABLE_COUNT (sizeof(element_table) / sizeof(element_table[0]))
 
/**
* Construct a box tree from an xml tree and stylesheets.
*
* \param n xml tree
* \param c content of type CONTENT_HTML to construct box tree in
* \param cb callback to report conversion completion
* \return netsurf error code indicating status of call
*/
 
nserror dom_to_box(dom_node *n, html_content *c, box_construct_complete_cb cb)
{
struct box_construct_ctx *ctx;
 
if (c->bctx == NULL) {
/* create a context allocation for this box tree */
c->bctx = talloc_zero(0, int);
if (c->bctx == NULL) {
return NSERROR_NOMEM;
}
}
 
ctx = malloc(sizeof(*ctx));
if (ctx == NULL) {
return NSERROR_NOMEM;
}
 
ctx->content = c;
ctx->n = dom_node_ref(n);
ctx->root_box = NULL;
ctx->cb = cb;
ctx->bctx = c->bctx;
 
schedule(0, (schedule_callback_fn) convert_xml_to_box, ctx);
 
return NSERROR_OK;
}
 
/* mapping from CSS display to box type
* this table must be in sync with libcss' css_display enum */
static const box_type box_map[] = {
0, /*CSS_DISPLAY_INHERIT,*/
BOX_INLINE, /*CSS_DISPLAY_INLINE,*/
BOX_BLOCK, /*CSS_DISPLAY_BLOCK,*/
BOX_BLOCK, /*CSS_DISPLAY_LIST_ITEM,*/
BOX_INLINE, /*CSS_DISPLAY_RUN_IN,*/
BOX_INLINE_BLOCK, /*CSS_DISPLAY_INLINE_BLOCK,*/
BOX_TABLE, /*CSS_DISPLAY_TABLE,*/
BOX_TABLE, /*CSS_DISPLAY_INLINE_TABLE,*/
BOX_TABLE_ROW_GROUP, /*CSS_DISPLAY_TABLE_ROW_GROUP,*/
BOX_TABLE_ROW_GROUP, /*CSS_DISPLAY_TABLE_HEADER_GROUP,*/
BOX_TABLE_ROW_GROUP, /*CSS_DISPLAY_TABLE_FOOTER_GROUP,*/
BOX_TABLE_ROW, /*CSS_DISPLAY_TABLE_ROW,*/
BOX_NONE, /*CSS_DISPLAY_TABLE_COLUMN_GROUP,*/
BOX_NONE, /*CSS_DISPLAY_TABLE_COLUMN,*/
BOX_TABLE_CELL, /*CSS_DISPLAY_TABLE_CELL,*/
BOX_INLINE, /*CSS_DISPLAY_TABLE_CAPTION,*/
BOX_NONE /*CSS_DISPLAY_NONE*/
};
 
/** Key for box userdata on DOM elements (== '__ns_box') */
static dom_string *kstr_box_key;
static dom_string *kstr_title;
static dom_string *kstr_id;
static dom_string *kstr_colspan;
static dom_string *kstr_rowspan;
static dom_string *kstr_style;
static dom_string *kstr_href;
static dom_string *kstr_name;
static dom_string *kstr_target;
static dom_string *kstr_alt;
static dom_string *kstr_src;
static dom_string *kstr_codebase;
static dom_string *kstr_classid;
static dom_string *kstr_data;
static dom_string *kstr_rows;
static dom_string *kstr_cols;
static dom_string *kstr_border;
static dom_string *kstr_frameborder;
static dom_string *kstr_bordercolor;
static dom_string *kstr_noresize;
static dom_string *kstr_scrolling;
static dom_string *kstr_marginwidth;
static dom_string *kstr_marginheight;
static dom_string *kstr_type;
static dom_string *kstr_value;
static dom_string *kstr_selected;
 
nserror box_construct_init(void)
{
dom_exception err;
 
err = dom_string_create_interned((const uint8_t *) "__ns_box",
SLEN("__ns_box"), &kstr_box_key);
if (err != DOM_NO_ERR || kstr_box_key == NULL)
goto error;
 
#define BOX_CONSTRUCT_STRING_INTERN(NAME) \
err = dom_string_create_interned((const uint8_t *)#NAME, \
sizeof(#NAME) - 1, \
&kstr_##NAME ); \
if ((err != DOM_NO_ERR) || (kstr_##NAME == NULL)) \
goto error
 
BOX_CONSTRUCT_STRING_INTERN(title);
BOX_CONSTRUCT_STRING_INTERN(id);
BOX_CONSTRUCT_STRING_INTERN(colspan);
BOX_CONSTRUCT_STRING_INTERN(rowspan);
BOX_CONSTRUCT_STRING_INTERN(style);
BOX_CONSTRUCT_STRING_INTERN(href);
BOX_CONSTRUCT_STRING_INTERN(name);
BOX_CONSTRUCT_STRING_INTERN(target);
BOX_CONSTRUCT_STRING_INTERN(alt);
BOX_CONSTRUCT_STRING_INTERN(src);
BOX_CONSTRUCT_STRING_INTERN(codebase);
BOX_CONSTRUCT_STRING_INTERN(classid);
BOX_CONSTRUCT_STRING_INTERN(data);
BOX_CONSTRUCT_STRING_INTERN(rows);
BOX_CONSTRUCT_STRING_INTERN(cols);
BOX_CONSTRUCT_STRING_INTERN(border);
BOX_CONSTRUCT_STRING_INTERN(frameborder);
BOX_CONSTRUCT_STRING_INTERN(bordercolor);
BOX_CONSTRUCT_STRING_INTERN(noresize);
BOX_CONSTRUCT_STRING_INTERN(scrolling);
BOX_CONSTRUCT_STRING_INTERN(marginwidth);
BOX_CONSTRUCT_STRING_INTERN(marginheight);
BOX_CONSTRUCT_STRING_INTERN(type);
BOX_CONSTRUCT_STRING_INTERN(value);
BOX_CONSTRUCT_STRING_INTERN(selected);
 
#undef BOX_CONSTRUCT_STRING_INTERN
 
return NSERROR_OK;
 
error:
return NSERROR_NOMEM;
}
 
void box_construct_fini(void)
{
if (kstr_box_key != NULL) {
dom_string_unref(kstr_box_key);
kstr_box_key = NULL;
}
 
#define BOX_CONSTRUCT_STRING_UNREF(NAME) \
do { \
if (kstr_##NAME != NULL) { \
dom_string_unref(kstr_##NAME); \
kstr_##NAME = NULL; \
} \
} while (0) \
 
BOX_CONSTRUCT_STRING_UNREF(title);
BOX_CONSTRUCT_STRING_UNREF(id);
BOX_CONSTRUCT_STRING_UNREF(colspan);
BOX_CONSTRUCT_STRING_UNREF(rowspan);
BOX_CONSTRUCT_STRING_UNREF(style);
BOX_CONSTRUCT_STRING_UNREF(href);
BOX_CONSTRUCT_STRING_UNREF(name);
BOX_CONSTRUCT_STRING_UNREF(target);
BOX_CONSTRUCT_STRING_UNREF(alt);
BOX_CONSTRUCT_STRING_UNREF(src);
BOX_CONSTRUCT_STRING_UNREF(codebase);
BOX_CONSTRUCT_STRING_UNREF(classid);
BOX_CONSTRUCT_STRING_UNREF(data);
BOX_CONSTRUCT_STRING_UNREF(rows);
BOX_CONSTRUCT_STRING_UNREF(cols);
BOX_CONSTRUCT_STRING_UNREF(border);
BOX_CONSTRUCT_STRING_UNREF(frameborder);
BOX_CONSTRUCT_STRING_UNREF(bordercolor);
BOX_CONSTRUCT_STRING_UNREF(noresize);
BOX_CONSTRUCT_STRING_UNREF(scrolling);
BOX_CONSTRUCT_STRING_UNREF(marginwidth);
BOX_CONSTRUCT_STRING_UNREF(marginheight);
BOX_CONSTRUCT_STRING_UNREF(type);
BOX_CONSTRUCT_STRING_UNREF(value);
BOX_CONSTRUCT_STRING_UNREF(selected);
 
#undef BOX_CONSTRUCT_DOM_STRING_UNREF
}
 
static inline struct box *box_for_node(dom_node *n)
{
struct box *box = NULL;
dom_exception err;
 
err = dom_node_get_user_data(n, kstr_box_key, (void *) &box);
if (err != DOM_NO_ERR)
return NULL;
 
return box;
}
 
static inline bool box_is_root(dom_node *n)
{
dom_node *parent;
dom_node_type type;
dom_exception err;
 
err = dom_node_get_parent_node(n, &parent);
if (err != DOM_NO_ERR)
return false;
 
if (parent != NULL) {
err = dom_node_get_node_type(parent, &type);
 
dom_node_unref(parent);
 
if (err != DOM_NO_ERR)
return false;
 
if (type != DOM_DOCUMENT_NODE)
return false;
}
 
return true;
}
 
/**
* Find the next node in the DOM tree, completing
* element construction where appropriate.
*
* \param n Current node
* \param content Containing content
* \param convert_children Whether to consider children of \a n
* \return Next node to process, or NULL if complete
*
* \note \a n will be unreferenced
*/
static dom_node *next_node(dom_node *n, html_content *content,
bool convert_children)
{
dom_node *next = NULL;
bool has_children;
dom_exception err;
 
err = dom_node_has_child_nodes(n, &has_children);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return NULL;
}
 
if (convert_children && has_children) {
err = dom_node_get_first_child(n, &next);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return NULL;
}
dom_node_unref(n);
} else {
err = dom_node_get_next_sibling(n, &next);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return NULL;
}
 
if (next != NULL) {
if (box_for_node(n) != NULL)
box_construct_element_after(n, content);
dom_node_unref(n);
} else {
if (box_for_node(n) != NULL)
box_construct_element_after(n, content);
 
while (box_is_root(n) == false) {
dom_node *parent = NULL;
dom_node *parent_next = NULL;
 
err = dom_node_get_parent_node(n, &parent);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return NULL;
}
 
assert(parent != NULL);
 
err = dom_node_get_next_sibling(parent,
&parent_next);
if (err != DOM_NO_ERR) {
dom_node_unref(parent);
dom_node_unref(n);
return NULL;
}
 
if (parent_next != NULL) {
dom_node_unref(parent_next);
dom_node_unref(parent);
break;
}
 
dom_node_unref(n);
n = parent;
parent = NULL;
 
if (box_for_node(n) != NULL) {
box_construct_element_after(
n, content);
}
}
 
if (box_is_root(n) == false) {
dom_node *parent = NULL;
 
err = dom_node_get_parent_node(n, &parent);
if (err != DOM_NO_ERR) {
dom_node_unref(n);
return NULL;
}
 
assert(parent != NULL);
 
err = dom_node_get_next_sibling(parent, &next);
if (err != DOM_NO_ERR) {
dom_node_unref(parent);
dom_node_unref(n);
return NULL;
}
 
if (box_for_node(parent) != NULL) {
box_construct_element_after(parent,
content);
}
 
dom_node_unref(parent);
}
 
dom_node_unref(n);
}
}
 
return next;
}
 
/**
* Convert an ELEMENT node to a box tree fragment,
* then schedule conversion of the next ELEMENT node
*/
void convert_xml_to_box(struct box_construct_ctx *ctx)
{
dom_node *next;
bool convert_children;
uint32_t num_processed = 0;
const uint32_t max_processed_before_yield = 10;
 
do {
convert_children = true;
 
assert(ctx->n != NULL);
 
if (box_construct_element(ctx, &convert_children) == false) {
ctx->cb(ctx->content, false);
dom_node_unref(ctx->n);
free(ctx);
return;
}
 
/* Find next element to process, converting text nodes as we go */
next = next_node(ctx->n, ctx->content, convert_children);
while (next != NULL) {
dom_node_type type;
dom_exception err;
 
err = dom_node_get_node_type(next, &type);
if (err != DOM_NO_ERR) {
ctx->cb(ctx->content, false);
dom_node_unref(next);
free(ctx);
return;
}
 
if (type == DOM_ELEMENT_NODE)
break;
 
if (type == DOM_TEXT_NODE) {
ctx->n = next;
if (box_construct_text(ctx) == false) {
ctx->cb(ctx->content, false);
dom_node_unref(ctx->n);
free(ctx);
return;
}
}
 
next = next_node(next, ctx->content, true);
}
 
ctx->n = next;
 
if (next == NULL) {
/* Conversion complete */
struct box root;
 
memset(&root, 0, sizeof(root));
 
root.type = BOX_BLOCK;
root.children = root.last = ctx->root_box;
root.children->parent = &root;
 
/** \todo Remove box_normalise_block */
if (box_normalise_block(&root, ctx->content) == false) {
ctx->cb(ctx->content, false);
} else {
ctx->content->layout = root.children;
ctx->content->layout->parent = NULL;
 
ctx->cb(ctx->content, true);
}
 
assert(ctx->n == NULL);
 
free(ctx);
return;
}
} while (++num_processed < max_processed_before_yield);
 
/* More work to do: schedule a continuation */
schedule(0, (schedule_callback_fn) convert_xml_to_box, ctx);
}
 
/**
* Construct a list marker box
*
* \param box Box to attach marker to
* \param title Current title attribute
* \param content Containing content
* \param parent Current block-level container
* \return True on success, false on memory exhaustion
*/
static bool box_construct_marker(struct box *box, const char *title,
struct box_construct_ctx *ctx, struct box *parent)
{
lwc_string *image_uri;
struct box *marker;
 
marker = box_create(NULL, box->style, false, NULL, NULL, title,
NULL, ctx->bctx);
if (marker == false)
return false;
 
marker->type = BOX_BLOCK;
 
/** \todo marker content (list-style-type) */
switch (css_computed_list_style_type(box->style)) {
case CSS_LIST_STYLE_TYPE_DISC:
/* 2022 BULLET */
marker->text = (char *) "\342\200\242";
marker->length = 3;
break;
case CSS_LIST_STYLE_TYPE_CIRCLE:
/* 25CB WHITE CIRCLE */
marker->text = (char *) "\342\227\213";
marker->length = 3;
break;
case CSS_LIST_STYLE_TYPE_SQUARE:
/* 25AA BLACK SMALL SQUARE */
marker->text = (char *) "\342\226\252";
marker->length = 3;
break;
case CSS_LIST_STYLE_TYPE_DECIMAL:
case CSS_LIST_STYLE_TYPE_LOWER_ALPHA:
case CSS_LIST_STYLE_TYPE_LOWER_ROMAN:
case CSS_LIST_STYLE_TYPE_UPPER_ALPHA:
case CSS_LIST_STYLE_TYPE_UPPER_ROMAN:
default:
if (parent->last) {
struct box *last = parent->last;
 
/* Drill down into last child of parent
* to find the list marker (if any)
*
* Floated list boxes end up as:
*
* parent
* BOX_INLINE_CONTAINER
* BOX_FLOAT_{LEFT,RIGHT}
* BOX_BLOCK <-- list box
* ...
*/
while (last != NULL) {
if (last->list_marker != NULL)
break;
 
last = last->last;
}
 
if (last && last->list_marker) {
marker->rows = last->list_marker->rows + 1;
}
}
 
marker->text = talloc_array(ctx->bctx, char, 20);
if (marker->text == NULL)
return false;
 
snprintf(marker->text, 20, "%u.", marker->rows);
marker->length = strlen(marker->text);
break;
case CSS_LIST_STYLE_TYPE_NONE:
marker->text = 0;
marker->length = 0;
break;
}
 
if (css_computed_list_style_image(box->style, &image_uri) == CSS_LIST_STYLE_IMAGE_URI &&
(image_uri != NULL) &&
(nsoption_bool(foreground_images) == true)) {
nsurl *url;
nserror error;
 
/* TODO: we get a url out of libcss as a lwc string, but
* earlier we already had it as a nsurl after we
* nsurl_joined it. Can this be improved?
* For now, just making another nsurl. */
error = nsurl_create(lwc_string_data(image_uri), &url);
if (error != NSERROR_OK)
return false;
 
if (html_fetch_object(ctx->content, url, marker, image_types,
ctx->content->base.available_width, 1000, false) ==
false) {
nsurl_unref(url);
return false;
}
nsurl_unref(url);
}
 
box->list_marker = marker;
marker->parent = box;
 
return true;
}
 
/**
* Construct the box required for a generated element.
*
* \param n XML node of type XML_ELEMENT_NODE
* \param content Content of type CONTENT_HTML that is being processed
* \param box Box which may have generated content
* \param style Complete computed style for pseudo element, or NULL
*
* TODO:
* This is currently incomplete. It just does enough to support the clearfix
* hack. ( http://www.positioniseverything.net/easyclearing.html )
*/
static void box_construct_generate(dom_node *n, html_content *content,
struct box *box, const css_computed_style *style)
{
struct box *gen = NULL;
const css_computed_content_item *c_item;
 
/* Nothing to generate if the parent box is not a block */
if (box->type != BOX_BLOCK)
return;
 
/* To determine if an element has a pseudo element, we select
* for it and test to see if the returned style's content
* property is set to normal. */
if (style == NULL ||
css_computed_content(style, &c_item) ==
CSS_CONTENT_NORMAL) {
/* No pseudo element */
return;
}
 
/* create box for this element */
if (css_computed_display(style, box_is_root(n)) == CSS_DISPLAY_BLOCK) {
/* currently only support block level elements */
 
/** \todo Not wise to drop const from the computed style */
gen = box_create(NULL, (css_computed_style *) style,
false, NULL, NULL, NULL, NULL, content->bctx);
if (gen == NULL) {
return;
}
 
/* set box type from computed display */
gen->type = box_map[css_computed_display(
style, box_is_root(n))];
 
box_add_child(box, gen);
}
}
 
/**
* Extract transient construction properties
*
* \param n Current DOM node to convert
* \param props Property object to populate
*/
static void box_extract_properties(dom_node *n,
struct box_construct_props *props)
{
memset(props, 0, sizeof(*props));
 
props->node_is_root = box_is_root(n);
 
/* Extract properties from containing DOM node */
if (props->node_is_root == false) {
dom_node *current_node = n;
dom_node *parent_node = NULL;
struct box *parent_box;
dom_exception err;
 
/* Find ancestor node containing parent box */
while (true) {
err = dom_node_get_parent_node(current_node,
&parent_node);
if (err != DOM_NO_ERR || parent_node == NULL)
break;
 
parent_box = box_for_node(parent_node);
 
if (parent_box != NULL) {
props->parent_style = parent_box->style;
props->href = parent_box->href;
props->target = parent_box->target;
props->title = parent_box->title;
 
dom_node_unref(parent_node);
break;
} else {
if (current_node != n)
dom_node_unref(current_node);
current_node = parent_node;
parent_node = NULL;
}
}
/* Find containing block (may be parent) */
while (true) {
struct box *b;
 
err = dom_node_get_parent_node(current_node,
&parent_node);
if (err != DOM_NO_ERR || parent_node == NULL) {
if (current_node != n)
dom_node_unref(current_node);
break;
}
 
if (current_node != n)
dom_node_unref(current_node);
 
b = box_for_node(parent_node);
 
/* Children of nodes that created an inline box
* will generate boxes which are attached as
* _siblings_ of the box generated for their
* parent node. Note, however, that we'll still
* use the parent node's styling as the parent
* style, above. */
if (b != NULL && b->type != BOX_INLINE &&
b->type != BOX_BR) {
props->containing_block = b;
 
dom_node_unref(parent_node);
break;
} else {
current_node = parent_node;
parent_node = NULL;
}
}
}
 
/* Compute current inline container, if any */
if (props->containing_block != NULL &&
props->containing_block->last != NULL &&
props->containing_block->last->type ==
BOX_INLINE_CONTAINER)
props->inline_container = props->containing_block->last;
}
 
/**
* Construct the box tree for an XML element.
*
* \param ctx Tree construction context
* \param convert_children Whether to convert children
* \return true on success, false on memory exhaustion
*/
 
bool box_construct_element(struct box_construct_ctx *ctx,
bool *convert_children)
{
dom_string *title0, *s;
lwc_string *id = NULL;
struct box *box = NULL, *old_box;
css_select_results *styles = NULL;
struct element_entry *element;
lwc_string *bgimage_uri;
dom_exception err;
struct box_construct_props props;
 
assert(ctx->n != NULL);
 
box_extract_properties(ctx->n, &props);
 
if (props.containing_block != NULL) {
/* In case the containing block is a pre block, we clear
* the PRE_STRIP flag since it is not used if we follow
* the pre with a tag */
props.containing_block->flags &= ~PRE_STRIP;
}
 
styles = box_get_style(ctx->content, props.parent_style, ctx->n);
if (styles == NULL)
return false;
 
/* Extract title attribute, if present */
err = dom_element_get_attribute(ctx->n, kstr_title, &title0);
if (err != DOM_NO_ERR)
return false;
 
if (title0 != NULL) {
char *t = squash_whitespace(dom_string_data(title0));
 
dom_string_unref(title0);
 
if (t == NULL)
return false;
 
props.title = talloc_strdup(ctx->bctx, t);
 
free(t);
 
if (props.title == NULL)
return false;
}
 
/* Extract id attribute, if present */
err = dom_element_get_attribute(ctx->n, kstr_id, &s);
if (err != DOM_NO_ERR)
return false;
 
if (s != NULL) {
err = dom_string_intern(s, &id);
if (err != DOM_NO_ERR)
id = NULL;
 
dom_string_unref(s);
}
 
box = box_create(styles, styles->styles[CSS_PSEUDO_ELEMENT_NONE], false,
props.href, props.target, props.title, id,
ctx->bctx);
if (box == NULL)
return false;
 
/* If this is the root box, add it to the context */
if (props.node_is_root)
ctx->root_box = box;
 
/* Deal with colspan/rowspan */
err = dom_element_get_attribute(ctx->n, kstr_colspan, &s);
if (err != DOM_NO_ERR)
return false;
 
if (s != NULL) {
const char *val = dom_string_data(s);
 
if ('0' <= val[0] && val[0] <= '9')
box->columns = strtol(val, NULL, 10);
 
dom_string_unref(s);
}
 
err = dom_element_get_attribute(ctx->n, kstr_rowspan, &s);
if (err != DOM_NO_ERR)
return false;
 
if (s != NULL) {
const char *val = dom_string_data(s);
 
if ('0' <= val[0] && val[0] <= '9')
box->rows = strtol(val, NULL, 10);
 
dom_string_unref(s);
}
 
/* Set box type from computed display */
if ((css_computed_position(box->style) == CSS_POSITION_ABSOLUTE ||
css_computed_position(box->style) ==
CSS_POSITION_FIXED) &&
(css_computed_display_static(box->style) ==
CSS_DISPLAY_INLINE ||
css_computed_display_static(box->style) ==
CSS_DISPLAY_INLINE_BLOCK ||
css_computed_display_static(box->style) ==
CSS_DISPLAY_INLINE_TABLE)) {
/* Special case for absolute positioning: make absolute inlines
* into inline block so that the boxes are constructed in an
* inline container as if they were not absolutely positioned.
* Layout expects and handles this. */
box->type = box_map[CSS_DISPLAY_INLINE_BLOCK];
} else {
/* Normal mapping */
box->type = box_map[css_computed_display(box->style,
props.node_is_root)];
}
 
/* Handle the :before pseudo element */
box_construct_generate(ctx->n, ctx->content, box,
box->styles->styles[CSS_PSEUDO_ELEMENT_BEFORE]);
 
err = dom_node_get_node_name(ctx->n, &s);
if (err != DOM_NO_ERR || s == NULL)
return false;
 
/* Special elements */
element = bsearch(dom_string_data(s), element_table,
ELEMENT_TABLE_COUNT, sizeof(element_table[0]),
(int (*)(const void *, const void *)) strcasecmp);
 
dom_string_unref(s);
 
if (element != NULL) {
/* A special convert function exists for this element */
if (element->convert(ctx->n, ctx->content, box,
convert_children) == false)
return false;
}
 
if (box->type == BOX_NONE || css_computed_display(box->style,
props.node_is_root) == CSS_DISPLAY_NONE) {
css_select_results_destroy(styles);
box->styles = NULL;
box->style = NULL;
 
/* Invalidate associated gadget, if any */
if (box->gadget != NULL) {
box->gadget->box = NULL;
box->gadget = NULL;
}
 
/* Can't do this, because the lifetimes of boxes and gadgets
* are inextricably linked. Fortunately, talloc will save us
* (for now) */
/* box_free_box(box); */
 
*convert_children = false;
 
return true;
}
 
/* Attach DOM node to box */
err = dom_node_set_user_data(ctx->n, kstr_box_key, box, NULL,
(void *) &old_box);
if (err != DOM_NO_ERR)
return false;
 
/* Attach box to DOM node */
box->node = dom_node_ref(ctx->n);
 
if (props.inline_container == NULL &&
(box->type == BOX_INLINE ||
box->type == BOX_BR ||
box->type == BOX_INLINE_BLOCK ||
css_computed_float(box->style) == CSS_FLOAT_LEFT ||
css_computed_float(box->style) == CSS_FLOAT_RIGHT)) {
/* Found an inline child of a block without a current container
* (i.e. this box is the first child of its parent, or was
* preceded by block-level siblings) */
assert(props.containing_block != NULL &&
"Root box must not be inline or floated");
 
props.inline_container = box_create(NULL, NULL, false, NULL,
NULL, NULL, NULL, ctx->bctx);
if (props.inline_container == NULL)
return false;
 
props.inline_container->type = BOX_INLINE_CONTAINER;
 
box_add_child(props.containing_block, props.inline_container);
}
 
/* Kick off fetch for any background image */
if (css_computed_background_image(box->style, &bgimage_uri) ==
CSS_BACKGROUND_IMAGE_IMAGE && bgimage_uri != NULL &&
nsoption_bool(background_images) == true) {
nsurl *url;
nserror error;
 
/* TODO: we get a url out of libcss as a lwc string, but
* earlier we already had it as a nsurl after we
* nsurl_joined it. Can this be improved?
* For now, just making another nsurl. */
error = nsurl_create(lwc_string_data(bgimage_uri), &url);
if (error != NSERROR_OK)
return false;
 
if (html_fetch_object(ctx->content, url, box, image_types,
ctx->content->base.available_width, 1000,
true) == false) {
nsurl_unref(url);
return false;
}
nsurl_unref(url);
}
 
if (*convert_children)
box->flags |= CONVERT_CHILDREN;
 
if (box->type == BOX_INLINE || box->type == BOX_BR ||
box->type == BOX_INLINE_BLOCK) {
/* Inline container must exist, as we'll have
* created it above if it didn't */
assert(props.inline_container != NULL);
 
box_add_child(props.inline_container, box);
} else {
if (css_computed_display(box->style, props.node_is_root) ==
CSS_DISPLAY_LIST_ITEM) {
/* List item: compute marker */
if (box_construct_marker(box, props.title, ctx,
props.containing_block) == false)
return false;
}
 
if (css_computed_float(box->style) == CSS_FLOAT_LEFT ||
css_computed_float(box->style) ==
CSS_FLOAT_RIGHT) {
/* Float: insert a float between the parent and box. */
struct box *flt = box_create(NULL, NULL, false,
props.href, props.target, props.title,
NULL, ctx->bctx);
if (flt == NULL)
return false;
 
if (css_computed_float(box->style) == CSS_FLOAT_LEFT)
flt->type = BOX_FLOAT_LEFT;
else
flt->type = BOX_FLOAT_RIGHT;
 
box_add_child(props.inline_container, flt);
box_add_child(flt, box);
} else {
/* Non-floated block-level box: add to containing block
* if there is one. If we're the root box, then there
* won't be. */
if (props.containing_block != NULL)
box_add_child(props.containing_block, box);
}
}
 
return true;
}
 
/**
* Complete construction of the box tree for an element.
*
* \param n DOM node to construct for
* \param content Containing document
*
* This will be called after all children of an element have been processed
*/
void box_construct_element_after(dom_node *n, html_content *content)
{
struct box_construct_props props;
struct box *box = box_for_node(n);
 
assert(box != NULL);
 
box_extract_properties(n, &props);
 
if (box->type == BOX_INLINE || box->type == BOX_BR) {
/* Insert INLINE_END into containing block */
struct box *inline_end;
bool has_children;
dom_exception err;
 
err = dom_node_has_child_nodes(n, &has_children);
if (err != DOM_NO_ERR)
return;
 
if (has_children == false ||
(box->flags & CONVERT_CHILDREN) == 0) {
/* No children, or didn't want children converted */
return;
}
 
if (props.inline_container == NULL) {
/* Create inline container if we don't have one */
props.inline_container = box_create(NULL, NULL, false,
NULL, NULL, NULL, NULL, content->bctx);
if (props.inline_container == NULL)
return;
 
props.inline_container->type = BOX_INLINE_CONTAINER;
 
box_add_child(props.containing_block,
props.inline_container);
}
 
inline_end = box_create(NULL, box->style, false,
box->href, box->target, box->title,
box->id == NULL ? NULL :
lwc_string_ref(box->id), content->bctx);
if (inline_end != NULL) {
inline_end->type = BOX_INLINE_END;
 
assert(props.inline_container != NULL);
 
box_add_child(props.inline_container, inline_end);
 
box->inline_end = inline_end;
inline_end->inline_end = box;
}
} else {
/* Handle the :after pseudo element */
box_construct_generate(n, content, box,
box->styles->styles[CSS_PSEUDO_ELEMENT_AFTER]);
}
}
 
/**
* Construct the box tree for an XML text node.
*
* \param ctx Tree construction context
* \return true on success, false on memory exhaustion
*/
 
bool box_construct_text(struct box_construct_ctx *ctx)
{
struct box_construct_props props;
struct box *box = NULL;
dom_string *content;
dom_exception err;
 
assert(ctx->n != NULL);
 
box_extract_properties(ctx->n, &props);
 
assert(props.containing_block != NULL);
 
err = dom_characterdata_get_data(ctx->n, &content);
if (err != DOM_NO_ERR || content == NULL)
return false;
 
if (css_computed_white_space(props.parent_style) ==
CSS_WHITE_SPACE_NORMAL ||
css_computed_white_space(props.parent_style) ==
CSS_WHITE_SPACE_NOWRAP) {
char *text;
 
text = squash_whitespace(dom_string_data(content));
 
dom_string_unref(content);
 
if (text == NULL)
return false;
 
/* if the text is just a space, combine it with the preceding
* text node, if any */
if (text[0] == ' ' && text[1] == 0) {
if (props.inline_container != NULL) {
assert(props.inline_container->last != NULL);
 
props.inline_container->last->space =
UNKNOWN_WIDTH;
}
 
free(text);
 
return true;
}
 
if (props.inline_container == NULL) {
/* Child of a block without a current container
* (i.e. this box is the first child of its parent, or
* was preceded by block-level siblings) */
props.inline_container = box_create(NULL, NULL, false,
NULL, NULL, NULL, NULL, ctx->bctx);
if (props.inline_container == NULL) {
free(text);
return false;
}
 
props.inline_container->type = BOX_INLINE_CONTAINER;
 
box_add_child(props.containing_block,
props.inline_container);
}
 
/** \todo Dropping const here is not clever */
box = box_create(NULL,
(css_computed_style *) props.parent_style,
false, props.href, props.target, props.title,
NULL, ctx->bctx);
if (box == NULL) {
free(text);
return false;
}
 
box->type = BOX_TEXT;
 
box->text = talloc_strdup(ctx->bctx, text);
free(text);
if (box->text == NULL)
return false;
 
box->length = strlen(box->text);
 
/* strip ending space char off */
if (box->length > 1 && box->text[box->length - 1] == ' ') {
box->space = UNKNOWN_WIDTH;
box->length--;
}
 
if (css_computed_text_transform(props.parent_style) !=
CSS_TEXT_TRANSFORM_NONE)
box_text_transform(box->text, box->length,
css_computed_text_transform(
props.parent_style));
 
box_add_child(props.inline_container, box);
 
if (box->text[0] == ' ') {
box->length--;
 
memmove(box->text, &box->text[1], box->length);
 
if (box->prev != NULL)
box->prev->space = UNKNOWN_WIDTH;
}
} else {
/* white-space: pre */
char *text;
size_t text_len = dom_string_byte_length(content);
size_t i;
char *current;
enum css_white_space_e white_space =
css_computed_white_space(props.parent_style);
 
/* note: pre-wrap/pre-line are unimplemented */
assert(white_space == CSS_WHITE_SPACE_PRE ||
white_space == CSS_WHITE_SPACE_PRE_LINE ||
white_space == CSS_WHITE_SPACE_PRE_WRAP);
 
text = malloc(text_len + 1);
dom_string_unref(content);
 
if (text == NULL)
return false;
 
memcpy(text, dom_string_data(content), text_len);
text[text_len] = '\0';
 
/* TODO: Handle tabs properly */
for (i = 0; i < text_len; i++)
if (text[i] == '\t')
text[i] = ' ';
 
if (css_computed_text_transform(props.parent_style) !=
CSS_TEXT_TRANSFORM_NONE)
box_text_transform(text, strlen(text),
css_computed_text_transform(
props.parent_style));
 
current = text;
 
/* swallow a single leading new line */
if (props.containing_block->flags & PRE_STRIP) {
switch (*current) {
case '\n':
current++;
break;
case '\r':
current++;
if (*current == '\n')
current++;
break;
}
props.containing_block->flags &= ~PRE_STRIP;
}
 
do {
size_t len = strcspn(current, "\r\n");
 
char old = current[len];
 
current[len] = 0;
 
if (props.inline_container == NULL) {
/* Child of a block without a current container
* (i.e. this box is the first child of its
* parent, or was preceded by block-level
* siblings) */
props.inline_container = box_create(NULL, NULL,
false, NULL, NULL, NULL, NULL,
ctx->bctx);
if (props.inline_container == NULL) {
free(text);
return false;
}
 
props.inline_container->type =
BOX_INLINE_CONTAINER;
 
box_add_child(props.containing_block,
props.inline_container);
}
 
/** \todo Dropping const isn't clever */
box = box_create(NULL,
(css_computed_style *) props.parent_style,
false, props.href, props.target, props.title,
NULL, ctx->bctx);
if (box == NULL) {
free(text);
return false;
}
 
box->type = BOX_TEXT;
 
box->text = talloc_strdup(ctx->bctx, current);
if (box->text == NULL) {
free(text);
return false;
}
 
box->length = strlen(box->text);
 
box_add_child(props.inline_container, box);
 
current[len] = old;
 
current += len;
 
if (current[0] != '\0') {
/* Linebreak: create new inline container */
props.inline_container = box_create(NULL, NULL,
false, NULL, NULL, NULL, NULL,
ctx->bctx);
if (props.inline_container == NULL) {
free(text);
return false;
}
 
props.inline_container->type =
BOX_INLINE_CONTAINER;
 
box_add_child(props.containing_block,
props.inline_container);
 
if (current[0] == '\r' && current[1] == '\n')
current += 2;
else
current++;
}
} while (*current);
 
free(text);
}
 
return true;
}
 
/**
* Get the style for an element.
*
* \param c content of type CONTENT_HTML that is being processed
* \param parent_style style at this point in xml tree, or NULL for root
* \param n node in xml tree
* \return the new style, or NULL on memory exhaustion
*/
css_select_results *box_get_style(html_content *c,
const css_computed_style *parent_style, dom_node *n)
{
dom_string *s;
dom_exception err;
int pseudo_element;
css_error error;
css_stylesheet *inline_style = NULL;
css_select_results *styles;
nscss_select_ctx ctx;
 
/* Firstly, construct inline stylesheet, if any */
err = dom_element_get_attribute(n, kstr_style, &s);
if (err != DOM_NO_ERR)
return NULL;
 
if (s != NULL) {
inline_style = nscss_create_inline_style(
(const uint8_t *) dom_string_data(s),
dom_string_byte_length(s),
c->encoding,
nsurl_access(content_get_url(&c->base)),
c->quirks != DOM_DOCUMENT_QUIRKS_MODE_NONE,
box_style_alloc, NULL);
 
dom_string_unref(s);
 
if (inline_style == NULL)
return NULL;
}
 
/* Populate selection context */
ctx.ctx = c->select_ctx;
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
 
/* Select partial style for element */
styles = nscss_get_style(&ctx, n, CSS_MEDIA_SCREEN, inline_style,
box_style_alloc, NULL);
 
/* No longer need inline style */
if (inline_style != NULL)
css_stylesheet_destroy(inline_style);
 
/* Failed selecting partial style -- bail out */
if (styles == NULL)
return NULL;
 
/* If there's a parent style, compose with partial to obtain
* complete computed style for element */
if (parent_style != NULL) {
/* Complete the computed style, by composing with the parent
* element's style */
error = css_computed_style_compose(parent_style,
styles->styles[CSS_PSEUDO_ELEMENT_NONE],
nscss_compute_font_size, NULL,
styles->styles[CSS_PSEUDO_ELEMENT_NONE]);
if (error != CSS_OK) {
css_select_results_destroy(styles);
return NULL;
}
}
 
for (pseudo_element = CSS_PSEUDO_ELEMENT_NONE + 1;
pseudo_element < CSS_PSEUDO_ELEMENT_COUNT;
pseudo_element++) {
 
if (pseudo_element == CSS_PSEUDO_ELEMENT_FIRST_LETTER ||
pseudo_element == CSS_PSEUDO_ELEMENT_FIRST_LINE)
/* TODO: Handle first-line and first-letter pseudo
* element computed style completion */
continue;
 
if (styles->styles[pseudo_element] == NULL)
/* There were no rules concerning this pseudo element */
continue;
 
/* Complete the pseudo element's computed style, by composing
* with the base element's style */
error = css_computed_style_compose(
styles->styles[CSS_PSEUDO_ELEMENT_NONE],
styles->styles[pseudo_element],
nscss_compute_font_size, NULL,
styles->styles[pseudo_element]);
if (error != CSS_OK) {
/* TODO: perhaps this shouldn't be quite so
* catastrophic? */
css_select_results_destroy(styles);
return NULL;
}
}
 
return styles;
}
 
 
/**
* Apply the CSS text-transform property to given text for its ASCII chars.
*
* \param s string to transform
* \param len length of s
* \param tt transform type
*/
 
void box_text_transform(char *s, unsigned int len, enum css_text_transform_e tt)
{
unsigned int i;
if (len == 0)
return;
switch (tt) {
case CSS_TEXT_TRANSFORM_UPPERCASE:
for (i = 0; i < len; ++i)
if ((unsigned char) s[i] < 0x80)
s[i] = ls_toupper(s[i]);
break;
case CSS_TEXT_TRANSFORM_LOWERCASE:
for (i = 0; i < len; ++i)
if ((unsigned char) s[i] < 0x80)
s[i] = ls_tolower(s[i]);
break;
case CSS_TEXT_TRANSFORM_CAPITALIZE:
if ((unsigned char) s[0] < 0x80)
s[0] = ls_toupper(s[0]);
for (i = 1; i < len; ++i)
if ((unsigned char) s[i] < 0x80 &&
ls_isspace(s[i - 1]))
s[i] = ls_toupper(s[i]);
break;
default:
break;
}
}
 
 
/**
* \name Special case element handlers
*
* These functions are called by box_construct_element() when an element is
* being converted, according to the entries in element_table.
*
* The parameters are the xmlNode, the content for the document, and a partly
* filled in box structure for the element.
*
* Return true on success, false on memory exhaustion. Set *convert_children
* to false if children of this element in the XML tree should be skipped (for
* example, if they have been processed in some special way already).
*
* Elements ordered as in the HTML 4.01 specification. Section numbers in
* brackets [] refer to the spec.
*
* \{
*/
 
/**
* Document body [7.5.1].
*/
 
bool box_body(BOX_SPECIAL_PARAMS)
{
css_color color;
 
css_computed_background_color(box->style, &color);
if (nscss_color_is_transparent(color))
content->background_colour = NS_TRANSPARENT;
else
content->background_colour = nscss_color_to_ns(color);
 
return true;
}
 
 
/**
* Forced line break [9.3.2].
*/
 
bool box_br(BOX_SPECIAL_PARAMS)
{
box->type = BOX_BR;
return true;
}
 
/**
* Preformatted text [9.3.4].
*/
 
bool box_pre(BOX_SPECIAL_PARAMS)
{
box->flags |= PRE_STRIP;
return true;
}
 
/**
* Anchor [12.2].
*/
 
bool box_a(BOX_SPECIAL_PARAMS)
{
bool ok;
nsurl *url;
dom_string *s;
dom_exception err;
 
err = dom_element_get_attribute(n, kstr_href, &s);
if (err == DOM_NO_ERR && s != NULL) {
ok = box_extract_link(dom_string_data(s),
content->base_url, &url);
dom_string_unref(s);
if (!ok)
return false;
if (url) {
if (box->href != NULL)
nsurl_unref(box->href);
box->href = url;
}
}
 
/* name and id share the same namespace */
err = dom_element_get_attribute(n, kstr_name, &s);
if (err == DOM_NO_ERR && s != NULL) {
lwc_string *lwc_name;
 
err = dom_string_intern(s, &lwc_name);
 
dom_string_unref(s);
 
if (err == DOM_NO_ERR) {
/* name replaces existing id
* TODO: really? */
if (box->id != NULL)
lwc_string_unref(box->id);
 
box->id = lwc_name;
}
}
 
/* target frame [16.3] */
err = dom_element_get_attribute(n, kstr_target, &s);
if (err == DOM_NO_ERR && s != NULL) {
if (dom_string_caseless_lwc_isequal(s,
corestring_lwc__blank))
box->target = TARGET_BLANK;
else if (dom_string_caseless_lwc_isequal(s,
corestring_lwc__top))
box->target = TARGET_TOP;
else if (dom_string_caseless_lwc_isequal(s,
corestring_lwc__parent))
box->target = TARGET_PARENT;
else if (dom_string_caseless_lwc_isequal(s,
corestring_lwc__self))
/* the default may have been overridden by a
* <base target=...>, so this is different to 0 */
box->target = TARGET_SELF;
else {
/* 6.16 says that frame names must begin with [a-zA-Z]
* This doesn't match reality, so just take anything */
box->target = talloc_strdup(content->bctx,
dom_string_data(s));
if (!box->target) {
dom_string_unref(s);
return false;
}
}
dom_string_unref(s);
}
 
return true;
}
 
 
/**
* Embedded image [13.2].
*/
 
bool box_image(BOX_SPECIAL_PARAMS)
{
bool ok;
dom_string *s;
dom_exception err;
nsurl *url;
enum css_width_e wtype;
enum css_height_e htype;
css_fixed value = 0;
css_unit wunit = CSS_UNIT_PX;
css_unit hunit = CSS_UNIT_PX;
 
if (box->style && css_computed_display(box->style,
box_is_root(n)) == CSS_DISPLAY_NONE)
return true;
 
/* handle alt text */
err = dom_element_get_attribute(n, kstr_alt, &s);
if (err == DOM_NO_ERR && s != NULL) {
char *alt = squash_whitespace(dom_string_data(s));
dom_string_unref(s);
if (alt == NULL)
return false;
box->text = talloc_strdup(content->bctx, alt);
free(alt);
if (box->text == NULL)
return false;
box->length = strlen(box->text);
}
 
if (nsoption_bool(foreground_images) == false) {
return true;
}
 
/* imagemap associated with this image */
if (!box_get_attribute(n, "usemap", content->bctx, &box->usemap))
return false;
if (box->usemap && box->usemap[0] == '#')
box->usemap++;
 
/* get image URL */
err = dom_element_get_attribute(n, kstr_src, &s);
if (err != DOM_NO_ERR || s == NULL)
return true;
 
if (box_extract_link(dom_string_data(s), content->base_url,
&url) == false) {
dom_string_unref(s);
return false;
}
 
dom_string_unref(s);
 
if (url == NULL)
return true;
 
/* start fetch */
ok = html_fetch_object(content, url, box, image_types,
content->base.available_width, 1000, false);
nsurl_unref(url);
 
wtype = css_computed_width(box->style, &value, &wunit);
htype = css_computed_height(box->style, &value, &hunit);
 
if (wtype == CSS_WIDTH_SET && wunit != CSS_UNIT_PCT &&
htype == CSS_HEIGHT_SET && hunit != CSS_UNIT_PCT) {
/* We know the dimensions the image will be shown at before it's
* fetched. */
box->flags |= REPLACE_DIM;
}
 
return ok;
}
 
 
/**
* Noscript element
*/
 
bool box_noscript(BOX_SPECIAL_PARAMS)
{
/* If scripting is enabled, do not display the contents of noscript */
if (nsoption_bool(enable_javascript))
*convert_children = false;
 
return true;
}
 
 
/**
* Destructor for object_params, for <object> elements
*
* \param b The object params being destroyed.
* \return 0 to allow talloc to continue destroying the tree.
*/
static int box_object_talloc_destructor(struct object_params *o)
{
if (o->codebase != NULL)
nsurl_unref(o->codebase);
if (o->classid != NULL)
nsurl_unref(o->classid);
if (o->data != NULL)
nsurl_unref(o->data);
return 0;
}
 
/**
* Generic embedded object [13.3].
*/
 
bool box_object(BOX_SPECIAL_PARAMS)
{
struct object_params *params;
struct object_param *param;
dom_string *codebase, *classid, *data;
dom_node *c;
dom_exception err;
 
if (box->style && css_computed_display(box->style,
box_is_root(n)) == CSS_DISPLAY_NONE)
return true;
 
if (box_get_attribute(n, "usemap", content->bctx, &box->usemap) ==
false)
return false;
if (box->usemap && box->usemap[0] == '#')
box->usemap++;
 
params = talloc(content->bctx, struct object_params);
if (params == NULL)
return false;
 
talloc_set_destructor(params, box_object_talloc_destructor);
 
params->data = NULL;
params->type = NULL;
params->codetype = NULL;
params->codebase = NULL;
params->classid = NULL;
params->params = NULL;
 
/* codebase, classid, and data are URLs
* (codebase is the base for the other two) */
err = dom_element_get_attribute(n, kstr_codebase, &codebase);
if (err == DOM_NO_ERR && codebase != NULL) {
if (box_extract_link(dom_string_data(codebase),
content->base_url,
&params->codebase) == false) {
dom_string_unref(codebase);
return false;
}
dom_string_unref(codebase);
}
if (params->codebase == NULL)
params->codebase = nsurl_ref(content->base_url);
 
err = dom_element_get_attribute(n, kstr_classid, &classid);
if (err == DOM_NO_ERR && classid != NULL) {
if (box_extract_link(dom_string_data(classid), params->codebase,
&params->classid) == false) {
dom_string_unref(classid);
return false;
}
dom_string_unref(classid);
}
 
err = dom_element_get_attribute(n, kstr_data, &data);
if (err == DOM_NO_ERR && data != NULL) {
if (box_extract_link(dom_string_data(data), params->codebase,
&params->data) == false) {
dom_string_unref(data);
return false;
}
dom_string_unref(data);
}
 
if (params->classid == NULL && params->data == NULL)
/* nothing to embed; ignore */
return true;
 
/* Don't include ourself */
if (params->classid != NULL && nsurl_compare(content->base_url,
params->classid, NSURL_COMPLETE))
return true;
 
if (params->data != NULL && nsurl_compare(content->base_url,
params->data, NSURL_COMPLETE))
return true;
 
/* codetype and type are MIME types */
if (box_get_attribute(n, "codetype", params,
&params->codetype) == false)
return false;
if (box_get_attribute(n, "type", params, &params->type) == false)
return false;
 
/* classid && !data => classid is used (consult codetype)
* (classid || !classid) && data => data is used (consult type)
* !classid && !data => invalid; ignored */
 
if (params->classid != NULL && params->data == NULL &&
params->codetype != NULL) {
lwc_string *icodetype;
lwc_error lerror;
 
lerror = lwc_intern_string(params->codetype,
strlen(params->codetype), &icodetype);
if (lerror != lwc_error_ok)
return false;
 
if (content_factory_type_from_mime_type(icodetype) ==
CONTENT_NONE) {
/* can't handle this MIME type */
lwc_string_unref(icodetype);
return true;
}
 
lwc_string_unref(icodetype);
}
 
if (params->data != NULL && params->type != NULL) {
lwc_string *itype;
lwc_error lerror;
 
lerror = lwc_intern_string(params->type, strlen(params->type),
&itype);
if (lerror != lwc_error_ok)
return false;
 
if (content_factory_type_from_mime_type(itype) ==
CONTENT_NONE) {
/* can't handle this MIME type */
lwc_string_unref(itype);
return true;
}
 
lwc_string_unref(itype);
}
 
/* add parameters to linked list */
err = dom_node_get_first_child(n, &c);
if (err != DOM_NO_ERR)
return false;
 
while (c != NULL) {
dom_node *next;
dom_node_type type;
 
err = dom_node_get_node_type(c, &type);
if (err != DOM_NO_ERR) {
dom_node_unref(c);
return false;
}
 
if (type == DOM_ELEMENT_NODE) {
dom_string *name;
 
err = dom_node_get_node_name(c, &name);
if (err != DOM_NO_ERR) {
dom_node_unref(c);
return false;
}
 
if (!dom_string_caseless_lwc_isequal(name,
corestring_lwc_param)) {
/* The first non-param child is the start of
* the alt html. Therefore, we should break
* out of this loop. */
dom_node_unref(c);
break;
}
 
param = talloc(params, struct object_param);
if (param == NULL) {
dom_node_unref(c);
return false;
}
param->name = NULL;
param->value = NULL;
param->type = NULL;
param->valuetype = NULL;
param->next = NULL;
 
if (box_get_attribute(c, "name", param,
&param->name) == false) {
dom_node_unref(c);
return false;
}
 
if (box_get_attribute(c, "value", param,
&param->value) == false) {
dom_node_unref(c);
return false;
}
 
if (box_get_attribute(c, "type", param,
&param->type) == false) {
dom_node_unref(c);
return false;
}
 
if (box_get_attribute(c, "valuetype", param,
&param->valuetype) == false) {
dom_node_unref(c);
return false;
}
 
if (param->valuetype == NULL) {
param->valuetype = talloc_strdup(param, "data");
if (param->valuetype == NULL) {
dom_node_unref(c);
return false;
}
}
 
param->next = params->params;
params->params = param;
}
 
err = dom_node_get_next_sibling(c, &next);
if (err != DOM_NO_ERR) {
dom_node_unref(c);
return false;
}
 
dom_node_unref(c);
c = next;
}
 
box->object_params = params;
 
/* start fetch (MIME type is ok or not specified) */
if (!html_fetch_object(content,
params->data ? params->data : params->classid,
box, CONTENT_ANY, content->base.available_width, 1000,
false))
return false;
 
*convert_children = false;
return true;
}
 
 
/**
* Window subdivision [16.2.1].
*/
 
bool box_frameset(BOX_SPECIAL_PARAMS)
{
bool ok;
 
if (content->frameset) {
LOG(("Error: multiple framesets in document."));
/* Don't convert children */
if (convert_children)
*convert_children = false;
/* And ignore this spurious frameset */
box->type = BOX_NONE;
return true;
}
 
content->frameset = talloc_zero(content->bctx, struct content_html_frames);
if (!content->frameset)
return false;
 
ok = box_create_frameset(content->frameset, n, content);
if (ok)
box->type = BOX_NONE;
 
if (convert_children)
*convert_children = false;
return ok;
}
 
 
/**
* Destructor for content_html_frames, for <frame> elements
*
* \param b The frame params being destroyed.
* \return 0 to allow talloc to continue destroying the tree.
*/
static int box_frames_talloc_destructor(struct content_html_frames *f)
{
if (f->url != NULL) {
nsurl_unref(f->url);
f->url = NULL;
}
return 0;
}
 
bool box_create_frameset(struct content_html_frames *f, dom_node *n,
html_content *content) {
unsigned int row, col, index, i;
unsigned int rows = 1, cols = 1;
dom_string *s;
dom_exception err;
nsurl *url;
struct frame_dimension *row_height = 0, *col_width = 0;
dom_node *c, *next;
struct content_html_frames *frame;
bool default_border = true;
colour default_border_colour = 0x000000;
 
/* parse rows and columns */
err = dom_element_get_attribute(n, kstr_rows, &s);
if (err == DOM_NO_ERR && s != NULL) {
row_height = box_parse_multi_lengths(dom_string_data(s), &rows);
dom_string_unref(s);
if (row_height == NULL)
return false;
} else {
row_height = calloc(1, sizeof(struct frame_dimension));
if (row_height == NULL)
return false;
row_height->value = 100;
row_height->unit = FRAME_DIMENSION_PERCENT;
}
 
err = dom_element_get_attribute(n, kstr_cols, &s);
if (err == DOM_NO_ERR && s != NULL) {
col_width = box_parse_multi_lengths(dom_string_data(s), &cols);
dom_string_unref(s);
if (col_width == NULL)
return false;
} else {
col_width = calloc(1, sizeof(struct frame_dimension));
if (col_width == NULL)
return false;
col_width->value = 100;
col_width->unit = FRAME_DIMENSION_PERCENT;
}
 
/* common extension: border="0|1" to control all children */
err = dom_element_get_attribute(n, kstr_border, &s);
if (err == DOM_NO_ERR && s != NULL) {
if ((dom_string_data(s)[0] == '0') &&
(dom_string_data(s)[1] == '\0'))
default_border = false;
dom_string_unref(s);
}
 
/* common extension: frameborder="yes|no" to control all children */
err = dom_element_get_attribute(n, kstr_frameborder, &s);
if (err == DOM_NO_ERR && s != NULL) {
if (dom_string_caseless_lwc_isequal(s,
corestring_lwc_no) == 0)
default_border = false;
dom_string_unref(s);
}
 
/* common extension: bordercolor="#RRGGBB|<named colour>" to control
*all children */
err = dom_element_get_attribute(n, kstr_bordercolor, &s);
if (err == DOM_NO_ERR && s != NULL) {
css_color color;
 
if (nscss_parse_colour(dom_string_data(s), &color))
default_border_colour = nscss_color_to_ns(color);
 
dom_string_unref(s);
}
 
/* update frameset and create default children */
f->cols = cols;
f->rows = rows;
f->scrolling = SCROLLING_NO;
f->children = talloc_array(content->bctx, struct content_html_frames,
(rows * cols));
 
talloc_set_destructor(f->children, box_frames_talloc_destructor);
 
for (row = 0; row < rows; row++) {
for (col = 0; col < cols; col++) {
index = (row * cols) + col;
frame = &f->children[index];
frame->cols = 0;
frame->rows = 0;
frame->width = col_width[col];
frame->height = row_height[row];
frame->margin_width = 0;
frame->margin_height = 0;
frame->name = NULL;
frame->url = NULL;
frame->no_resize = false;
frame->scrolling = SCROLLING_AUTO;
frame->border = default_border;
frame->border_colour = default_border_colour;
frame->children = NULL;
}
}
free(col_width);
free(row_height);
 
/* create the frameset windows */
err = dom_node_get_first_child(n, &c);
if (err != DOM_NO_ERR)
return false;
 
for (row = 0; c != NULL && row < rows; row++) {
for (col = 0; c != NULL && col < cols; col++) {
while (c != NULL) {
dom_node_type type;
dom_string *name;
 
err = dom_node_get_node_type(c, &type);
if (err != DOM_NO_ERR) {
dom_node_unref(c);
return false;
}
 
err = dom_node_get_node_name(c, &name);
if (err != DOM_NO_ERR) {
dom_node_unref(c);
return false;
}
 
if (type != DOM_ELEMENT_NODE ||
(!dom_string_caseless_lwc_isequal(
name,
corestring_lwc_frame) &&
!dom_string_caseless_lwc_isequal(
name,
corestring_lwc_frameset
))) {
err = dom_node_get_next_sibling(c,
&next);
if (err != DOM_NO_ERR) {
dom_node_unref(c);
return false;
}
 
dom_node_unref(c);
c = next;
} else {
/* Got a FRAME or FRAMESET element */
break;
}
}
 
if (c == NULL)
break;
 
/* get current frame */
index = (row * cols) + col;
frame = &f->children[index];
 
/* nest framesets */
err = dom_node_get_node_name(c, &s);
if (err != DOM_NO_ERR) {
dom_node_unref(c);
return false;
}
 
if (dom_string_caseless_lwc_isequal(s,
corestring_lwc_frameset)) {
dom_string_unref(s);
frame->border = 0;
if (box_create_frameset(frame, c,
content) == false) {
dom_node_unref(c);
return false;
}
 
err = dom_node_get_next_sibling(c, &next);
if (err != DOM_NO_ERR) {
dom_node_unref(c);
return false;
}
 
dom_node_unref(c);
c = next;
continue;
}
 
dom_string_unref(s);
 
/* get frame URL (not required) */
url = NULL;
err = dom_element_get_attribute(c, kstr_src, &s);
if (err == DOM_NO_ERR && s != NULL) {
box_extract_link(dom_string_data(s),
content->base_url, &url);
dom_string_unref(s);
}
 
/* copy url */
if (url != NULL) {
/* no self-references */
if (nsurl_compare(content->base_url, url,
NSURL_COMPLETE) == false)
frame->url = url;
url = NULL;
}
 
/* fill in specified values */
err = dom_element_get_attribute(c, kstr_name, &s);
if (err == DOM_NO_ERR && s != NULL) {
frame->name = talloc_strdup(content->bctx,
dom_string_data(s));
dom_string_unref(s);
}
 
dom_element_has_attribute(c, kstr_noresize,
&frame->no_resize);
 
err = dom_element_get_attribute(c, kstr_frameborder,
&s);
if (err == DOM_NO_ERR && s != NULL) {
i = atoi(dom_string_data(s));
frame->border = (i != 0);
dom_string_unref(s);
}
 
err = dom_element_get_attribute(c, kstr_scrolling, &s);
if (err == DOM_NO_ERR && s != NULL) {
if (dom_string_caseless_lwc_isequal(s,
corestring_lwc_yes))
frame->scrolling = SCROLLING_YES;
else if (dom_string_caseless_lwc_isequal(s,
corestring_lwc_no))
frame->scrolling = SCROLLING_NO;
dom_string_unref(s);
}
 
err = dom_element_get_attribute(c, kstr_marginwidth,
&s);
if (err == DOM_NO_ERR && s != NULL) {
frame->margin_width = atoi(dom_string_data(s));
dom_string_unref(s);
}
 
err = dom_element_get_attribute(c, kstr_marginheight,
&s);
if (err == DOM_NO_ERR && s != NULL) {
frame->margin_height = atoi(dom_string_data(s));
dom_string_unref(s);
}
 
err = dom_element_get_attribute(c, kstr_bordercolor,
&s);
if (err == DOM_NO_ERR && s != NULL) {
css_color color;
 
if (nscss_parse_colour(dom_string_data(s),
&color))
frame->border_colour =
nscss_color_to_ns(color);
 
dom_string_unref(s);
}
 
/* advance */
err = dom_node_get_next_sibling(c, &next);
if (err != DOM_NO_ERR) {
dom_node_unref(c);
return false;
}
 
dom_node_unref(c);
c = next;
}
}
 
return true;
}
 
 
/**
* Destructor for content_html_iframe, for <iframe> elements
*
* \param b The iframe params being destroyed.
* \return 0 to allow talloc to continue destroying the tree.
*/
static int box_iframes_talloc_destructor(struct content_html_iframe *f)
{
if (f->url != NULL) {
nsurl_unref(f->url);
f->url = NULL;
}
return 0;
}
 
 
/**
* Inline subwindow [16.5].
*/
 
bool box_iframe(BOX_SPECIAL_PARAMS)
{
nsurl *url;
dom_string *s;
dom_exception err;
struct content_html_iframe *iframe;
int i;
 
if (box->style && css_computed_display(box->style,
box_is_root(n)) == CSS_DISPLAY_NONE)
return true;
 
if (box->style && css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)
/* Don't create iframe discriptors for invisible iframes
* TODO: handle hidden iframes at browser_window generation
* time instead? */
return true;
 
/* get frame URL */
err = dom_element_get_attribute(n, kstr_src, &s);
if (err != DOM_NO_ERR || s == NULL)
return true;
if (box_extract_link(dom_string_data(s), content->base_url,
&url) == false) {
dom_string_unref(s);
return false;
}
dom_string_unref(s);
if (url == NULL)
return true;
 
/* don't include ourself */
if (nsurl_compare(content->base_url, url, NSURL_COMPLETE)) {
nsurl_unref(url);
return true;
}
 
/* create a new iframe */
iframe = talloc(content->bctx, struct content_html_iframe);
if (iframe == NULL) {
nsurl_unref(url);
return false;
}
 
talloc_set_destructor(iframe, box_iframes_talloc_destructor);
 
iframe->box = box;
iframe->margin_width = 0;
iframe->margin_height = 0;
iframe->name = NULL;
iframe->url = url;
iframe->scrolling = SCROLLING_AUTO;
iframe->border = true;
 
/* Add this iframe to the linked list of iframes */
iframe->next = content->iframe;
content->iframe = iframe;
 
/* fill in specified values */
err = dom_element_get_attribute(n, kstr_name, &s);
if (err == DOM_NO_ERR && s != NULL) {
iframe->name = talloc_strdup(content->bctx, dom_string_data(s));
dom_string_unref(s);
}
 
err = dom_element_get_attribute(n, kstr_frameborder, &s);
if (err == DOM_NO_ERR && s != NULL) {
i = atoi(dom_string_data(s));
iframe->border = (i != 0);
dom_string_unref(s);
}
 
err = dom_element_get_attribute(n, kstr_bordercolor, &s);
if (err == DOM_NO_ERR && s != NULL) {
css_color color;
 
if (nscss_parse_colour(dom_string_data(s), &color))
iframe->border_colour = nscss_color_to_ns(color);
 
dom_string_unref(s);
}
 
err = dom_element_get_attribute(n, kstr_scrolling, &s);
if (err == DOM_NO_ERR && s != NULL) {
if (dom_string_caseless_lwc_isequal(s,
corestring_lwc_yes))
iframe->scrolling = SCROLLING_YES;
else if (dom_string_caseless_lwc_isequal(s,
corestring_lwc_no))
iframe->scrolling = SCROLLING_NO;
dom_string_unref(s);
}
 
err = dom_element_get_attribute(n, kstr_marginwidth, &s);
if (err == DOM_NO_ERR && s != NULL) {
iframe->margin_width = atoi(dom_string_data(s));
dom_string_unref(s);
}
 
err = dom_element_get_attribute(n, kstr_marginheight, &s);
if (err == DOM_NO_ERR && s != NULL) {
iframe->margin_height = atoi(dom_string_data(s));
dom_string_unref(s);
}
 
/* box */
assert(box->style);
box->flags |= IFRAME;
 
/* Showing iframe, so don't show alternate content */
if (convert_children)
*convert_children = false;
return true;
}
 
 
/**
* Form control [17.4].
*/
 
bool box_input(BOX_SPECIAL_PARAMS)
{
struct form_control *gadget = NULL;
dom_string *type = NULL;
dom_exception err;
nsurl *url;
nserror error;
 
dom_element_get_attribute(n, kstr_type, &type);
 
gadget = html_forms_get_control_for_node(content->forms, n);
if (gadget == NULL)
goto no_memory;
box->gadget = gadget;
gadget->box = box;
 
if (type && dom_string_caseless_lwc_isequal(type,
corestring_lwc_password)) {
if (box_input_text(n, content, box, 0, true) == false)
goto no_memory;
 
} else if (type && dom_string_caseless_lwc_isequal(type,
corestring_lwc_file)) {
box->type = BOX_INLINE_BLOCK;
 
} else if (type && dom_string_caseless_lwc_isequal(type,
corestring_lwc_hidden)) {
/* no box for hidden inputs */
box->type = BOX_NONE;
 
} else if (type &&
(dom_string_caseless_lwc_isequal(type,
corestring_lwc_checkbox) ||
dom_string_caseless_lwc_isequal(type,
corestring_lwc_radio))) {
 
} else if (type &&
(dom_string_caseless_lwc_isequal(type,
corestring_lwc_submit) ||
dom_string_caseless_lwc_isequal(type,
corestring_lwc_reset) ||
dom_string_caseless_lwc_isequal(type,
corestring_lwc_button))) {
struct box *inline_container, *inline_box;
 
if (box_button(n, content, box, 0) == false)
goto no_memory;
 
inline_container = box_create(NULL, 0, false, 0, 0, 0, 0,
content->bctx);
if (inline_container == NULL)
goto no_memory;
 
inline_container->type = BOX_INLINE_CONTAINER;
 
inline_box = box_create(NULL, box->style, false, 0, 0,
box->title, 0, content->bctx);
if (inline_box == NULL)
goto no_memory;
 
inline_box->type = BOX_TEXT;
 
if (box->gadget->value != NULL)
inline_box->text = talloc_strdup(content->bctx,
box->gadget->value);
else if (box->gadget->type == GADGET_SUBMIT)
inline_box->text = talloc_strdup(content->bctx,
messages_get("Form_Submit"));
else if (box->gadget->type == GADGET_RESET)
inline_box->text = talloc_strdup(content->bctx,
messages_get("Form_Reset"));
else
inline_box->text = talloc_strdup(content->bctx,
"Button");
 
if (inline_box->text == NULL)
goto no_memory;
 
inline_box->length = strlen(inline_box->text);
 
box_add_child(inline_container, inline_box);
 
box_add_child(box, inline_container);
 
} else if (type && dom_string_caseless_lwc_isequal(type,
corestring_lwc_image)) {
gadget->type = GADGET_IMAGE;
 
if (box->style && css_computed_display(box->style,
box_is_root(n)) != CSS_DISPLAY_NONE &&
nsoption_bool(foreground_images) == true) {
dom_string *s;
 
err = dom_element_get_attribute(n, kstr_src, &s);
if (err == DOM_NO_ERR && s != NULL) {
error = nsurl_join(content->base_url,
dom_string_data(s), &url);
dom_string_unref(s);
if (error != NSERROR_OK)
goto no_memory;
 
/* if url is equivalent to the parent's url,
* we've got infinite inclusion. stop it here
*/
if (nsurl_compare(url, content->base_url,
NSURL_COMPLETE) == false) {
if (!html_fetch_object(content, url,
box, image_types,
content->base.
available_width,
1000, false)) {
nsurl_unref(url);
goto no_memory;
}
}
nsurl_unref(url);
}
}
} else {
/* the default type is "text" */
if (box_input_text(n, content, box, 0, false) == false)
goto no_memory;
}
 
if (type)
dom_string_unref(type);
 
*convert_children = false;
return true;
 
no_memory:
if (type)
dom_string_unref(type);
 
return false;
}
 
 
/**
* Helper function for box_input().
*/
 
bool box_input_text(BOX_SPECIAL_PARAMS, bool password)
{
struct box *inline_container, *inline_box;
 
box->type = BOX_INLINE_BLOCK;
 
inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, content->bctx);
if (!inline_container)
return false;
inline_container->type = BOX_INLINE_CONTAINER;
inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0,
content->bctx);
if (!inline_box)
return false;
inline_box->type = BOX_TEXT;
if (password) {
inline_box->length = strlen(box->gadget->value);
inline_box->text = talloc_array(content->bctx, char,
inline_box->length + 1);
if (!inline_box->text)
return false;
memset(inline_box->text, '*', inline_box->length);
inline_box->text[inline_box->length] = '\0';
} else {
/* replace spaces/TABs with hard spaces to prevent line
* wrapping */
char *text = cnv_space2nbsp(box->gadget->value);
if (!text)
return false;
inline_box->text = talloc_strdup(content->bctx, text);
free(text);
if (!inline_box->text)
return false;
inline_box->length = strlen(inline_box->text);
}
box_add_child(inline_container, inline_box);
box_add_child(box, inline_container);
 
return true;
}
 
 
/**
* Push button [17.5].
*/
 
bool box_button(BOX_SPECIAL_PARAMS)
{
struct form_control *gadget;
 
gadget = html_forms_get_control_for_node(content->forms, n);
if (!gadget)
return false;
 
box->gadget = gadget;
gadget->box = box;
 
box->type = BOX_INLINE_BLOCK;
 
/* Just render the contents */
 
return true;
}
 
 
/**
* Option selector [17.6].
*/
 
bool box_select(BOX_SPECIAL_PARAMS)
{
struct box *inline_container;
struct box *inline_box;
struct form_control *gadget;
dom_node *c, *c2;
dom_node *next, *next2;
dom_exception err;
 
gadget = html_forms_get_control_for_node(content->forms, n);
if (gadget == NULL)
return false;
 
err = dom_node_get_first_child(n, &c);
if (err != DOM_NO_ERR)
return false;
 
while (c != NULL) {
dom_string *name;
 
err = dom_node_get_node_name(c, &name);
if (err != DOM_NO_ERR) {
dom_node_unref(c);
return false;
}
 
if (dom_string_caseless_lwc_isequal(name,
corestring_lwc_option)) {
dom_string_unref(name);
 
if (box_select_add_option(gadget, c) == false) {
dom_node_unref(c);
goto no_memory;
}
} else if (dom_string_caseless_lwc_isequal(name,
corestring_lwc_optgroup)) {
dom_string_unref(name);
 
err = dom_node_get_first_child(c, &c2);
if (err != DOM_NO_ERR) {
dom_node_unref(c);
return false;
}
 
while (c2 != NULL) {
dom_string *c2_name;
 
err = dom_node_get_node_name(c2, &c2_name);
if (err != DOM_NO_ERR) {
dom_node_unref(c2);
dom_node_unref(c);
return false;
}
if (dom_string_caseless_lwc_isequal(c2_name,
corestring_lwc_option)) {
dom_string_unref(c2_name);
 
if (box_select_add_option(gadget,
c2) == false) {
dom_node_unref(c2);
dom_node_unref(c);
goto no_memory;
}
} else {
dom_string_unref(c2_name);
}
 
err = dom_node_get_next_sibling(c2, &next2);
if (err != DOM_NO_ERR) {
dom_node_unref(c2);
dom_node_unref(c);
return false;
}
 
dom_node_unref(c2);
c2 = next2;
}
} else {
dom_string_unref(name);
}
err = dom_node_get_next_sibling(c, &next);
if (err != DOM_NO_ERR) {
dom_node_unref(c);
return false;
}
 
dom_node_unref(c);
c = next;
}
 
if (gadget->data.select.num_items == 0) {
/* no options: ignore entire select */
return true;
}
 
box->type = BOX_INLINE_BLOCK;
box->gadget = gadget;
gadget->box = box;
 
inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, content->bctx);
if (inline_container == NULL)
goto no_memory;
inline_container->type = BOX_INLINE_CONTAINER;
inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0,
content->bctx);
if (inline_box == NULL)
goto no_memory;
inline_box->type = BOX_TEXT;
box_add_child(inline_container, inline_box);
box_add_child(box, inline_container);
 
if (gadget->data.select.multiple == false &&
gadget->data.select.num_selected == 0) {
gadget->data.select.current = gadget->data.select.items;
gadget->data.select.current->initial_selected =
gadget->data.select.current->selected = true;
gadget->data.select.num_selected = 1;
}
 
if (gadget->data.select.num_selected == 0)
inline_box->text = talloc_strdup(content->bctx,
messages_get("Form_None"));
else if (gadget->data.select.num_selected == 1)
inline_box->text = talloc_strdup(content->bctx,
gadget->data.select.current->text);
else
inline_box->text = talloc_strdup(content->bctx,
messages_get("Form_Many"));
if (inline_box->text == NULL)
goto no_memory;
 
inline_box->length = strlen(inline_box->text);
 
*convert_children = false;
return true;
 
no_memory:
return false;
}
 
 
/**
* Add an option to a form select control (helper function for box_select()).
*
* \param control select containing the option
* \param n xml element node for <option>
* \return true on success, false on memory exhaustion
*/
 
bool box_select_add_option(struct form_control *control, dom_node *n)
{
char *value = NULL;
char *text = NULL;
char *text_nowrap = NULL;
bool selected;
dom_string *content, *s;
dom_exception err;
 
err = dom_node_get_text_content(n, &content);
if (err != DOM_NO_ERR)
return false;
 
if (content != NULL) {
text = squash_whitespace(dom_string_data(content));
dom_string_unref(content);
} else {
text = strdup("");
}
 
if (text == NULL)
goto no_memory;
 
err = dom_element_get_attribute(n, kstr_value, &s);
if (err == DOM_NO_ERR && s != NULL) {
value = strdup(dom_string_data(s));
dom_string_unref(s);
} else {
value = strdup(text);
}
 
if (value == NULL)
goto no_memory;
 
dom_element_has_attribute(n, kstr_selected, &selected);
 
/* replace spaces/TABs with hard spaces to prevent line wrapping */
text_nowrap = cnv_space2nbsp(text);
if (text_nowrap == NULL)
goto no_memory;
 
if (form_add_option(control, value, text_nowrap, selected) == false)
goto no_memory;
 
free(text);
 
return true;
 
no_memory:
free(value);
free(text);
free(text_nowrap);
return false;
}
 
 
/**
* Multi-line text field [17.7].
*/
 
bool box_textarea(BOX_SPECIAL_PARAMS)
{
/* A textarea is an INLINE_BLOCK containing a single INLINE_CONTAINER,
* which contains the text as runs of TEXT separated by BR. There is
* at least one TEXT. The first and last boxes are TEXT.
* Consecutive BR may not be present. These constraints are satisfied
* by using a 0-length TEXT for blank lines. */
 
const char *current;
dom_string *area_data = NULL;
dom_exception err;
struct box *inline_container, *inline_box, *br_box;
char *s;
size_t len;
 
box->type = BOX_INLINE_BLOCK;
box->gadget = html_forms_get_control_for_node(content->forms, n);
if (box->gadget == NULL)
return false;
box->gadget->box = box;
 
inline_container = box_create(NULL, 0, false, 0, 0, box->title, 0,
content->bctx);
if (inline_container == NULL)
return false;
inline_container->type = BOX_INLINE_CONTAINER;
box_add_child(box, inline_container);
 
err = dom_node_get_text_content(n, &area_data);
if (err != DOM_NO_ERR)
return false;
 
if (area_data != NULL) {
current = dom_string_data(area_data);
} else {
/* No content, or failed reading it: use a blank string */
current = "";
}
 
while (true) {
/* BOX_TEXT */
len = strcspn(current, "\r\n");
s = talloc_strndup(content->bctx, current, len);
if (s == NULL) {
if (area_data != NULL)
dom_string_unref(area_data);
return false;
}
 
inline_box = box_create(NULL, box->style, false, 0, 0,
box->title, 0, content->bctx);
if (inline_box == NULL) {
if (area_data != NULL)
dom_string_unref(area_data);
return false;
}
inline_box->type = BOX_TEXT;
inline_box->text = s;
inline_box->length = len;
box_add_child(inline_container, inline_box);
 
current += len;
if (current[0] == 0)
/* finished */
break;
 
/* BOX_BR */
br_box = box_create(NULL, box->style, false, 0, 0, box->title,
0, content->bctx);
if (br_box == NULL) {
if (area_data != NULL)
dom_string_unref(area_data);
return false;
}
br_box->type = BOX_BR;
box_add_child(inline_container, br_box);
 
if (current[0] == '\r' && current[1] == '\n')
current += 2;
else
current++;
}
 
if (area_data != NULL)
dom_string_unref(area_data);
 
*convert_children = false;
return true;
}
 
 
/**
* Embedded object (not in any HTML specification:
* see http://wp.netscape.com/assist/net_sites/new_html3_prop.html )
*/
 
bool box_embed(BOX_SPECIAL_PARAMS)
{
struct object_params *params;
struct object_param *param;
dom_namednodemap *attrs;
unsigned long idx;
uint32_t num_attrs;
dom_string *src;
dom_exception err;
 
if (box->style && css_computed_display(box->style,
box_is_root(n)) == CSS_DISPLAY_NONE)
return true;
 
params = talloc(content->bctx, struct object_params);
if (params == NULL)
return false;
 
talloc_set_destructor(params, box_object_talloc_destructor);
 
params->data = NULL;
params->type = NULL;
params->codetype = NULL;
params->codebase = NULL;
params->classid = NULL;
params->params = NULL;
 
/* src is a URL */
err = dom_element_get_attribute(n, kstr_src, &src);
if (err != DOM_NO_ERR || src == NULL)
return true;
if (box_extract_link(dom_string_data(src), content->base_url,
&params->data) == false) {
dom_string_unref(src);
return false;
}
 
dom_string_unref(src);
 
if (params->data == NULL)
return true;
 
/* Don't include ourself */
if (nsurl_compare(content->base_url, params->data, NSURL_COMPLETE))
return true;
 
/* add attributes as parameters to linked list */
err = dom_node_get_attributes(n, &attrs);
if (err != DOM_NO_ERR)
return false;
 
err = dom_namednodemap_get_length(attrs, &num_attrs);
if (err != DOM_NO_ERR) {
dom_namednodemap_unref(attrs);
return false;
}
 
for (idx = 0; idx < num_attrs; idx++) {
dom_attr *attr;
dom_string *name, *value;
 
err = dom_namednodemap_item(attrs, idx, (void *) &attr);
if (err != DOM_NO_ERR) {
dom_namednodemap_unref(attrs);
return false;
}
 
err = dom_attr_get_name(attr, &name);
if (err != DOM_NO_ERR) {
dom_namednodemap_unref(attrs);
return false;
}
 
if (dom_string_caseless_lwc_isequal(name, corestring_lwc_src)) {
dom_string_unref(name);
continue;
}
 
err = dom_attr_get_value(attr, &value);
if (err != DOM_NO_ERR) {
dom_string_unref(name);
dom_namednodemap_unref(attrs);
return false;
}
 
param = talloc(content->bctx, struct object_param);
if (param == NULL) {
dom_string_unref(value);
dom_string_unref(name);
dom_namednodemap_unref(attrs);
return false;
}
 
param->name = talloc_strdup(content->bctx, dom_string_data(name));
param->value = talloc_strdup(content->bctx, dom_string_data(value));
param->type = NULL;
param->valuetype = talloc_strdup(content->bctx, "data");
param->next = NULL;
 
dom_string_unref(value);
dom_string_unref(name);
 
if (param->name == NULL || param->value == NULL ||
param->valuetype == NULL) {
dom_namednodemap_unref(attrs);
return false;
}
 
param->next = params->params;
params->params = param;
}
 
dom_namednodemap_unref(attrs);
 
box->object_params = params;
 
/* start fetch */
return html_fetch_object(content, params->data, box, CONTENT_ANY,
content->base.available_width, 1000, false);
}
 
/**
* \}
*/
 
 
/**
* Get the value of an XML element's attribute.
*
* \param n xmlNode, of type XML_ELEMENT_NODE
* \param attribute name of attribute
* \param context talloc context for result buffer
* \param value updated to value, if the attribute is present
* \return true on success, false if attribute present but memory exhausted
*
* Note that returning true does not imply that the attribute was found. If the
* attribute was not found, *value will be unchanged.
*/
 
bool box_get_attribute(dom_node *n, const char *attribute,
void *context, char **value)
{
char *result;
dom_string *attr, *attr_name;
dom_exception err;
 
err = dom_string_create_interned((const uint8_t *) attribute,
strlen(attribute), &attr_name);
if (err != DOM_NO_ERR)
return false;
 
err = dom_element_get_attribute(n, attr_name, &attr);
if (err != DOM_NO_ERR) {
dom_string_unref(attr_name);
return false;
}
 
dom_string_unref(attr_name);
 
if (attr != NULL) {
result = talloc_strdup(context, dom_string_data(attr));
 
dom_string_unref(attr);
if (result == NULL)
return false;
 
*value = result;
}
 
return true;
}
 
 
/**
* Extract a URL from a relative link, handling junk like whitespace and
* attempting to read a real URL from "javascript:" links.
*
* \param rel relative URL taken from page
* \param base base for relative URLs
* \param result updated to target URL on heap, unchanged if extract failed
* \return true on success, false on memory exhaustion
*/
 
bool box_extract_link(const char *rel, nsurl *base, nsurl **result)
{
char *s, *s1, *apos0 = 0, *apos1 = 0, *quot0 = 0, *quot1 = 0;
unsigned int i, j, end;
nserror error;
 
s1 = s = malloc(3 * strlen(rel) + 1);
if (!s)
return false;
 
/* copy to s, removing white space and control characters */
for (i = 0; rel[i] && isspace(rel[i]); i++)
;
for (end = strlen(rel); end != i && isspace(rel[end - 1]); end--)
;
for (j = 0; i != end; i++) {
if ((unsigned char) rel[i] < 0x20) {
; /* skip control characters */
} else if (rel[i] == ' ') {
s[j++] = '%';
s[j++] = '2';
s[j++] = '0';
} else {
s[j++] = rel[i];
}
}
s[j] = 0;
 
/* extract first quoted string out of "javascript:" link */
if (strncmp(s, "javascript:", 11) == 0) {
apos0 = strchr(s, '\'');
if (apos0)
apos1 = strchr(apos0 + 1, '\'');
quot0 = strchr(s, '"');
if (quot0)
quot1 = strchr(quot0 + 1, '"');
if (apos0 && apos1 && (!quot0 || !quot1 || apos0 < quot0)) {
*apos1 = 0;
s1 = apos0 + 1;
} else if (quot0 && quot1) {
*quot1 = 0;
s1 = quot0 + 1;
}
}
 
/* construct absolute URL */
error = nsurl_join(base, s1, result);
free(s);
if (error != NSERROR_OK) {
*result = NULL;
return false;
}
 
return true;
}
 
 
/**
* Parse a multi-length-list, as defined by HTML 4.01.
*
* \param s string to parse
* \param count updated to number of entries
* \return array of struct box_multi_length, or 0 on memory exhaustion
*/
 
struct frame_dimension *box_parse_multi_lengths(const char *s,
unsigned int *count)
{
char *end;
unsigned int i, n;
struct frame_dimension *length;
 
for (i = 0, n = 1; s[i]; i++)
if (s[i] == ',')
n++;
 
length = calloc(n, sizeof(struct frame_dimension));
if (!length)
return NULL;
 
for (i = 0; i != n; i++) {
while (isspace(*s))
s++;
length[i].value = strtof(s, &end);
if (length[i].value <= 0)
length[i].value = 1;
s = end;
switch (*s) {
case '%':
length[i].unit = FRAME_DIMENSION_PERCENT;
break;
case '*':
length[i].unit = FRAME_DIMENSION_RELATIVE;
break;
default:
length[i].unit = FRAME_DIMENSION_PIXELS;
break;
}
while (*s && *s != ',')
s++;
if (*s == ',')
s++;
}
 
*count = n;
return length;
}
 
/programs/network/netsurf/netsurf/render/box_normalise.c
0,0 → 1,974
/*
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2004 Kevin Bagust <kevin.bagust@ntlworld.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Box tree normalisation (implementation).
*/
 
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include "css/css.h"
#include "css/select.h"
#include "render/box.h"
#include "render/html_internal.h"
#include "render/table.h"
#include "utils/log.h"
 
/* Define to enable box normalise debug */
#undef BOX_NORMALISE_DEBUG
 
/**
* Row spanning information for a cell
*/
struct span_info {
/** Number of rows this cell spans */
unsigned int row_span;
/** The cell in this column spans all rows until the end of the table */
bool auto_row;
};
 
/**
* Column record for a table
*/
struct columns {
/** Current column index */
unsigned int current_column;
/** Number of columns in main part of table 1..max columns */
unsigned int num_columns;
/** Information about columns in main table, array [0, num_columns) */
struct span_info *spans;
/** Number of rows in table */
unsigned int num_rows;
};
 
 
static bool box_normalise_table(struct box *table, html_content *c);
static bool box_normalise_table_spans(struct box *table,
struct span_info *spans, html_content *c);
static bool box_normalise_table_row_group(struct box *row_group,
struct columns *col_info,
html_content *c);
static bool box_normalise_table_row(struct box *row,
struct columns *col_info,
html_content *c);
static bool calculate_table_row(struct columns *col_info,
unsigned int col_span, unsigned int row_span,
unsigned int *start_column);
static bool box_normalise_inline_container(struct box *cont, html_content *c);
 
/**
* Ensure the box tree is correctly nested by adding and removing nodes.
*
* \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
* \param box_pool pool to allocate new boxes in
* \return true on success, false on memory exhaustion
*
* The tree is modified to satisfy the following:
* \code
* parent permitted child nodes
* BLOCK, INLINE_BLOCK BLOCK, INLINE_CONTAINER, TABLE
* INLINE_CONTAINER INLINE, INLINE_BLOCK, FLOAT_LEFT, FLOAT_RIGHT, BR, TEXT
* INLINE, TEXT none
* TABLE at least 1 TABLE_ROW_GROUP
* TABLE_ROW_GROUP at least 1 TABLE_ROW
* TABLE_ROW at least 1 TABLE_CELL
* TABLE_CELL BLOCK, INLINE_CONTAINER, TABLE (same as BLOCK)
* FLOAT_(LEFT|RIGHT) exactly 1 BLOCK or TABLE
* \endcode
*/
 
bool box_normalise_block(struct box *block, html_content *c)
{
struct box *child;
struct box *next_child;
struct box *table;
css_computed_style *style;
nscss_select_ctx ctx;
 
assert(block != NULL);
 
#ifdef BOX_NORMALISE_DEBUG
LOG(("block %p, block->type %u", block, block->type));
#endif
 
assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK ||
block->type == BOX_TABLE_CELL);
 
for (child = block->children; child != NULL; child = next_child) {
#ifdef BOX_NORMALISE_DEBUG
LOG(("child %p, child->type = %d", child, child->type));
#endif
 
next_child = child->next; /* child may be destroyed */
 
switch (child->type) {
case BOX_BLOCK:
/* ok */
if (box_normalise_block(child, c) == false)
return false;
break;
case BOX_INLINE_CONTAINER:
if (box_normalise_inline_container(child, c) == false)
return false;
break;
case BOX_TABLE:
if (box_normalise_table(child, c) == false)
return false;
break;
case BOX_INLINE:
case BOX_INLINE_END:
case BOX_INLINE_BLOCK:
case BOX_FLOAT_LEFT:
case BOX_FLOAT_RIGHT:
case BOX_BR:
case BOX_TEXT:
/* should have been wrapped in inline
container by convert_xml_to_box() */
assert(0);
break;
case BOX_TABLE_ROW_GROUP:
case BOX_TABLE_ROW:
case BOX_TABLE_CELL:
/* insert implied table */
assert(block->style != NULL);
 
ctx.ctx = c->select_ctx;
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
 
style = nscss_get_blank_style(&ctx, block->style,
box_style_alloc, NULL);
if (style == NULL)
return false;
 
table = box_create(NULL, style, true, block->href,
block->target, NULL, NULL, c->bctx);
if (table == NULL) {
css_computed_style_destroy(style);
return false;
}
table->type = BOX_TABLE;
 
if (child->prev == NULL)
block->children = table;
else
child->prev->next = table;
 
table->prev = child->prev;
 
while (child != NULL && (
child->type == BOX_TABLE_ROW_GROUP ||
child->type == BOX_TABLE_ROW ||
child->type == BOX_TABLE_CELL)) {
box_add_child(table, child);
 
next_child = child->next;
child->next = NULL;
child = next_child;
}
 
table->last->next = NULL;
table->next = next_child = child;
if (table->next != NULL)
table->next->prev = table;
else
block->last = table;
table->parent = block;
 
if (box_normalise_table(table, c) == false)
return false;
break;
default:
assert(0);
}
}
 
return true;
}
 
 
bool box_normalise_table(struct box *table, html_content * c)
{
struct box *child;
struct box *next_child;
struct box *row_group;
css_computed_style *style;
struct columns col_info;
nscss_select_ctx ctx;
 
assert(table != NULL);
assert(table->type == BOX_TABLE);
 
#ifdef BOX_NORMALISE_DEBUG
LOG(("table %p", table));
#endif
 
col_info.num_columns = 1;
col_info.current_column = 0;
col_info.spans = malloc(2 * sizeof *col_info.spans);
if (col_info.spans == NULL)
return false;
 
col_info.spans[0].row_span = col_info.spans[1].row_span = 0;
col_info.spans[0].auto_row = false;
col_info.spans[1].auto_row = false;
col_info.num_rows = 0;
 
for (child = table->children; child != NULL; child = next_child) {
next_child = child->next;
switch (child->type) {
case BOX_TABLE_ROW_GROUP:
/* ok */
if (box_normalise_table_row_group(child,
&col_info, c) == false) {
free(col_info.spans);
return false;
}
break;
case BOX_BLOCK:
case BOX_INLINE_CONTAINER:
case BOX_TABLE:
case BOX_TABLE_ROW:
case BOX_TABLE_CELL:
/* insert implied table row group */
assert(table->style != NULL);
 
ctx.ctx = c->select_ctx;
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
 
style = nscss_get_blank_style(&ctx, table->style,
box_style_alloc, NULL);
if (style == NULL) {
free(col_info.spans);
return false;
}
 
row_group = box_create(NULL, style, true, table->href,
table->target, NULL, NULL, c->bctx);
if (row_group == NULL) {
css_computed_style_destroy(style);
free(col_info.spans);
return false;
}
 
row_group->type = BOX_TABLE_ROW_GROUP;
 
if (child->prev == NULL)
table->children = row_group;
else
child->prev->next = row_group;
 
row_group->prev = child->prev;
 
while (child != NULL && (
child->type == BOX_BLOCK ||
child->type == BOX_INLINE_CONTAINER ||
child->type == BOX_TABLE ||
child->type == BOX_TABLE_ROW ||
child->type == BOX_TABLE_CELL)) {
box_add_child(row_group, child);
 
next_child = child->next;
child->next = NULL;
child = next_child;
}
 
assert(row_group->last != NULL);
 
row_group->last->next = NULL;
row_group->next = next_child = child;
if (row_group->next != NULL)
row_group->next->prev = row_group;
else
table->last = row_group;
row_group->parent = table;
 
if (box_normalise_table_row_group(row_group,
&col_info, c) == false) {
free(col_info.spans);
return false;
}
break;
case BOX_INLINE:
case BOX_INLINE_END:
case BOX_INLINE_BLOCK:
case BOX_FLOAT_LEFT:
case BOX_FLOAT_RIGHT:
case BOX_BR:
case BOX_TEXT:
/* should have been wrapped in inline
container by convert_xml_to_box() */
assert(0);
break;
default:
fprintf(stderr, "%i\n", child->type);
assert(0);
}
}
 
table->columns = col_info.num_columns;
table->rows = col_info.num_rows;
 
if (table->children == NULL) {
struct box *row;
 
#ifdef BOX_NORMALISE_DEBUG
LOG(("table->children == 0, creating implied row"));
#endif
 
assert(table->style != NULL);
 
ctx.ctx = c->select_ctx;
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
 
style = nscss_get_blank_style(&ctx, table->style,
box_style_alloc, NULL);
if (style == NULL) {
free(col_info.spans);
return false;
}
 
row_group = box_create(NULL, style, true, table->href,
table->target, NULL, NULL, c->bctx);
if (row_group == NULL) {
css_computed_style_destroy(style);
free(col_info.spans);
return false;
}
row_group->type = BOX_TABLE_ROW_GROUP;
 
style = nscss_get_blank_style(&ctx, row_group->style,
box_style_alloc, NULL);
if (style == NULL) {
box_free(row_group);
free(col_info.spans);
return false;
}
 
row = box_create(NULL, style, true, row_group->href,
row_group->target, NULL, NULL, c->bctx);
if (row == NULL) {
css_computed_style_destroy(style);
box_free(row_group);
free(col_info.spans);
return false;
}
row->type = BOX_TABLE_ROW;
 
row->parent = row_group;
row_group->children = row_group->last = row;
 
row_group->parent = table;
table->children = table->last = row_group;
 
table->rows = 1;
}
 
if (box_normalise_table_spans(table, col_info.spans, c) == false) {
free(col_info.spans);
return false;
}
 
free(col_info.spans);
 
if (table_calculate_column_types(table) == false)
return false;
 
#ifdef BOX_NORMALISE_DEBUG
LOG(("table %p done", table));
#endif
 
return true;
}
 
 
/**
* Normalise table cell column/row counts for colspan/rowspan = 0.
* Additionally, generate empty cells.
*
* \param table Table to process
* \param spans Array of length table->columns for use in empty cell detection
* \param c Content containing table
* \return True on success, false on memory exhaustion.
*/
 
bool box_normalise_table_spans(struct box *table, struct span_info *spans,
html_content *c)
{
struct box *table_row_group;
struct box *table_row;
struct box *table_cell;
unsigned int rows_left = table->rows;
unsigned int col;
nscss_select_ctx ctx;
 
/* Clear span data */
memset(spans, 0, table->columns * sizeof(struct span_info));
 
/* Scan table, filling in width and height of table cells with
* colspan = 0 and rowspan = 0. Also generate empty cells */
for (table_row_group = table->children; table_row_group != NULL;
table_row_group = table_row_group->next) {
for (table_row = table_row_group->children; table_row != NULL;
table_row = table_row->next){
for (table_cell = table_row->children;
table_cell != NULL;
table_cell = table_cell->next) {
/* colspan = 0 -> colspan = 1 */
if (table_cell->columns == 0)
table_cell->columns = 1;
 
/* rowspan = 0 -> rowspan = rows_left */
if (table_cell->rows == 0)
table_cell->rows = rows_left;
 
/* Record span information */
for (col = table_cell->start_column;
col < table_cell->start_column +
table_cell->columns; col++) {
spans[col].row_span = table_cell->rows;
}
}
 
/* Reduce span count of each column */
for (col = 0; col < table->columns; col++) {
if (spans[col].row_span == 0) {
unsigned int start = col;
css_computed_style *style;
struct box *cell, *prev;
 
/* If it's already zero, then we need
* to generate an empty cell for the
* gap in the row that spans as many
* columns as remain blank.
*/
assert(table_row->style != NULL);
 
/* Find width of gap */
while (col < table->columns &&
spans[col].row_span ==
0) {
col++;
}
 
ctx.ctx = c->select_ctx;
ctx.quirks = (c->quirks ==
DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
 
style = nscss_get_blank_style(&ctx,
table_row->style,
box_style_alloc, NULL);
if (style == NULL)
return false;
 
cell = box_create(NULL, style, true,
table_row->href,
table_row->target,
NULL, NULL, c->bctx);
if (cell == NULL) {
css_computed_style_destroy(
style);
return false;
}
cell->type = BOX_TABLE_CELL;
 
cell->rows = 1;
cell->columns = col - start;
cell->start_column = start;
 
/* Find place to insert cell */
for (prev = table_row->children;
prev != NULL;
prev = prev->next) {
if (prev->start_column +
prev->columns ==
start)
break;
if (prev->next == NULL)
break;
}
 
/* Insert it */
if (prev == NULL) {
if (table_row->children != NULL)
table_row->children->
prev = cell;
else
table_row->last = cell;
 
cell->next =
table_row->children;
table_row->children = cell;
} else {
if (prev->next != NULL)
prev->next->prev = cell;
else
table_row->last = cell;
 
cell->next = prev->next;
prev->next = cell;
cell->prev = prev;
}
cell->parent = table_row;
} else {
spans[col].row_span--;
}
}
 
assert(rows_left > 0);
 
rows_left--;
}
}
 
return true;
}
 
 
bool box_normalise_table_row_group(struct box *row_group,
struct columns *col_info,
html_content * c)
{
struct box *child;
struct box *next_child;
struct box *row;
css_computed_style *style;
nscss_select_ctx ctx;
 
assert(row_group != 0);
assert(row_group->type == BOX_TABLE_ROW_GROUP);
 
#ifdef BOX_NORMALISE_DEBUG
LOG(("row_group %p", row_group));
#endif
 
for (child = row_group->children; child != NULL; child = next_child) {
next_child = child->next;
 
switch (child->type) {
case BOX_TABLE_ROW:
/* ok */
if (box_normalise_table_row(child, col_info,
c) == false)
return false;
break;
case BOX_BLOCK:
case BOX_INLINE_CONTAINER:
case BOX_TABLE:
case BOX_TABLE_ROW_GROUP:
case BOX_TABLE_CELL:
/* insert implied table row */
assert(row_group->style != NULL);
 
ctx.ctx = c->select_ctx;
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
 
style = nscss_get_blank_style(&ctx, row_group->style,
box_style_alloc, NULL);
if (style == NULL)
return false;
 
row = box_create(NULL, style, true, row_group->href,
row_group->target, NULL, NULL, c->bctx);
if (row == NULL) {
css_computed_style_destroy(style);
return false;
}
row->type = BOX_TABLE_ROW;
 
if (child->prev == NULL)
row_group->children = row;
else
child->prev->next = row;
 
row->prev = child->prev;
 
while (child != NULL && (
child->type == BOX_BLOCK ||
child->type == BOX_INLINE_CONTAINER ||
child->type == BOX_TABLE ||
child->type == BOX_TABLE_ROW_GROUP ||
child->type == BOX_TABLE_CELL)) {
box_add_child(row, child);
 
next_child = child->next;
child->next = NULL;
child = next_child;
}
 
assert(row->last != NULL);
 
row->last->next = NULL;
row->next = next_child = child;
if (row->next != NULL)
row->next->prev = row;
else
row_group->last = row;
row->parent = row_group;
 
if (box_normalise_table_row(row, col_info,
c) == false)
return false;
break;
case BOX_INLINE:
case BOX_INLINE_END:
case BOX_INLINE_BLOCK:
case BOX_FLOAT_LEFT:
case BOX_FLOAT_RIGHT:
case BOX_BR:
case BOX_TEXT:
/* should have been wrapped in inline
container by convert_xml_to_box() */
assert(0);
break;
default:
assert(0);
}
}
 
if (row_group->children == NULL) {
#ifdef BOX_NORMALISE_DEBUG
LOG(("row_group->children == 0, inserting implied row"));
#endif
 
assert(row_group->style != NULL);
 
ctx.ctx = c->select_ctx;
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
 
style = nscss_get_blank_style(&ctx, row_group->style,
box_style_alloc, NULL);
if (style == NULL) {
return false;
}
 
row = box_create(NULL, style, true, row_group->href,
row_group->target, NULL, NULL, c->bctx);
if (row == NULL) {
css_computed_style_destroy(style);
return false;
}
row->type = BOX_TABLE_ROW;
 
row->parent = row_group;
row_group->children = row_group->last = row;
 
/* Keep table's row count in sync */
col_info->num_rows++;
}
 
#ifdef BOX_NORMALISE_DEBUG
LOG(("row_group %p done", row_group));
#endif
 
return true;
}
 
 
bool box_normalise_table_row(struct box *row,
struct columns *col_info,
html_content * c)
{
struct box *child;
struct box *next_child;
struct box *cell = NULL;
css_computed_style *style;
unsigned int i;
nscss_select_ctx ctx;
 
assert(row != NULL);
assert(row->type == BOX_TABLE_ROW);
 
#ifdef BOX_NORMALISE_DEBUG
LOG(("row %p", row));
#endif
 
for (child = row->children; child != NULL; child = next_child) {
next_child = child->next;
 
switch (child->type) {
case BOX_TABLE_CELL:
/* ok */
if (box_normalise_block(child, c) == false)
return false;
cell = child;
break;
case BOX_BLOCK:
case BOX_INLINE_CONTAINER:
case BOX_TABLE:
case BOX_TABLE_ROW_GROUP:
case BOX_TABLE_ROW:
/* insert implied table cell */
assert(row->style != NULL);
 
ctx.ctx = c->select_ctx;
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
 
style = nscss_get_blank_style(&ctx, row->style,
box_style_alloc, NULL);
if (style == NULL)
return false;
 
cell = box_create(NULL, style, true, row->href,
row->target, NULL, NULL, c->bctx);
if (cell == NULL) {
css_computed_style_destroy(style);
return false;
}
cell->type = BOX_TABLE_CELL;
 
if (child->prev == NULL)
row->children = cell;
else
child->prev->next = cell;
 
cell->prev = child->prev;
 
while (child != NULL && (
child->type == BOX_BLOCK ||
child->type == BOX_INLINE_CONTAINER ||
child->type == BOX_TABLE ||
child->type == BOX_TABLE_ROW_GROUP ||
child->type == BOX_TABLE_ROW)) {
box_add_child(cell, child);
 
next_child = child->next;
child->next = NULL;
child = next_child;
}
 
assert(cell->last != NULL);
 
cell->last->next = NULL;
cell->next = next_child = child;
if (cell->next != NULL)
cell->next->prev = cell;
else
row->last = cell;
cell->parent = row;
 
if (box_normalise_block(cell, c) == false)
return false;
break;
case BOX_INLINE:
case BOX_INLINE_END:
case BOX_INLINE_BLOCK:
case BOX_FLOAT_LEFT:
case BOX_FLOAT_RIGHT:
case BOX_BR:
case BOX_TEXT:
/* should have been wrapped in inline
container by convert_xml_to_box() */
assert(0);
break;
default:
assert(0);
}
 
if (calculate_table_row(col_info, cell->columns, cell->rows,
&cell->start_column) == false)
return false;
}
 
 
/* Update row spanning details for all columns */
for (i = 0; i < col_info->num_columns; i++) {
if (col_info->spans[i].row_span != 0 &&
col_info->spans[i].auto_row == false) {
/* This cell spans rows, and is not an auto row.
* Reduce number of rows left to span */
col_info->spans[i].row_span--;
}
}
 
/* Reset current column for next row */
col_info->current_column = 0;
 
/* Increment row counter */
col_info->num_rows++;
 
#ifdef BOX_NORMALISE_DEBUG
LOG(("row %p done", row));
#endif
 
return true;
}
 
 
/**
* Compute the column index at which the current cell begins.
* Additionally, update the column record to reflect row spanning.
*
* \param col_info Column record
* \param col_span Number of columns that current cell spans
* \param row_span Number of rows that current cell spans
* \param start_column Pointer to location to receive column index
* \return true on success, false on memory exhaustion
*/
 
bool calculate_table_row(struct columns *col_info,
unsigned int col_span, unsigned int row_span,
unsigned int *start_column)
{
unsigned int cell_start_col = col_info->current_column;
unsigned int cell_end_col;
unsigned int i;
struct span_info *spans;
 
/* Skip columns with cells spanning from above */
while (col_info->spans[cell_start_col].row_span != 0)
cell_start_col++;
 
/* Update current column with calculated start */
col_info->current_column = cell_start_col;
 
/* If this cell has a colspan of 0, then assume 1.
* No other browser supports colspan=0, anyway. */
if (col_span == 0)
col_span = 1;
cell_end_col = cell_start_col + col_span;
 
if (col_info->num_columns < cell_end_col) {
/* It appears that this row has more columns than
* the maximum recorded for the table so far.
* Allocate more span records. */
spans = realloc(col_info->spans,
sizeof *spans * (cell_end_col + 1));
if (spans == NULL)
return false;
 
col_info->spans = spans;
col_info->num_columns = cell_end_col;
 
/* Mark new final column as sentinel */
col_info->spans[cell_end_col].row_span = 0;
col_info->spans[cell_end_col].auto_row = false;
}
 
/* This cell may span multiple columns. If it also wants to span
* multiple rows, temporarily assume it spans 1 row only. This will
* be fixed up in box_normalise_table_spans() */
for (i = cell_start_col; i < cell_end_col; i++) {
col_info->spans[i].row_span = (row_span == 0) ? 1 : row_span;
col_info->spans[i].auto_row = (row_span == 0);
}
 
/* Update current column with calculated end. */
col_info->current_column = cell_end_col;
 
*start_column = cell_start_col;
 
return true;
}
 
 
bool box_normalise_inline_container(struct box *cont, html_content * c)
{
struct box *child;
struct box *next_child;
 
assert(cont != NULL);
assert(cont->type == BOX_INLINE_CONTAINER);
 
#ifdef BOX_NORMALISE_DEBUG
LOG(("cont %p", cont));
#endif
 
for (child = cont->children; child != NULL; child = next_child) {
next_child = child->next;
switch (child->type) {
case BOX_INLINE:
case BOX_INLINE_END:
case BOX_BR:
case BOX_TEXT:
/* ok */
break;
case BOX_INLINE_BLOCK:
/* ok */
if (box_normalise_block(child, c) == false)
return false;
break;
case BOX_FLOAT_LEFT:
case BOX_FLOAT_RIGHT:
/* ok */
assert(child->children != NULL);
 
switch (child->children->type) {
case BOX_BLOCK:
if (box_normalise_block(child->children,
c) == false)
return false;
break;
case BOX_TABLE:
if (box_normalise_table(child->children,
c) == false)
return false;
break;
default:
assert(0);
}
 
if (child->children == NULL) {
/* the child has destroyed itself: remove float */
if (child->prev == NULL)
child->parent->children = child->next;
else
child->prev->next = child->next;
if (child->next != NULL)
child->next->prev = child->prev;
else
child->parent->last = child->prev;
 
box_free(child);
}
break;
case BOX_BLOCK:
case BOX_INLINE_CONTAINER:
case BOX_TABLE:
case BOX_TABLE_ROW_GROUP:
case BOX_TABLE_ROW:
case BOX_TABLE_CELL:
default:
assert(0);
}
}
 
#ifdef BOX_NORMALISE_DEBUG
LOG(("cont %p done", cont));
#endif
 
return true;
}
/programs/network/netsurf/netsurf/render/font.c
0,0 → 1,169
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include "css/css.h"
#include "css/utils.h"
#include "desktop/options.h"
#include "render/font.h"
 
static plot_font_generic_family_t plot_font_generic_family(
enum css_font_family_e css);
static int plot_font_weight(enum css_font_weight_e css);
static plot_font_flags_t plot_font_flags(enum css_font_style_e style,
enum css_font_variant_e variant);
 
/**
* Populate a font style using data from a computed CSS style
*
* \param css Computed style to consider
* \param fstyle Font style to populate
*/
void font_plot_style_from_css(const css_computed_style *css,
plot_font_style_t *fstyle)
{
lwc_string **families;
css_fixed length = 0;
css_unit unit = CSS_UNIT_PX;
css_color col;
 
fstyle->family = plot_font_generic_family(
css_computed_font_family(css, &families));
 
css_computed_font_size(css, &length, &unit);
fstyle->size = FIXTOINT(FMUL(nscss_len2pt(length, unit),
INTTOFIX(FONT_SIZE_SCALE)));
 
/* Clamp font size to configured minimum */
if (fstyle->size < (nsoption_int(font_min_size) * FONT_SIZE_SCALE) / 10)
fstyle->size = (nsoption_int(font_min_size) * FONT_SIZE_SCALE) / 10;
 
fstyle->weight = plot_font_weight(css_computed_font_weight(css));
fstyle->flags = plot_font_flags(css_computed_font_style(css),
css_computed_font_variant(css));
 
css_computed_color(css, &col);
fstyle->foreground = nscss_color_to_ns(col);
fstyle->background = 0;
}
 
/******************************************************************************
* Helper functions *
******************************************************************************/
 
/**
* Map a generic CSS font family to a generic plot font family
*
* \param css Generic CSS font family
* \return Plot font family
*/
plot_font_generic_family_t plot_font_generic_family(
enum css_font_family_e css)
{
plot_font_generic_family_t plot;
 
switch (css) {
case CSS_FONT_FAMILY_SERIF:
plot = PLOT_FONT_FAMILY_SERIF;
break;
case CSS_FONT_FAMILY_MONOSPACE:
plot = PLOT_FONT_FAMILY_MONOSPACE;
break;
case CSS_FONT_FAMILY_CURSIVE:
plot = PLOT_FONT_FAMILY_CURSIVE;
break;
case CSS_FONT_FAMILY_FANTASY:
plot = PLOT_FONT_FAMILY_FANTASY;
break;
case CSS_FONT_FAMILY_SANS_SERIF:
default:
plot = PLOT_FONT_FAMILY_SANS_SERIF;
break;
}
 
return plot;
}
 
/**
* Map a CSS font weight to a plot weight value
*
* \param css CSS font weight
* \return Plot weight
*/
int plot_font_weight(enum css_font_weight_e css)
{
int weight;
 
switch (css) {
case CSS_FONT_WEIGHT_100:
weight = 100;
break;
case CSS_FONT_WEIGHT_200:
weight = 200;
break;
case CSS_FONT_WEIGHT_300:
weight = 300;
break;
case CSS_FONT_WEIGHT_400:
case CSS_FONT_WEIGHT_NORMAL:
default:
weight = 400;
break;
case CSS_FONT_WEIGHT_500:
weight = 500;
break;
case CSS_FONT_WEIGHT_600:
weight = 600;
break;
case CSS_FONT_WEIGHT_700:
case CSS_FONT_WEIGHT_BOLD:
weight = 700;
break;
case CSS_FONT_WEIGHT_800:
weight = 800;
break;
case CSS_FONT_WEIGHT_900:
weight = 900;
break;
}
 
return weight;
}
 
/**
* Map a CSS font style and font variant to plot font flags
*
* \param style CSS font style
* \param variant CSS font variant
* \return Computed plot flags
*/
plot_font_flags_t plot_font_flags(enum css_font_style_e style,
enum css_font_variant_e variant)
{
plot_font_flags_t flags = FONTF_NONE;
 
if (style == CSS_FONT_STYLE_ITALIC)
flags |= FONTF_ITALIC;
else if (style == CSS_FONT_STYLE_OBLIQUE)
flags |= FONTF_OBLIQUE;
 
if (variant == CSS_FONT_VARIANT_SMALL_CAPS)
flags |= FONTF_SMALLCAPS;
 
return flags;
}
 
/programs/network/netsurf/netsurf/render/font.h
0,0 → 1,94
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004 John Tytgat <joty@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Font handling (interface).
*
* These functions provide font related services. They all work on UTF-8 strings
* with lengths given.
*
* Note that an interface to painting is not defined here. Painting is
* redirected through platform-dependent plotters anyway, so there is no gain in
* abstracting it here.
*/
 
#ifndef _NETSURF_RENDER_FONT_H_
#define _NETSURF_RENDER_FONT_H_
 
#include <stdbool.h>
#include <stddef.h>
 
#include "css/css.h"
#include "desktop/plot_style.h"
 
struct font_functions
{
/**
* Measure the width of a string.
*
* \param fstyle plot style for this text
* \param string UTF-8 string to measure
* \param length length of string, in bytes
* \param width updated to width of string[0..length)
* \return true on success, false on error and error reported
*/
bool (*font_width)(const plot_font_style_t *fstyle,
const char *string, size_t length,
int *width);
/**
* Find the position in a string where an x coordinate falls.
*
* \param fstyle style for this text
* \param string UTF-8 string to measure
* \param length length of string, in bytes
* \param x x coordinate to search for
* \param char_offset updated to offset in string of actual_x, [0..length]
* \param actual_x updated to x coordinate of character closest to x
* \return true on success, false on error and error reported
*/
bool (*font_position_in_string)(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x);
/**
* Find where to split a string to make it fit a width.
*
* \param fstyle style for this text
* \param string UTF-8 string to measure
* \param length length of string, in bytes
* \param x width available
* \param char_offset updated to offset in string of actual_x, [0..length]
* \param actual_x updated to x coordinate of character closest to x
* \return true on success, false on error and error reported
*
* On exit, [char_offset == 0 ||
* string[char_offset] == ' ' ||
* char_offset == length]
*/
bool (*font_split)(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x);
};
 
extern const struct font_functions nsfont;
 
void font_plot_style_from_css(const css_computed_style *css,
plot_font_style_t *fstyle);
 
#endif
/programs/network/netsurf/netsurf/render/form.c
0,0 → 1,1545
/*
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2004 John Tytgat <joty@netsurf-browser.org>
* Copyright 2005-9 John-Mark Bell <jmb@netsurf-browser.org>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
* Copyright 2010 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Form handling functions (implementation).
*/
 
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <dom/dom.h>
#include "content/fetch.h"
#include "content/hlcache.h"
#include "css/css.h"
#include "css/utils.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
#include "desktop/mouse.h"
#include "desktop/knockout.h"
#include "desktop/plot_style.h"
#include "desktop/plotters.h"
#include "desktop/scrollbar.h"
#include "render/box.h"
#include "render/font.h"
#include "render/form.h"
#include "render/html.h"
#include "render/html_internal.h"
#include "render/layout.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/talloc.h"
#include "utils/url.h"
#include "utils/utf8.h"
#include "utils/utils.h"
 
#define MAX_SELECT_HEIGHT 210
#define SELECT_LINE_SPACING 0.2
#define SELECT_BORDER_WIDTH 1
#define SELECT_SELECTED_COLOUR 0xDB9370
 
struct form_select_menu {
int line_height;
int width, height;
struct scrollbar *scrollbar;
int f_size;
bool scroll_capture;
select_menu_redraw_callback callback;
void *client_data;
struct content *c;
};
 
static plot_style_t plot_style_fill_selected = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = SELECT_SELECTED_COLOUR,
};
 
static plot_font_style_t plot_fstyle_entry = {
.family = PLOT_FONT_FAMILY_SANS_SERIF,
.weight = 400,
.flags = FONTF_NONE,
.background = 0xffffff,
.foreground = 0x000000,
};
 
static char *form_textarea_value(struct form_control *textarea);
static char *form_acceptable_charset(struct form *form);
static char *form_encode_item(const char *item, const char *charset,
const char *fallback);
static void form_select_menu_clicked(struct form_control *control,
int x, int y);
static void form_select_menu_scroll_callback(void *client_data,
struct scrollbar_msg_data *scrollbar_data);
 
/**
* Create a struct form.
*
* \param node DOM node associated with form
* \param action URL to submit form to, or NULL for default
* \param target Target frame of form, or NULL for default
* \param method method and enctype
* \param charset acceptable encodings for form submission, or NULL
* \param doc_charset encoding of containing document, or NULL
* \return a new structure, or NULL on memory exhaustion
*/
struct form *form_new(void *node, const char *action, const char *target,
form_method method, const char *charset,
const char *doc_charset)
{
struct form *form;
 
form = calloc(1, sizeof *form);
if (!form)
return NULL;
 
form->action = strdup(action != NULL ? action : "");
if (form->action == NULL) {
free(form);
return NULL;
}
 
form->target = target != NULL ? strdup(target) : NULL;
if (target != NULL && form->target == NULL) {
free(form->action);
free(form);
return NULL;
}
 
form->method = method;
 
form->accept_charsets = charset != NULL ? strdup(charset) : NULL;
if (charset != NULL && form->accept_charsets == NULL) {
free(form->target);
free(form->action);
free(form);
return NULL;
}
 
form->document_charset = doc_charset != NULL ? strdup(doc_charset)
: NULL;
if (doc_charset && form->document_charset == NULL) {
free(form->accept_charsets);
free(form->target);
free(form->action);
free(form);
return NULL;
}
 
form->node = node;
 
return form;
}
 
/**
* Free a form, and any controls it owns.
*
* \param form The form to free
*
* \note There may exist controls attached to box tree nodes which are not
* associated with any form. These will leak at present. Ideally, they will
* be cleaned up when the box tree is destroyed. As that currently happens
* via talloc, this won't happen. These controls are distinguishable, as their
* form field will be NULL.
*/
void form_free(struct form *form)
{
struct form_control *c, *d;
 
for (c = form->controls; c != NULL; c = d) {
d = c->next;
 
form_free_control(c);
}
 
free(form->action);
free(form->target);
free(form->accept_charsets);
free(form->document_charset);
 
free(form);
}
 
/**
* Create a struct form_control.
*
* \param node Associated DOM node
* \param type control type
* \return a new structure, or NULL on memory exhaustion
*/
struct form_control *form_new_control(void *node, form_control_type type)
{
struct form_control *control;
 
control = calloc(1, sizeof *control);
if (control == NULL)
return NULL;
 
control->node = node;
control->type = type;
 
return control;
}
 
 
/**
* Add a control to the list of controls in a form.
*
* \param form The form to add the control to
* \param control The control to add
*/
void form_add_control(struct form *form, struct form_control *control)
{
control->form = form;
 
if (form->controls != NULL) {
assert(form->last_control);
 
form->last_control->next = control;
control->prev = form->last_control;
control->next = NULL;
form->last_control = control;
} else {
form->controls = form->last_control = control;
}
}
 
 
/**
* Free a struct form_control.
*
* \param control structure to free
*/
void form_free_control(struct form_control *control)
{
free(control->name);
free(control->value);
free(control->initial_value);
 
if (control->type == GADGET_SELECT) {
struct form_option *option, *next;
 
for (option = control->data.select.items; option;
option = next) {
next = option->next;
free(option->text);
free(option->value);
free(option);
}
if (control->data.select.menu != NULL)
form_free_select_menu(control);
}
 
free(control);
}
 
 
/**
* Add an option to a form select control.
*
* \param control form control of type GADGET_SELECT
* \param value value of option, used directly (not copied)
* \param text text for option, used directly (not copied)
* \param selected this option is selected
* \return true on success, false on memory exhaustion
*/
bool form_add_option(struct form_control *control, char *value, char *text,
bool selected)
{
struct form_option *option;
 
assert(control);
assert(control->type == GADGET_SELECT);
 
option = calloc(1, sizeof *option);
if (!option)
return false;
 
option->value = value;
option->text = text;
 
/* add to linked list */
if (control->data.select.items == 0)
control->data.select.items = option;
else
control->data.select.last_item->next = option;
control->data.select.last_item = option;
 
/* set selected */
if (selected && (control->data.select.num_selected == 0 ||
control->data.select.multiple)) {
option->selected = option->initial_selected = true;
control->data.select.num_selected++;
control->data.select.current = option;
}
 
control->data.select.num_items++;
 
return true;
}
 
 
/**
* Identify 'successful' controls.
*
* All text strings in the successful controls list will be in the charset most
* appropriate for submission. Therefore, no utf8_to_* processing should be
* performed upon them.
*
* \todo The chosen charset needs to be made available such that it can be
* included in the submission request (e.g. in the fetch's Content-Type header)
*
* \param form form to search for successful controls
* \param submit_button control used to submit the form, if any
* \param successful_controls updated to point to linked list of
* fetch_multipart_data, 0 if no controls
* \return true on success, false on memory exhaustion
*
* See HTML 4.01 section 17.13.2.
*/
bool form_successful_controls(struct form *form,
struct form_control *submit_button,
struct fetch_multipart_data **successful_controls)
{
struct form_control *control;
struct form_option *option;
struct fetch_multipart_data sentinel, *last_success, *success_new;
char *value = NULL;
bool had_submit = false;
char *charset;
 
last_success = &sentinel;
sentinel.next = NULL;
 
charset = form_acceptable_charset(form);
if (!charset)
return false;
 
#define ENCODE_ITEM(i) form_encode_item((i), charset, form->document_charset)
 
for (control = form->controls; control; control = control->next) {
/* ignore disabled controls */
if (control->disabled)
continue;
 
/* ignore controls with no name */
if (!control->name)
continue;
 
switch (control->type) {
case GADGET_HIDDEN:
case GADGET_TEXTBOX:
case GADGET_PASSWORD:
if (control->value)
value = ENCODE_ITEM(control->value);
else
value = ENCODE_ITEM("");
if (!value) {
LOG(("failed to duplicate value"
"'%s' for control %s",
control->value,
control->name));
goto no_memory;
}
break;
 
case GADGET_RADIO:
case GADGET_CHECKBOX:
/* ignore checkboxes and radio buttons which
* aren't selected */
if (!control->selected)
continue;
if (control->value)
value = ENCODE_ITEM(control->value);
else
value = ENCODE_ITEM("on");
if (!value) {
LOG(("failed to duplicate"
"value '%s' for"
"control %s",
control->value,
control->name));
goto no_memory;
}
break;
 
case GADGET_SELECT:
/* select */
for (option = control->data.select.items;
option != NULL;
option = option->next) {
if (!option->selected)
continue;
success_new =
malloc(sizeof(*success_new));
if (!success_new) {
LOG(("malloc failed"));
goto no_memory;
}
success_new->file = false;
success_new->name =
ENCODE_ITEM(control->name);
success_new->value =
ENCODE_ITEM(option->value);
success_new->next = NULL;
last_success->next = success_new;
last_success = success_new;
if (!success_new->name ||
!success_new->value) {
LOG(("strdup failed"));
goto no_memory;
}
}
 
continue;
break;
 
case GADGET_TEXTAREA:
{
char *v2;
 
/* textarea */
value = form_textarea_value(control);
if (!value) {
LOG(("failed handling textarea"));
goto no_memory;
}
if (value[0] == 0) {
free(value);
continue;
}
 
v2 = ENCODE_ITEM(value);
if (!v2) {
LOG(("failed handling textarea"));
free(value);
goto no_memory;
}
 
free(value);
value = v2;
}
break;
 
case GADGET_IMAGE: {
/* image */
size_t len;
char *name;
 
if (control != submit_button)
/* only the activated submit button
* is successful */
continue;
 
name = ENCODE_ITEM(control->name);
if (name == NULL)
goto no_memory;
 
len = strlen(name) + 3;
 
/* x */
success_new = malloc(sizeof(*success_new));
if (!success_new) {
free(name);
LOG(("malloc failed"));
goto no_memory;
}
success_new->file = false;
success_new->name = malloc(len);
success_new->value = malloc(20);
if (!success_new->name ||
!success_new->value) {
free(success_new->name);
free(success_new->value);
free(success_new);
free(name);
LOG(("malloc failed"));
goto no_memory;
}
sprintf(success_new->name, "%s.x", name);
sprintf(success_new->value, "%i",
control->data.image.mx);
success_new->next = 0;
last_success->next = success_new;
last_success = success_new;
 
/* y */
success_new = malloc(sizeof(*success_new));
if (!success_new) {
free(name);
LOG(("malloc failed"));
goto no_memory;
}
success_new->file = false;
success_new->name = malloc(len);
success_new->value = malloc(20);
if (!success_new->name ||
!success_new->value) {
free(success_new->name);
free(success_new->value);
free(success_new);
free(name);
LOG(("malloc failed"));
goto no_memory;
}
sprintf(success_new->name, "%s.y", name);
sprintf(success_new->value, "%i",
control->data.image.my);
success_new->next = 0;
last_success->next = success_new;
last_success = success_new;
 
free(name);
 
continue;
break;
}
 
case GADGET_SUBMIT:
if (!submit_button && !had_submit)
/* no submit button specified, so
* use first declared in form */
had_submit = true;
else if (control != submit_button)
/* only the activated submit button
* is successful */
continue;
if (control->value)
value = ENCODE_ITEM(control->value);
else
value = ENCODE_ITEM("");
if (!value) {
LOG(("failed to duplicate value"
"'%s' for control %s",
control->value,
control->name));
goto no_memory;
}
break;
 
case GADGET_RESET:
/* ignore reset */
continue;
break;
 
case GADGET_FILE:
/* file */
/* Handling of blank file entries is
* implementation defined - we're perfectly
* within our rights to treat it as an
* unsuccessful control. Unfortunately, every
* other browser submits the field with
* a blank filename and no content. So,
* that's what we have to do, too.
*/
success_new = malloc(sizeof(*success_new));
if (!success_new) {
LOG(("malloc failed"));
goto no_memory;
}
success_new->file = true;
success_new->name = ENCODE_ITEM(control->name);
success_new->value =
ENCODE_ITEM(control->value ?
control->value : "");
success_new->next = 0;
last_success->next = success_new;
last_success = success_new;
if (!success_new->name ||
!success_new->value) {
LOG(("strdup failed"));
goto no_memory;
}
 
continue;
break;
 
case GADGET_BUTTON:
/* Ignore it */
continue;
break;
 
default:
assert(0);
break;
}
 
success_new = malloc(sizeof(*success_new));
if (!success_new) {
LOG(("malloc failed"));
goto no_memory;
}
success_new->file = false;
success_new->name = ENCODE_ITEM(control->name);
success_new->value = value;
success_new->next = NULL;
last_success->next = success_new;
last_success = success_new;
if (!success_new->name) {
LOG(("failed to duplicate name '%s'",
control->name));
goto no_memory;
}
}
 
*successful_controls = sentinel.next;
return true;
 
no_memory:
warn_user("NoMemory", 0);
fetch_multipart_data_destroy(sentinel.next);
return false;
 
#undef ENCODE_ITEM
}
 
 
/**
* Find the value for a textarea control.
*
* \param textarea control of type GADGET_TEXTAREA
* \return the value as a UTF-8 string on heap, or 0 on memory exhaustion
*/
char *form_textarea_value(struct form_control *textarea)
{
unsigned int len = 0;
char *value, *s;
struct box *text_box;
 
/* Textarea may have no associated box if styled with display: none */
if (textarea->box == NULL) {
/* Return the empty string: caller treats this as a
* non-successful control. */
return strdup("");
}
 
/* find required length */
for (text_box = textarea->box->children->children; text_box;
text_box = text_box->next) {
if (text_box->type == BOX_TEXT)
len += text_box->length + 1;
else /* BOX_BR */
len += 2;
}
 
/* construct value */
s = value = malloc(len + 1);
if (!s)
return NULL;
 
for (text_box = textarea->box->children->children; text_box;
text_box = text_box->next) {
if (text_box->type == BOX_TEXT) {
strncpy(s, text_box->text, text_box->length);
s += text_box->length;
if (text_box->next && text_box->next->type != BOX_BR)
/* only add space if this isn't
* the last box on a line (or in the area) */
*s++ = ' ';
} else { /* BOX_BR */
*s++ = '\r';
*s++ = '\n';
}
}
*s = 0;
 
return value;
}
 
 
/**
* Encode controls using application/x-www-form-urlencoded.
*
* \param form form to which successful controls relate
* \param control linked list of fetch_multipart_data
* \param query_string iff true add '?' to the start of returned data
* \return URL-encoded form, or 0 on memory exhaustion
*/
 
static char *form_url_encode(struct form *form,
struct fetch_multipart_data *control,
bool query_string)
{
char *name, *value;
char *s, *s2;
unsigned int len, len1, len_init;
url_func_result url_err;
 
if (query_string)
s = malloc(2);
else
s = malloc(1);
 
if (s == NULL)
return NULL;
 
if (query_string) {
s[0] = '?';
s[1] = '\0';
len_init = len = 1;
} else {
s[0] = '\0';
len_init = len = 0;
}
 
for (; control; control = control->next) {
url_err = url_escape(control->name, 0, true, NULL, &name);
if (url_err == URL_FUNC_NOMEM) {
free(s);
return NULL;
}
 
assert(url_err == URL_FUNC_OK);
 
url_err = url_escape(control->value, 0, true, NULL, &value);
if (url_err == URL_FUNC_NOMEM) {
free(name);
free(s);
return NULL;
}
 
assert(url_err == URL_FUNC_OK);
 
len1 = len + strlen(name) + strlen(value) + 2;
s2 = realloc(s, len1 + 1);
if (!s2) {
free(value);
free(name);
free(s);
return NULL;
}
s = s2;
sprintf(s + len, "%s=%s&", name, value);
len = len1;
free(name);
free(value);
}
 
if (len > len_init)
/* Replace trailing '&' */
s[len - 1] = '\0';
return s;
}
 
/**
* Find an acceptable character set encoding with which to submit the form
*
* \param form The form
* \return Pointer to charset name (on heap, caller should free) or NULL
*/
char *form_acceptable_charset(struct form *form)
{
char *temp, *c;
 
if (!form)
return NULL;
 
if (!form->accept_charsets) {
/* no accept-charsets attribute for this form */
if (form->document_charset)
/* document charset present, so use it */
return strdup(form->document_charset);
else
/* no document charset, so default to 8859-1 */
return strdup("ISO-8859-1");
}
 
/* make temporary copy of accept-charsets attribute */
temp = strdup(form->accept_charsets);
if (!temp)
return NULL;
 
/* make it upper case */
for (c = temp; *c; c++)
*c = toupper(*c);
 
/* is UTF-8 specified? */
c = strstr(temp, "UTF-8");
if (c) {
free(temp);
return strdup("UTF-8");
}
 
/* dispense with temporary copy */
free(temp);
 
/* according to RFC2070, the accept-charsets attribute of the
* form element contains a space and/or comma separated list */
c = form->accept_charsets;
 
/* What would be an improvement would be to choose an encoding
* acceptable to the server which covers as much of the input
* values as possible. Additionally, we need to handle the case
* where none of the acceptable encodings cover all the textual
* input values.
* For now, we just extract the first element of the charset list
*/
while (*c && !isspace(*c)) {
if (*c == ',')
break;
c++;
}
 
return strndup(form->accept_charsets, c - form->accept_charsets);
}
 
/**
* Convert a string from UTF-8 to the specified charset
* As a final fallback, this will attempt to convert to ISO-8859-1.
*
* \todo Return charset used?
*
* \param item String to convert
* \param charset Destination charset
* \param fallback Fallback charset (may be NULL),
* used iff converting to charset fails
* \return Pointer to converted string (on heap, caller frees), or NULL
*/
char *form_encode_item(const char *item, const char *charset,
const char *fallback)
{
utf8_convert_ret err;
char *ret = NULL;
char cset[256];
 
if (!item || !charset)
return NULL;
 
snprintf(cset, sizeof cset, "%s//TRANSLIT", charset);
 
err = utf8_to_enc(item, cset, 0, &ret);
if (err == UTF8_CONVERT_BADENC) {
/* charset not understood, try without transliteration */
snprintf(cset, sizeof cset, "%s", charset);
err = utf8_to_enc(item, cset, 0, &ret);
 
if (err == UTF8_CONVERT_BADENC) {
/* nope, try fallback charset (if any) */
if (fallback) {
snprintf(cset, sizeof cset,
"%s//TRANSLIT", fallback);
err = utf8_to_enc(item, cset, 0, &ret);
 
if (err == UTF8_CONVERT_BADENC) {
/* and without transliteration */
snprintf(cset, sizeof cset,
"%s", fallback);
err = utf8_to_enc(item, cset, 0, &ret);
}
}
 
if (err == UTF8_CONVERT_BADENC) {
/* that also failed, use 8859-1 */
err = utf8_to_enc(item, "ISO-8859-1//TRANSLIT",
0, &ret);
if (err == UTF8_CONVERT_BADENC) {
/* and without transliteration */
err = utf8_to_enc(item, "ISO-8859-1",
0, &ret);
}
}
}
}
if (err == UTF8_CONVERT_NOMEM) {
return NULL;
}
 
return ret;
}
 
/**
* Open a select menu for a select form control, creating it if necessary.
*
* \param client_data data passed to the redraw callback
* \param control the select form control for which the menu is being
* opened
* \param callback redraw callback for the select menu
* \param bw the browser window in which the select menu is being
* opened
* \return false on memory exhaustion, true otherwise
*/
bool form_open_select_menu(void *client_data,
struct form_control *control,
select_menu_redraw_callback callback,
struct content *c)
{
int line_height_with_spacing;
struct box *box;
plot_font_style_t fstyle;
int total_height;
struct form_select_menu *menu;
 
 
/* if the menu is opened for the first time */
if (control->data.select.menu == NULL) {
 
menu = calloc(1, sizeof (struct form_select_menu));
if (menu == NULL) {
warn_user("NoMemory", 0);
return false;
}
 
control->data.select.menu = menu;
 
box = control->box;
 
menu->width = box->width +
box->border[RIGHT].width +
box->border[LEFT].width +
box->padding[RIGHT] + box->padding[LEFT];
 
font_plot_style_from_css(control->box->style,
&fstyle);
menu->f_size = fstyle.size;
 
menu->line_height = FIXTOINT(FDIV((FMUL(FLTTOFIX(1.2),
FMUL(nscss_screen_dpi,
INTTOFIX(fstyle.size / FONT_SIZE_SCALE)))),
F_72));
 
line_height_with_spacing = menu->line_height +
menu->line_height *
SELECT_LINE_SPACING;
 
total_height = control->data.select.num_items *
line_height_with_spacing;
menu->height = total_height;
 
if (menu->height > MAX_SELECT_HEIGHT) {
 
menu->height = MAX_SELECT_HEIGHT;
}
menu->client_data = client_data;
menu->callback = callback;
if (!scrollbar_create(false,
menu->height,
total_height,
menu->height,
control,
form_select_menu_scroll_callback,
&(menu->scrollbar))) {
free(menu);
return false;
}
menu->c = c;
}
else menu = control->data.select.menu;
 
menu->callback(client_data, 0, 0, menu->width, menu->height);
 
return true;
}
 
 
/**
* Destroy a select menu and free allocated memory.
*
* \param control the select form control owning the select menu being
* destroyed
*/
void form_free_select_menu(struct form_control *control)
{
if (control->data.select.menu->scrollbar != NULL)
scrollbar_destroy(control->data.select.menu->scrollbar);
free(control->data.select.menu);
control->data.select.menu = NULL;
}
 
/**
* Redraw an opened select menu.
*
* \param control the select menu being redrawn
* \param x the X coordinate to draw the menu at
* \param x the Y coordinate to draw the menu at
* \param scale current redraw scale
* \param clip clipping rectangle
* \param ctx current redraw context
* \return true on success, false otherwise
*/
bool form_redraw_select_menu(struct form_control *control, int x, int y,
float scale, const struct rect *clip,
const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
struct box *box;
struct form_select_menu *menu = control->data.select.menu;
struct form_option *option;
int line_height, line_height_with_spacing;
int width, height;
int x0, y0, x1, scrollbar_x, y1, y2, y3;
int item_y;
int text_pos_offset, text_x;
int scrollbar_width = SCROLLBAR_WIDTH;
int i;
int scroll;
int x_cp, y_cp;
struct rect r;
box = control->box;
x_cp = x;
y_cp = y;
width = menu->width;
height = menu->height;
line_height = menu->line_height;
line_height_with_spacing = line_height +
line_height * SELECT_LINE_SPACING;
scroll = scrollbar_get_offset(menu->scrollbar);
if (scale != 1.0) {
x *= scale;
y *= scale;
width *= scale;
height *= scale;
scrollbar_width *= scale;
i = scroll / line_height_with_spacing;
scroll -= i * line_height_with_spacing;
line_height *= scale;
line_height_with_spacing *= scale;
scroll *= scale;
scroll += i * line_height_with_spacing;
}
x0 = x;
y0 = y;
x1 = x + width - 1;
y1 = y + height - 1;
scrollbar_x = x1 - scrollbar_width;
 
r.x0 = x0;
r.y0 = y0;
r.x1 = x1 + 1;
r.y1 = y1 + 1;
if (!plot->clip(&r))
return false;
if (!plot->rectangle(x0, y0, x1, y1 ,plot_style_stroke_darkwbasec))
return false;
x0 = x0 + SELECT_BORDER_WIDTH;
y0 = y0 + SELECT_BORDER_WIDTH;
x1 = x1 - SELECT_BORDER_WIDTH;
y1 = y1 - SELECT_BORDER_WIDTH;
height = height - 2 * SELECT_BORDER_WIDTH;
 
r.x0 = x0;
r.y0 = y0;
r.x1 = x1 + 1;
r.y1 = y1 + 1;
if (!plot->clip(&r))
return false;
if (!plot->rectangle(x0, y0, x1 + 1, y1 + 1,
plot_style_fill_lightwbasec))
return false;
option = control->data.select.items;
item_y = line_height_with_spacing;
while (item_y < scroll) {
option = option->next;
item_y += line_height_with_spacing;
}
item_y -= line_height_with_spacing;
text_pos_offset = y - scroll +
(int) (line_height * (0.75 + SELECT_LINE_SPACING));
text_x = x + (box->border[LEFT].width + box->padding[LEFT]) * scale;
plot_fstyle_entry.size = menu->f_size;
while (option && item_y - scroll < height) {
if (option->selected) {
y2 = y + item_y - scroll;
y3 = y + item_y + line_height_with_spacing - scroll;
if (!plot->rectangle(x0, (y0 > y2 ? y0 : y2),
scrollbar_x + 1,
(y3 < y1 + 1 ? y3 : y1 + 1),
&plot_style_fill_selected))
return false;
}
y2 = text_pos_offset + item_y;
if (!plot->text(text_x, y2, option->text,
strlen(option->text), &plot_fstyle_entry))
return false;
item_y += line_height_with_spacing;
option = option->next;
}
if (!scrollbar_redraw(menu->scrollbar,
x_cp + menu->width - SCROLLBAR_WIDTH,
y_cp,
clip, scale, ctx))
return false;
return true;
}
 
/**
* Check whether a clipping rectangle is completely contained in the
* select menu.
*
* \param control the select menu to check the clipping rectangle for
* \param scale the current browser window scale
* \param clip_x0 minimum x of clipping rectangle
* \param clip_y0 minimum y of clipping rectangle
* \param clip_x1 maximum x of clipping rectangle
* \param clip_y1 maximum y of clipping rectangle
* \return true if inside false otherwise
*/
bool form_clip_inside_select_menu(struct form_control *control, float scale,
const struct rect *clip)
{
struct form_select_menu *menu = control->data.select.menu;
int width, height;
 
width = menu->width;
height = menu->height;
if (scale != 1.0) {
width *= scale;
height *= scale;
}
if (clip->x0 >= 0 && clip->x1 <= width &&
clip->y0 >= 0 && clip->y1 <= height)
return true;
 
return false;
}
 
 
/**
* Process a selection from a form select menu.
*
* \param bw browser window with menu
* \param control form control with menu
* \param item index of item selected from the menu
*/
 
static void form__select_process_selection(html_content *html,
struct form_control *control, int item)
{
struct box *inline_box;
struct form_option *o;
int count;
 
assert(control != NULL);
assert(html != NULL);
 
/** \todo Even though the form code is effectively part of the html
* content handler, poking around inside contents is not good */
 
inline_box = control->box->children->children;
 
for (count = 0, o = control->data.select.items;
o != NULL;
count++, o = o->next) {
if (!control->data.select.multiple)
o->selected = false;
if (count == item) {
if (control->data.select.multiple) {
if (o->selected) {
o->selected = false;
control->data.select.num_selected--;
} else {
o->selected = true;
control->data.select.num_selected++;
}
} else {
o->selected = true;
}
}
if (o->selected)
control->data.select.current = o;
}
 
talloc_free(inline_box->text);
inline_box->text = 0;
if (control->data.select.num_selected == 0)
inline_box->text = talloc_strdup(html->bctx,
messages_get("Form_None"));
else if (control->data.select.num_selected == 1)
inline_box->text = talloc_strdup(html->bctx,
control->data.select.current->text);
else
inline_box->text = talloc_strdup(html->bctx,
messages_get("Form_Many"));
if (!inline_box->text) {
warn_user("NoMemory", 0);
inline_box->length = 0;
} else
inline_box->length = strlen(inline_box->text);
inline_box->width = control->box->width;
 
html__redraw_a_box(html, control->box);
}
 
 
void form_select_process_selection(hlcache_handle *h,
struct form_control *control, int item)
{
assert(h != NULL);
 
form__select_process_selection(
(html_content *)hlcache_handle_get_content(h),
control, item);
}
 
/**
* Handle a click on the area of the currently opened select menu.
*
* \param control the select menu which received the click
* \param x X coordinate of click
* \param y Y coordinate of click
*/
void form_select_menu_clicked(struct form_control *control, int x, int y)
{
struct form_select_menu *menu = control->data.select.menu;
struct form_option *option;
html_content *html = (html_content *)menu->c;
int line_height, line_height_with_spacing;
int item_bottom_y;
int scroll, i;
scroll = scrollbar_get_offset(menu->scrollbar);
line_height = menu->line_height;
line_height_with_spacing = line_height +
line_height * SELECT_LINE_SPACING;
option = control->data.select.items;
item_bottom_y = line_height_with_spacing;
i = 0;
while (option && item_bottom_y < scroll + y) {
item_bottom_y += line_height_with_spacing;
option = option->next;
i++;
}
if (option != NULL) {
form__select_process_selection(html, control, i);
}
menu->callback(menu->client_data, 0, 0, menu->width, menu->height);
}
 
/**
* Handle mouse action for the currently opened select menu.
*
* \param control the select menu which received the mouse action
* \param mouse current mouse state
* \param x X coordinate of click
* \param y Y coordinate of click
* \return text for the browser status bar or NULL if the menu has
* to be closed
*/
const char *form_select_mouse_action(struct form_control *control,
browser_mouse_state mouse, int x, int y)
{
struct form_select_menu *menu = control->data.select.menu;
int x0, y0, x1, y1, scrollbar_x;
const char *status = NULL;
bool multiple = control->data.select.multiple;
x0 = 0;
y0 = 0;
x1 = menu->width;
y1 = menu->height;
scrollbar_x = x1 - SCROLLBAR_WIDTH;
if (menu->scroll_capture ||
(x > scrollbar_x && x < x1 && y > y0 && y < y1)) {
/* The scroll is currently capturing all events or the mouse
* event is taking place on the scrollbar widget area
*/
x -= scrollbar_x;
return scrollbar_mouse_action(menu->scrollbar,
mouse, x, y);
}
if (x > x0 && x < scrollbar_x && y > y0 && y < y1) {
/* over option area */
if (mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2))
/* button 1 or 2 click */
form_select_menu_clicked(control, x, y);
if (!(mouse & BROWSER_MOUSE_CLICK_1 && !multiple))
/* anything but a button 1 click over a single select
menu */
status = messages_get(control->data.select.multiple ?
"SelectMClick" : "SelectClick");
} else if (!(mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2)))
/* if not a button 1 or 2 click*/
status = messages_get("SelectClose");
return status;
}
 
/**
* Handle mouse drag end for the currently opened select menu.
*
* \param control the select menu which received the mouse drag end
* \param mouse current mouse state
* \param x X coordinate of drag end
* \param y Y coordinate of drag end
*/
void form_select_mouse_drag_end(struct form_control *control,
browser_mouse_state mouse, int x, int y)
{
int x0, y0, x1, y1;
int box_x, box_y;
struct box *box;
struct form_select_menu *menu = control->data.select.menu;
 
box = control->box;
 
/* Get global coords of scrollbar */
box_coords(box, &box_x, &box_y);
box_x -= box->border[LEFT].width;
box_y += box->height + box->border[BOTTOM].width +
box->padding[BOTTOM] + box->padding[TOP];
 
/* Get drag end coords relative to scrollbar */
x = x - box_x;
y = y - box_y;
 
if (menu->scroll_capture) {
x -= menu->width - SCROLLBAR_WIDTH;
scrollbar_mouse_drag_end(menu->scrollbar, mouse, x, y);
return;
}
x0 = 0;
y0 = 0;
x1 = menu->width;
y1 = menu->height;
if (x > x0 && x < x1 - SCROLLBAR_WIDTH && y > y0 && y < y1)
/* handle drag end above the option area like a regular click */
form_select_menu_clicked(control, x, y);
}
 
/**
* Callback for the select menus scroll
*/
void form_select_menu_scroll_callback(void *client_data,
struct scrollbar_msg_data *scrollbar_data)
{
struct form_control *control = client_data;
struct form_select_menu *menu = control->data.select.menu;
html_content *html = (html_content *)menu->c;
switch (scrollbar_data->msg) {
case SCROLLBAR_MSG_MOVED:
menu->callback(menu->client_data,
0, 0,
menu->width,
menu->height);
break;
case SCROLLBAR_MSG_SCROLL_START:
{
struct rect rect = {
.x0 = scrollbar_data->x0,
.y0 = scrollbar_data->y0,
.x1 = scrollbar_data->x1,
.y1 = scrollbar_data->y1
};
 
browser_window_set_drag_type(html->bw,
DRAGGING_CONTENT_SCROLLBAR, &rect);
 
menu->scroll_capture = true;
}
break;
case SCROLLBAR_MSG_SCROLL_FINISHED:
menu->scroll_capture = false;
 
browser_window_set_drag_type(html->bw,
DRAGGING_NONE, NULL);
break;
default:
break;
}
}
 
/**
* Get the dimensions of a select menu.
*
* \param control the select menu to get the dimensions of
* \param width gets updated to menu width
* \param height gets updated to menu height
*/
void form_select_get_dimensions(struct form_control *control,
int *width, int *height)
{
*width = control->data.select.menu->width;
*height = control->data.select.menu->height;
}
 
/**
* Callback for the core select menu.
*/
void form_select_menu_callback(void *client_data,
int x, int y, int width, int height)
{
html_content *html = client_data;
int menu_x, menu_y;
struct box *box;
box = html->visible_select_menu->box;
box_coords(box, &menu_x, &menu_y);
menu_x -= box->border[LEFT].width;
menu_y += box->height + box->border[BOTTOM].width +
box->padding[BOTTOM] +
box->padding[TOP];
content__request_redraw((struct content *)html, menu_x + x, menu_y + y,
width, height);
}
 
 
/**
* Set a radio form control and clear the others in the group.
*
* \param content content containing the form, of type CONTENT_TYPE
* \param radio form control of type GADGET_RADIO
*/
 
void form_radio_set(html_content *html,
struct form_control *radio)
{
struct form_control *control;
 
assert(html);
assert(radio);
if (!radio->form)
return;
 
if (radio->selected)
return;
 
for (control = radio->form->controls; control;
control = control->next) {
if (control->type != GADGET_RADIO)
continue;
if (control == radio)
continue;
if (strcmp(control->name, radio->name) != 0)
continue;
 
if (control->selected) {
control->selected = false;
html__redraw_a_box(html, control->box);
}
}
 
radio->selected = true;
html__redraw_a_box(html, radio->box);
}
 
 
/**
* Collect controls and submit a form.
*/
 
void form_submit(nsurl *page_url, struct browser_window *target,
struct form *form, struct form_control *submit_button)
{
char *data = NULL;
struct fetch_multipart_data *success;
nsurl *action;
nsurl *action_query;
 
assert(form != NULL);
 
if (form_successful_controls(form, submit_button, &success) == false) {
warn_user("NoMemory", 0);
return;
}
 
switch (form->method) {
case method_GET:
data = form_url_encode(form, success, true);
if (data == NULL) {
fetch_multipart_data_destroy(success);
warn_user("NoMemory", 0);
return;
}
 
/* Decompose action */
if (nsurl_create(form->action, &action) != NSERROR_OK) {
free(data);
fetch_multipart_data_destroy(success);
warn_user("NoMemory", 0);
return;
}
 
/* Replace query segment */
if (nsurl_replace_query(action, data, &action_query) !=
NSERROR_OK) {
nsurl_unref(action);
free(data);
fetch_multipart_data_destroy(success);
warn_user("NoMemory", 0);
return;
}
 
/* Construct submit url */
browser_window_go(target, nsurl_access(action_query),
nsurl_access(page_url), true);
nsurl_unref(action);
nsurl_unref(action_query);
break;
 
case method_POST_URLENC:
data = form_url_encode(form, success, false);
if (data == NULL) {
fetch_multipart_data_destroy(success);
warn_user("NoMemory", 0);
return;
}
 
browser_window_go_post(target, form->action, data, 0,
true, nsurl_access(page_url), false, true, 0);
break;
 
case method_POST_MULTIPART:
browser_window_go_post(target, form->action, 0, success,
true, nsurl_access(page_url), false, true, 0);
break;
}
 
fetch_multipart_data_destroy(success);
free(data);
}
/programs/network/netsurf/netsurf/render/form.h
0,0 → 1,179
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2003 James Bursa <bursa@users.sourceforge.net>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Form handling functions (interface).
*/
 
#ifndef _NETSURF_RENDER_FORM_H_
#define _NETSURF_RENDER_FORM_H_
 
#include <stdbool.h>
#include "desktop/browser.h"
#include "utils/config.h"
 
struct box;
struct form_control;
struct form_option;
struct form_select_menu;
struct html_content;
 
/** Form submit method. */
typedef enum {
method_GET, /**< GET, always url encoded. */
method_POST_URLENC, /**< POST, url encoded. */
method_POST_MULTIPART /**< POST, multipart/form-data. */
} form_method;
 
/** HTML form. */
struct form {
void *node; /**< Corresponding DOM node */
 
char *action; /**< Absolute URL to submit to. */
char *target; /**< Target to submit to. */
form_method method; /**< Method and enctype. */
char *accept_charsets; /**< Charset to submit form in */
char *document_charset; /**< Charset of document containing form */
struct form_control *controls; /**< Linked list of controls. */
struct form_control *last_control; /**< Last control in list. */
 
struct form *prev; /**< Previous form in doc. */
};
 
/** Type of a struct form_control. */
typedef enum {
GADGET_HIDDEN,
GADGET_TEXTBOX,
GADGET_RADIO,
GADGET_CHECKBOX,
GADGET_SELECT,
GADGET_TEXTAREA,
GADGET_IMAGE,
GADGET_PASSWORD,
GADGET_SUBMIT,
GADGET_RESET,
GADGET_FILE,
GADGET_BUTTON
} form_control_type;
 
/** Form control. */
struct form_control {
void *node; /**< Corresponding DOM node */
 
form_control_type type; /**< Type of control */
 
struct form *form; /**< Containing form */
 
char *name; /**< Control name */
char *value; /**< Current value of control */
char *initial_value; /**< Initial value of control */
bool disabled; /**< Whether control is disabled */
 
struct box *box; /**< Box for control */
/** Caret details. */
struct box *caret_inline_container;
struct box *caret_text_box;
size_t caret_box_offset, caret_form_offset;
int caret_pixel_offset;
 
unsigned int length; /**< Number of characters in control */
unsigned int maxlength; /**< Maximum characters permitted */
 
bool selected; /**< Whether control is selected */
 
union {
struct {
int mx, my;
} image;
struct {
int num_items;
struct form_option *items, *last_item;
bool multiple;
int num_selected;
/** Currently selected item, if num_selected == 1. */
struct form_option *current;
struct form_select_menu *menu;
} select;
} data;
 
struct form_control *prev; /**< Previous control in this form */
struct form_control *next; /**< Next control in this form. */
};
 
/** Option in a select. */
struct form_option {
bool selected;
bool initial_selected;
char *value;
char *text; /**< NUL terminated. */
struct form_option* next;
};
 
/**
* Called by the select menu when it wants an area to be redrawn. The
* coordinates are menu origin relative.
*
* \param client_data data which was passed to form_open_select_menu
* \param x X coordinate of redraw rectangle
* \param y Y coordinate of redraw rectangle
* \param width width of redraw rectangle
* \param height height of redraw rectangle
*/
typedef void(*select_menu_redraw_callback)(void *client_data,
int x, int y, int width, int height);
 
struct form *form_new(void *node, const char *action, const char *target,
form_method method, const char *charset,
const char *doc_charset);
void form_free(struct form *form);
struct form_control *form_new_control(void *node, form_control_type type);
void form_add_control(struct form *form, struct form_control *control);
void form_free_control(struct form_control *control);
bool form_add_option(struct form_control *control, char *value, char *text,
bool selected);
bool form_successful_controls(struct form *form,
struct form_control *submit_button,
struct fetch_multipart_data **successful_controls);
 
bool form_open_select_menu(void *client_data,
struct form_control *control,
select_menu_redraw_callback redraw_callback,
struct content *c);
void form_select_menu_callback(void *client_data,
int x, int y, int width, int height);
void form_free_select_menu(struct form_control *control);
bool form_redraw_select_menu(struct form_control *control, int x, int y,
float scale, const struct rect *clip,
const struct redraw_context *ctx);
bool form_clip_inside_select_menu(struct form_control *control, float scale,
const struct rect *clip);
const char *form_select_mouse_action(struct form_control *control,
browser_mouse_state mouse, int x, int y);
void form_select_mouse_drag_end(struct form_control *control,
browser_mouse_state mouse, int x, int y);
void form_select_get_dimensions(struct form_control *control,
int *width, int *height);
void form_select_process_selection(hlcache_handle *h,
struct form_control *control, int item);
void form_submit(nsurl *page_url, struct browser_window *target,
struct form *form, struct form_control *submit_button);
void form_radio_set(struct html_content *html, struct form_control *radio);
 
#endif
/programs/network/netsurf/netsurf/render/html.c
0,0 → 1,3262
/*
* Copyright 2007 James Bursa <bursa@users.sourceforge.net>
* Copyright 2010 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for text/html (implementation).
*/
 
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
 
#include "utils/config.h"
#include "content/content_protected.h"
#include "content/fetch.h"
#include "content/hlcache.h"
#include "desktop/options.h"
#include "desktop/selection.h"
#include "desktop/scrollbar.h"
#include "image/bitmap.h"
#include "render/box.h"
#include "render/font.h"
#include "render/form.h"
#include "render/html_internal.h"
#include "render/imagemap.h"
#include "render/layout.h"
#include "render/search.h"
#include "javascript/js.h"
#include "utils/corestrings.h"
#include "utils/http.h"
#include "utils/libdom.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/schedule.h"
#include "utils/talloc.h"
#include "utils/url.h"
#include "utils/utf8.h"
#include "utils/utils.h"
 
#define CHUNK 4096
 
/* Change these to 1 to cause a dump to stderr of the frameset or box
* when the trees have been built.
*/
#define ALWAYS_DUMP_FRAMESET 0
#define ALWAYS_DUMP_BOX 0
 
static const char *html_types[] = {
"application/xhtml+xml",
"text/html"
};
 
/* forward declared functions */
static void html_object_refresh(void *p);
 
/* pre-interned character set */
static lwc_string *html_charset;
 
static nsurl *html_default_stylesheet_url;
static nsurl *html_adblock_stylesheet_url;
static nsurl *html_quirks_stylesheet_url;
static nsurl *html_user_stylesheet_url;
 
static nserror css_error_to_nserror(css_error error)
{
switch (error) {
case CSS_OK:
return NSERROR_OK;
 
case CSS_NOMEM:
return NSERROR_NOMEM;
 
case CSS_BADPARM:
return NSERROR_BAD_PARAMETER;
 
case CSS_INVALID:
return NSERROR_INVALID;
 
case CSS_FILENOTFOUND:
return NSERROR_NOT_FOUND;
 
case CSS_NEEDDATA:
return NSERROR_NEED_DATA;
 
case CSS_BADCHARSET:
return NSERROR_BAD_ENCODING;
 
case CSS_EOF:
case CSS_IMPORTS_PENDING:
case CSS_PROPERTY_NOT_SET:
default:
break;
}
return NSERROR_CSS;
}
 
 
static void html_destroy_objects(html_content *html)
{
while (html->object_list != NULL) {
struct content_html_object *victim = html->object_list;
 
if (victim->content != NULL) {
LOG(("object %p", victim->content));
 
if (content_get_type(victim->content) == CONTENT_HTML)
schedule_remove(html_object_refresh, victim);
 
hlcache_handle_release(victim->content);
}
 
html->object_list = victim->next;
free(victim);
}
}
 
/**
* Perform post-box-creation conversion of a document
*
* \param c HTML content to complete conversion of
* \param success Whether box tree construction was successful
*/
static void html_box_convert_done(html_content *c, bool success)
{
nserror err;
dom_exception exc; /* returned by libdom functions */
dom_node *html;
 
LOG(("Done XML to box (%p)", c));
 
/* Clean up and report error if unsuccessful or aborted */
if ((success == false) || (c->aborted)) {
html_destroy_objects(c);
 
if (success == false) {
content_broadcast_errorcode(&c->base, NSERROR_BOX_CONVERT);
} else {
content_broadcast_errorcode(&c->base, NSERROR_STOPPED);
}
 
content_set_error(&c->base);
return;
}
 
 
#if ALWAYS_DUMP_BOX
box_dump(stderr, c->layout->children, 0);
#endif
#if ALWAYS_DUMP_FRAMESET
if (c->frameset)
html_dump_frameset(c->frameset, 0);
#endif
 
exc = dom_document_get_document_element(c->document, (void *) &html);
if ((exc != DOM_NO_ERR) || (html == NULL)) {
/** @todo should this call html_destroy_objects(c);
* like the other error paths
*/
LOG(("error retrieving html element from dom"));
content_broadcast_errorcode(&c->base, NSERROR_DOM);
content_set_error(&c->base);
return;
}
 
/* extract image maps - can't do this sensibly in dom_to_box */
err = imagemap_extract(c);
if (err != NSERROR_OK) {
LOG(("imagemap extraction failed"));
html_destroy_objects(c);
content_broadcast_errorcode(&c->base, err);
content_set_error(&c->base);
dom_node_unref(html);
return;
}
/*imagemap_dump(c);*/
 
/* Destroy the parser binding */
dom_hubbub_parser_destroy(c->parser);
c->parser = NULL;
 
content_set_ready(&c->base);
 
if (c->base.active == 0) {
content_set_done(&c->base);
}
 
html_set_status(c, "");
dom_node_unref(html);
}
 
 
/**
* Complete conversion of an HTML document
*
* \param c Content to convert
*/
void html_finish_conversion(html_content *c)
{
union content_msg_data msg_data;
dom_exception exc; /* returned by libdom functions */
dom_node *html;
uint32_t i;
css_error css_ret;
nserror error;
 
/* Bail out if we've been aborted */
if (c->aborted) {
content_broadcast_errorcode(&c->base, NSERROR_STOPPED);
content_set_error(&c->base);
return;
}
 
/* check that the base stylesheet loaded; layout fails without it */
if (c->stylesheets[STYLESHEET_BASE].data.external == NULL) {
content_broadcast_errorcode(&c->base, NSERROR_CSS_BASE);
content_set_error(&c->base);
return;
}
 
/* Create selection context */
css_ret = css_select_ctx_create(ns_realloc, c, &c->select_ctx);
if (css_ret != CSS_OK) {
content_broadcast_errorcode(&c->base,
css_error_to_nserror(css_ret));
content_set_error(&c->base);
return;
}
 
/* Add sheets to it */
for (i = STYLESHEET_BASE; i != c->stylesheet_count; i++) {
const struct html_stylesheet *hsheet = &c->stylesheets[i];
css_stylesheet *sheet;
css_origin origin = CSS_ORIGIN_AUTHOR;
 
if (i < STYLESHEET_USER)
origin = CSS_ORIGIN_UA;
else if (i < STYLESHEET_START)
origin = CSS_ORIGIN_USER;
 
if (hsheet->type == HTML_STYLESHEET_EXTERNAL &&
hsheet->data.external != NULL) {
sheet = nscss_get_stylesheet(hsheet->data.external);
} else if (hsheet->type == HTML_STYLESHEET_INTERNAL) {
sheet = hsheet->data.internal->sheet;
} else {
sheet = NULL;
}
 
if (sheet != NULL) {
css_ret = css_select_ctx_append_sheet(c->select_ctx,
sheet,
origin,
CSS_MEDIA_SCREEN);
if (css_ret != CSS_OK) {
content_broadcast_errorcode(&c->base,
css_error_to_nserror(css_ret));
content_set_error(&c->base);
return;
}
}
}
 
/* fire a simple event named load at the Document's Window
* object, but with its target set to the Document object (and
* the currentTarget set to the Window object)
*/
js_fire_event(c->jscontext, "load", c->document, NULL);
 
/* convert dom tree to box tree */
LOG(("DOM to box (%p)", c));
content_set_status(&c->base, messages_get("Processing"));
msg_data.explicit_status_text = NULL;
content_broadcast(&c->base, CONTENT_MSG_STATUS, msg_data);
 
exc = dom_document_get_document_element(c->document, (void *) &html);
if ((exc != DOM_NO_ERR) || (html == NULL)) {
LOG(("error retrieving html element from dom"));
content_broadcast_errorcode(&c->base, NSERROR_DOM);
content_set_error(&c->base);
return;
}
 
error = dom_to_box(html, c, html_box_convert_done);
if (error != NSERROR_OK) {
dom_node_unref(html);
html_destroy_objects(c);
content_broadcast_errorcode(&c->base, error);
content_set_error(&c->base);
return;
}
 
dom_node_unref(html);
}
 
 
 
static nserror
html_create_html_data(html_content *c, const http_parameter *params)
{
lwc_string *charset;
nserror nerror;
dom_hubbub_parser_params parse_params;
dom_hubbub_error error;
 
c->parser = NULL;
c->document = NULL;
c->quirks = DOM_DOCUMENT_QUIRKS_MODE_NONE;
c->encoding = NULL;
c->base_url = nsurl_ref(content_get_url(&c->base));
c->base_target = NULL;
c->aborted = false;
c->bctx = NULL;
c->layout = NULL;
c->background_colour = NS_TRANSPARENT;
c->stylesheet_count = 0;
c->stylesheets = NULL;
c->select_ctx = NULL;
c->universal = NULL;
c->num_objects = 0;
c->object_list = NULL;
c->forms = NULL;
c->imagemaps = NULL;
c->bw = NULL;
c->frameset = NULL;
c->iframe = NULL;
c->page = NULL;
c->font_func = &nsfont;
c->scrollbar = NULL;
c->scripts_count = 0;
c->scripts = NULL;
c->jscontext = NULL;
 
c->base.active = 1; /* The html content itself is active */
 
if (lwc_intern_string("*", SLEN("*"), &c->universal) != lwc_error_ok) {
return NSERROR_NOMEM;
}
 
selection_prepare(&c->sel, (struct content *)c, true);
 
nerror = http_parameter_list_find_item(params, html_charset, &charset);
if (nerror == NSERROR_OK) {
c->encoding = strdup(lwc_string_data(charset));
 
lwc_string_unref(charset);
 
if (c->encoding == NULL) {
lwc_string_unref(c->universal);
c->universal = NULL;
return NSERROR_NOMEM;
 
}
c->encoding_source = DOM_HUBBUB_ENCODING_SOURCE_HEADER;
}
 
/* Create the parser binding */
parse_params.enc = c->encoding;
parse_params.fix_enc = true;
parse_params.enable_script = nsoption_bool(enable_javascript);
parse_params.msg = NULL;
parse_params.script = html_process_script;
parse_params.ctx = c;
parse_params.daf = NULL;
 
error = dom_hubbub_parser_create(&parse_params,
&c->parser,
&c->document);
if ((error != DOM_HUBBUB_OK) && (c->encoding != NULL)) {
/* Ok, we don't support the declared encoding. Bailing out
* isn't exactly user-friendly, so fall back to autodetect */
free(c->encoding);
c->encoding = NULL;
 
parse_params.enc = c->encoding;
 
error = dom_hubbub_parser_create(&parse_params,
&c->parser,
&c->document);
}
 
if (error != DOM_HUBBUB_OK) {
nsurl_unref(c->base_url);
c->base_url = NULL;
 
lwc_string_unref(c->universal);
c->universal = NULL;
 
return libdom_hubbub_error_to_nserror(error);
}
 
return NSERROR_OK;
 
}
 
/**
* Create a CONTENT_HTML.
*
* The content_html_data structure is initialized and the HTML parser is
* created.
*/
 
static nserror
html_create(const content_handler *handler,
lwc_string *imime_type,
const http_parameter *params,
llcache_handle *llcache,
const char *fallback_charset,
bool quirks,
struct content **c)
{
html_content *html;
nserror error;
 
html = calloc(1, sizeof(html_content));
if (html == NULL)
return NSERROR_NOMEM;
 
error = content__init(&html->base, handler, imime_type, params,
llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(html);
return error;
}
 
error = html_create_html_data(html, params);
if (error != NSERROR_OK) {
content_broadcast_errorcode(&html->base, error);
free(html);
return error;
}
 
*c = (struct content *) html;
 
return NSERROR_OK;
}
 
 
 
static nserror
html_process_encoding_change(struct content *c,
const char *data,
unsigned int size)
{
html_content *html = (html_content *) c;
dom_hubbub_parser_params parse_params;
dom_hubbub_error error;
const char *encoding;
const char *source_data;
unsigned long source_size;
 
/* Retrieve new encoding */
encoding = dom_hubbub_parser_get_encoding(html->parser,
&html->encoding_source);
if (encoding == NULL) {
return NSERROR_NOMEM;
}
 
if (html->encoding != NULL) {
free(html->encoding);
}
 
html->encoding = strdup(encoding);
if (html->encoding == NULL) {
return NSERROR_NOMEM;
}
 
/* Destroy binding */
dom_hubbub_parser_destroy(html->parser);
html->parser = NULL;
 
if (html->document != NULL) {
dom_node_unref(html->document);
}
 
parse_params.enc = html->encoding;
parse_params.fix_enc = true;
parse_params.enable_script = nsoption_bool(enable_javascript);
parse_params.msg = NULL;
parse_params.script = html_process_script;
parse_params.ctx = html;
parse_params.daf = NULL;
 
/* Create new binding, using the new encoding */
error = dom_hubbub_parser_create(&parse_params,
&html->parser,
&html->document);
if (error != DOM_HUBBUB_OK) {
/* Ok, we don't support the declared encoding. Bailing out
* isn't exactly user-friendly, so fall back to Windows-1252 */
free(html->encoding);
html->encoding = strdup("Windows-1252");
if (html->encoding == NULL) {
return NSERROR_NOMEM;
}
parse_params.enc = html->encoding;
 
error = dom_hubbub_parser_create(&parse_params,
&html->parser,
&html->document);
 
if (error != DOM_HUBBUB_OK) {
return libdom_hubbub_error_to_nserror(error);
}
 
}
 
source_data = content__get_source_data(c, &source_size);
 
/* Reprocess all the data. This is safe because
* the encoding is now specified at parser start which means
* it cannot be changed again.
*/
error = dom_hubbub_parser_parse_chunk(html->parser,
(const uint8_t *)source_data,
source_size);
 
return libdom_hubbub_error_to_nserror(error);
}
 
 
/**
* Process data for CONTENT_HTML.
*/
 
static bool
html_process_data(struct content *c, const char *data, unsigned int size)
{
html_content *html = (html_content *) c;
dom_hubbub_error dom_ret;
nserror err = NSERROR_OK; /* assume its all going to be ok */
 
dom_ret = dom_hubbub_parser_parse_chunk(html->parser,
(const uint8_t *) data,
size);
 
err = libdom_hubbub_error_to_nserror(dom_ret);
 
/* deal with encoding change */
if (err == NSERROR_ENCODING_CHANGE) {
err = html_process_encoding_change(c, data, size);
}
 
/* broadcast the error if necessary */
if (err != NSERROR_OK) {
content_broadcast_errorcode(c, err);
return false;
}
 
return true;
}
 
 
/** process link node */
static bool html_process_link(html_content *c, dom_node *node)
{
struct content_rfc5988_link link; /* the link added to the content */
dom_exception exc; /* returned by libdom functions */
dom_string *atr_string;
nserror error;
 
memset(&link, 0, sizeof(struct content_rfc5988_link));
 
/* check that the relation exists - w3c spec says must be present */
exc = dom_element_get_attribute(node, corestring_dom_rel, &atr_string);
if ((exc != DOM_NO_ERR) || (atr_string == NULL)) {
return false;
}
/* get a lwc string containing the link relation */
exc = dom_string_intern(atr_string, &link.rel);
dom_string_unref(atr_string);
if (exc != DOM_NO_ERR) {
return false;
}
 
/* check that the href exists - w3c spec says must be present */
exc = dom_element_get_attribute(node, corestring_dom_href, &atr_string);
if ((exc != DOM_NO_ERR) || (atr_string == NULL)) {
lwc_string_unref(link.rel);
return false;
}
 
/* get nsurl */
error = nsurl_join(c->base_url, dom_string_data(atr_string),
&link.href);
dom_string_unref(atr_string);
if (error != NSERROR_OK) {
lwc_string_unref(link.rel);
return false;
}
 
/* look for optional properties -- we don't care if internment fails */
 
exc = dom_element_get_attribute(node,
corestring_dom_hreflang, &atr_string);
if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
/* get a lwc string containing the href lang */
exc = dom_string_intern(atr_string, &link.hreflang);
dom_string_unref(atr_string);
}
 
exc = dom_element_get_attribute(node,
corestring_dom_type, &atr_string);
if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
/* get a lwc string containing the type */
exc = dom_string_intern(atr_string, &link.type);
dom_string_unref(atr_string);
}
 
exc = dom_element_get_attribute(node,
corestring_dom_media, &atr_string);
if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
/* get a lwc string containing the media */
exc = dom_string_intern(atr_string, &link.media);
dom_string_unref(atr_string);
}
 
exc = dom_element_get_attribute(node,
corestring_dom_sizes, &atr_string);
if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
/* get a lwc string containing the sizes */
exc = dom_string_intern(atr_string, &link.sizes);
dom_string_unref(atr_string);
}
 
/* add to content */
content__add_rfc5988_link(&c->base, &link);
 
if (link.sizes != NULL)
lwc_string_unref(link.sizes);
if (link.media != NULL)
lwc_string_unref(link.media);
if (link.type != NULL)
lwc_string_unref(link.type);
if (link.hreflang != NULL)
lwc_string_unref(link.hreflang);
 
nsurl_unref(link.href);
lwc_string_unref(link.rel);
 
return true;
}
 
/** process title node */
static bool html_process_title(html_content *c, dom_node *node)
{
dom_exception exc; /* returned by libdom functions */
dom_string *title;
char *title_str;
bool success;
 
if (c->base.title != NULL)
return true;
 
exc = dom_node_get_text_content(node, &title);
if ((exc != DOM_NO_ERR) || (title == NULL)) {
return false;
}
 
title_str = squash_whitespace(dom_string_data(title));
dom_string_unref(title);
 
if (title_str == NULL) {
return false;
}
 
success = content__set_title(&c->base, title_str);
 
free(title_str);
 
return success;
}
 
static bool html_process_base(html_content *c, dom_node *node)
{
dom_exception exc; /* returned by libdom functions */
dom_string *atr_string;
 
/* get href attribute if present */
exc = dom_element_get_attribute(node,
corestring_dom_href, &atr_string);
if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
nsurl *url;
nserror error;
 
/* get url from string */
error = nsurl_create(dom_string_data(atr_string), &url);
dom_string_unref(atr_string);
if (error == NSERROR_OK) {
if (c->base_url != NULL)
nsurl_unref(c->base_url);
c->base_url = url;
}
}
 
 
/* get target attribute if present and not already set */
if (c->base_target != NULL) {
return true;
}
 
exc = dom_element_get_attribute(node,
corestring_dom_target, &atr_string);
if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
/* Validation rules from the HTML5 spec for the base element:
* The target must be one of _blank, _self, _parent, or
* _top or any identifier which does not begin with an
* underscore
*/
if (*dom_string_data(atr_string) != '_' ||
dom_string_caseless_lwc_isequal(atr_string,
corestring_lwc__blank) ||
dom_string_caseless_lwc_isequal(atr_string,
corestring_lwc__self) ||
dom_string_caseless_lwc_isequal(atr_string,
corestring_lwc__parent) ||
dom_string_caseless_lwc_isequal(atr_string,
corestring_lwc__top)) {
c->base_target = strdup(dom_string_data(atr_string));
}
dom_string_unref(atr_string);
}
 
return true;
}
 
/**
* Process elements in <head>.
*
* \param c content structure
* \param head xml node of head element
* \return true on success, false on memory exhaustion
*
* The title and base href are extracted if present.
*/
 
static nserror html_head(html_content *c, dom_node *head)
{
dom_node *node;
dom_exception exc; /* returned by libdom functions */
dom_string *node_name;
dom_node_type node_type;
dom_node *next_node;
 
exc = dom_node_get_first_child(head, &node);
if (exc != DOM_NO_ERR) {
return NSERROR_DOM;
}
 
while (node != NULL) {
exc = dom_node_get_node_type(node, &node_type);
 
if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
exc = dom_node_get_node_name(node, &node_name);
 
if ((exc == DOM_NO_ERR) && (node_name != NULL)) {
if (dom_string_caseless_lwc_isequal(
node_name,
corestring_lwc_title)) {
html_process_title(c, node);
} else if (dom_string_caseless_lwc_isequal(
node_name,
corestring_lwc_base)) {
html_process_base(c, node);
} else if (dom_string_caseless_lwc_isequal(
node_name,
corestring_lwc_link)) {
html_process_link(c, node);
}
}
if (node_name != NULL) {
dom_string_unref(node_name);
}
}
 
/* move to next node */
exc = dom_node_get_next_sibling(node, &next_node);
dom_node_unref(node);
if (exc == DOM_NO_ERR) {
node = next_node;
} else {
node = NULL;
}
}
 
return NSERROR_OK;
}
 
static nserror html_meta_refresh_process_element(html_content *c, dom_node *n)
{
union content_msg_data msg_data;
const char *url, *end, *refresh = NULL;
char *new_url;
char quote = '\0';
dom_string *equiv, *content;
dom_exception exc;
nsurl *nsurl;
nserror error = NSERROR_OK;
 
exc = dom_element_get_attribute(n, corestring_dom_http_equiv, &equiv);
if (exc != DOM_NO_ERR) {
return NSERROR_DOM;
}
 
if (equiv == NULL) {
return NSERROR_OK;
}
 
if (!dom_string_caseless_lwc_isequal(equiv, corestring_lwc_refresh)) {
dom_string_unref(equiv);
return NSERROR_OK;
}
 
dom_string_unref(equiv);
 
exc = dom_element_get_attribute(n, corestring_dom_content, &content);
if (exc != DOM_NO_ERR) {
return NSERROR_DOM;
}
 
if (content == NULL) {
return NSERROR_OK;
}
 
end = dom_string_data(content) + dom_string_byte_length(content);
 
/* content := *LWS intpart fracpart? *LWS [';' *LWS *1url *LWS]
* intpart := 1*DIGIT
* fracpart := 1*('.' | DIGIT)
* url := "url" *LWS '=' *LWS (url-nq | url-sq | url-dq)
* url-nq := *urlchar
* url-sq := "'" *(urlchar | '"') "'"
* url-dq := '"' *(urlchar | "'") '"'
* urlchar := [#x9#x21#x23-#x26#x28-#x7E] | nonascii
* nonascii := [#x80-#xD7FF#xE000-#xFFFD#x10000-#x10FFFF]
*/
 
url = dom_string_data(content);
 
/* *LWS */
while (url < end && isspace(*url)) {
url++;
}
 
/* intpart */
if (url == end || (*url < '0' || '9' < *url)) {
/* Empty content, or invalid timeval */
dom_string_unref(content);
return NSERROR_OK;
}
 
msg_data.delay = (int) strtol(url, &new_url, 10);
/* a very small delay and self-referencing URL can cause a loop
* that grinds machines to a halt. To prevent this we set a
* minimum refresh delay of 1s. */
if (msg_data.delay < 1) {
msg_data.delay = 1;
}
 
url = new_url;
 
/* fracpart? (ignored, as delay is integer only) */
while (url < end && (('0' <= *url && *url <= '9') ||
*url == '.')) {
url++;
}
 
/* *LWS */
while (url < end && isspace(*url)) {
url++;
}
 
/* ';' */
if (url < end && *url == ';')
url++;
 
/* *LWS */
while (url < end && isspace(*url)) {
url++;
}
 
if (url == end) {
/* Just delay specified, so refresh current page */
dom_string_unref(content);
 
c->base.refresh = nsurl_ref(
content_get_url(&c->base));
 
content_broadcast(&c->base, CONTENT_MSG_REFRESH, msg_data);
 
return NSERROR_OK;
}
 
/* "url" */
if (url <= end - 3) {
if (strncasecmp(url, "url", 3) == 0) {
url += 3;
} else {
/* Unexpected input, ignore this header */
dom_string_unref(content);
return NSERROR_OK;
}
} else {
/* Insufficient input, ignore this header */
dom_string_unref(content);
return NSERROR_OK;
}
 
/* *LWS */
while (url < end && isspace(*url)) {
url++;
}
 
/* '=' */
if (url < end) {
if (*url == '=') {
url++;
} else {
/* Unexpected input, ignore this header */
dom_string_unref(content);
return NSERROR_OK;
}
} else {
/* Insufficient input, ignore this header */
dom_string_unref(content);
return NSERROR_OK;
}
 
/* *LWS */
while (url < end && isspace(*url)) {
url++;
}
 
/* '"' or "'" */
if (url < end && (*url == '"' || *url == '\'')) {
quote = *url;
url++;
}
 
/* Start of URL */
refresh = url;
 
if (quote != 0) {
/* url-sq | url-dq */
while (url < end && *url != quote)
url++;
} else {
/* url-nq */
while (url < end && !isspace(*url))
url++;
}
 
/* '"' or "'" or *LWS (we don't care) */
if (url > refresh) {
/* There's a URL */
new_url = strndup(refresh, url - refresh);
if (new_url == NULL) {
dom_string_unref(content);
return NSERROR_NOMEM;
}
 
error = nsurl_join(c->base_url, new_url, &nsurl);
if (error == NSERROR_OK) {
/* broadcast valid refresh url */
 
c->base.refresh = nsurl;
 
content_broadcast(&c->base, CONTENT_MSG_REFRESH, msg_data);
}
 
free(new_url);
 
}
 
dom_string_unref(content);
 
return error;
}
 
/**
* Search for meta refresh
*
* http://wp.netscape.com/assist/net_sites/pushpull.html
*
* \param c content structure
* \param head xml node of head element
* \return true on success, false otherwise (error reported)
*/
 
static nserror html_meta_refresh(html_content *c, dom_node *head)
{
dom_node *n, *next;
dom_exception exc;
nserror ns_error = NSERROR_OK;
 
if (head == NULL) {
return ns_error;
}
 
exc = dom_node_get_first_child(head, &n);
if (exc != DOM_NO_ERR) {
return NSERROR_DOM;
}
 
while (n != NULL) {
dom_node_type type;
 
exc = dom_node_get_node_type(n, &type);
if (exc != DOM_NO_ERR) {
dom_node_unref(n);
return NSERROR_DOM;
}
 
if (type == DOM_ELEMENT_NODE) {
dom_string *name;
 
exc = dom_node_get_node_name(n, &name);
if (exc != DOM_NO_ERR) {
dom_node_unref(n);
return NSERROR_DOM;
}
 
/* Recurse into noscript elements */
if (dom_string_caseless_lwc_isequal(name, corestring_lwc_noscript)) {
ns_error = html_meta_refresh(c, n);
if (ns_error != NSERROR_OK) {
/* Some error occurred */
dom_string_unref(name);
dom_node_unref(n);
return ns_error;
} else if (c->base.refresh != NULL) {
/* Meta refresh found - stop */
dom_string_unref(name);
dom_node_unref(n);
return NSERROR_OK;
}
} else if (dom_string_caseless_lwc_isequal(name, corestring_lwc_meta)) {
ns_error = html_meta_refresh_process_element(c, n);
if (ns_error != NSERROR_OK) {
/* Some error occurred */
dom_string_unref(name);
dom_node_unref(n);
return ns_error;
} else if (c->base.refresh != NULL) {
/* Meta refresh found - stop */
dom_string_unref(name);
dom_node_unref(n);
return NSERROR_OK;
}
}
dom_string_unref(name);
}
 
exc = dom_node_get_next_sibling(n, &next);
if (exc != DOM_NO_ERR) {
dom_node_unref(n);
return NSERROR_DOM;
}
 
dom_node_unref(n);
n = next;
}
 
return ns_error;
}
 
/**
* Update a box whose content has completed rendering.
*/
 
static void
html_object_done(struct box *box,
hlcache_handle *object,
bool background)
{
struct box *b;
 
if (background) {
box->background = object;
return;
}
 
box->object = object;
 
if (!(box->flags & REPLACE_DIM)) {
/* invalidate parent min, max widths */
for (b = box; b; b = b->parent)
b->max_width = UNKNOWN_MAX_WIDTH;
 
/* delete any clones of this box */
while (box->next && (box->next->flags & CLONE)) {
/* box_free_box(box->next); */
box->next = box->next->next;
}
}
}
 
/**
* Handle object fetching or loading failure.
*
* \param box box containing object which failed to load
* \param content document of type CONTENT_HTML
* \param background the object was the background image for the box
*/
 
static void
html_object_failed(struct box *box, html_content *content, bool background)
{
/* Nothing to do */
return;
}
 
/**
* Callback for hlcache_handle_retrieve() for objects.
*/
 
static nserror
html_object_callback(hlcache_handle *object,
const hlcache_event *event,
void *pw)
{
struct content_html_object *o = pw;
html_content *c = (html_content *) o->parent;
int x, y;
struct box *box;
 
assert(c->base.status != CONTENT_STATUS_ERROR);
 
box = o->box;
 
switch (event->type) {
case CONTENT_MSG_LOADING:
if (c->base.status != CONTENT_STATUS_LOADING && c->bw != NULL)
content_open(object,
c->bw, &c->base,
box->object_params);
break;
 
case CONTENT_MSG_READY:
if (content_can_reformat(object)) {
/* TODO: avoid knowledge of box internals here */
content_reformat(object, false,
box->max_width != UNKNOWN_MAX_WIDTH ?
box->width : 0,
box->max_width != UNKNOWN_MAX_WIDTH ?
box->height : 0);
 
/* Adjust parent content for new object size */
html_object_done(box, object, o->background);
if (c->base.status == CONTENT_STATUS_READY ||
c->base.status == CONTENT_STATUS_DONE)
content__reformat(&c->base, false,
c->base.available_width,
c->base.height);
}
break;
 
case CONTENT_MSG_DONE:
c->base.active--;
LOG(("%d fetches active", c->base.active));
 
html_object_done(box, object, o->background);
 
if (c->base.status != CONTENT_STATUS_LOADING &&
box->flags & REPLACE_DIM) {
union content_msg_data data;
 
if (!box_visible(box))
break;
 
box_coords(box, &x, &y);
 
data.redraw.x = x + box->padding[LEFT];
data.redraw.y = y + box->padding[TOP];
data.redraw.width = box->width;
data.redraw.height = box->height;
data.redraw.full_redraw = true;
 
content_broadcast(&c->base, CONTENT_MSG_REDRAW, data);
}
break;
 
case CONTENT_MSG_ERROR:
hlcache_handle_release(object);
 
o->content = NULL;
 
c->base.active--;
LOG(("%d fetches active", c->base.active));
 
content_add_error(&c->base, "?", 0);
html_object_failed(box, c, o->background);
break;
 
case CONTENT_MSG_STATUS:
if (event->data.explicit_status_text == NULL) {
/* Object content's status text updated */
union content_msg_data data;
data.explicit_status_text =
content_get_status_message(object);
html_set_status(c, data.explicit_status_text);
content_broadcast(&c->base, CONTENT_MSG_STATUS, data);
} else {
/* Object content wants to set explicit message */
content_broadcast(&c->base, CONTENT_MSG_STATUS,
event->data);
}
break;
 
case CONTENT_MSG_REFORMAT:
break;
 
case CONTENT_MSG_REDRAW:
if (c->base.status != CONTENT_STATUS_LOADING) {
union content_msg_data data = event->data;
 
if (!box_visible(box))
break;
 
box_coords(box, &x, &y);
 
if (hlcache_handle_get_content(object) ==
event->data.redraw.object) {
data.redraw.x = data.redraw.x *
box->width / content_get_width(object);
data.redraw.y = data.redraw.y *
box->height /
content_get_height(object);
data.redraw.width = data.redraw.width *
box->width / content_get_width(object);
data.redraw.height = data.redraw.height *
box->height /
content_get_height(object);
data.redraw.object_width = box->width;
data.redraw.object_height = box->height;
}
 
data.redraw.x += x + box->padding[LEFT];
data.redraw.y += y + box->padding[TOP];
data.redraw.object_x += x + box->padding[LEFT];
data.redraw.object_y += y + box->padding[TOP];
 
content_broadcast(&c->base, CONTENT_MSG_REDRAW, data);
}
break;
 
case CONTENT_MSG_REFRESH:
if (content_get_type(object) == CONTENT_HTML) {
/* only for HTML objects */
schedule(event->data.delay * 100,
html_object_refresh, o);
}
 
break;
 
case CONTENT_MSG_LINK:
/* Don't care about favicons that aren't on top level content */
break;
 
case CONTENT_MSG_GETCTX:
*(event->data.jscontext) = NULL;
break;
 
case CONTENT_MSG_SCROLL:
if (box->scroll_x != NULL)
scrollbar_set(box->scroll_x, event->data.scroll.x0,
false);
if (box->scroll_y != NULL)
scrollbar_set(box->scroll_y, event->data.scroll.y0,
false);
break;
 
case CONTENT_MSG_DRAGSAVE:
{
union content_msg_data msg_data;
if (event->data.dragsave.content == NULL)
msg_data.dragsave.content = object;
else
msg_data.dragsave.content =
event->data.dragsave.content;
 
content_broadcast(&c->base, CONTENT_MSG_DRAGSAVE, msg_data);
}
break;
 
case CONTENT_MSG_SAVELINK:
case CONTENT_MSG_POINTER:
/* These messages are for browser window layer.
* we're not interested, so pass them on. */
content_broadcast(&c->base, event->type, event->data);
break;
 
default:
assert(0);
}
 
if (c->base.status == CONTENT_STATUS_READY && c->base.active == 0 &&
(event->type == CONTENT_MSG_LOADING ||
event->type == CONTENT_MSG_DONE ||
event->type == CONTENT_MSG_ERROR)) {
/* all objects have arrived */
content__reformat(&c->base, false, c->base.available_width,
c->base.height);
html_set_status(c, "");
content_set_done(&c->base);
}
 
/* If 1) the configuration option to reflow pages while objects are
* fetched is set
* 2) an object is newly fetched & converted,
* 3) the box's dimensions need to change due to being replaced
* 4) the object's parent HTML is ready for reformat,
* 5) the time since the previous reformat is more than the
* configured minimum time between reformats
* then reformat the page to display newly fetched objects */
else if (nsoption_bool(incremental_reflow) &&
event->type == CONTENT_MSG_DONE &&
!(box->flags & REPLACE_DIM) &&
(c->base.status == CONTENT_STATUS_READY ||
c->base.status == CONTENT_STATUS_DONE) &&
(wallclock() > c->base.reformat_time)) {
content__reformat(&c->base, false, c->base.available_width,
c->base.height);
}
 
return NSERROR_OK;
}
 
/**
* Start a fetch for an object required by a page, replacing an existing object.
*
* \param object Object to replace
* \param url URL of object to fetch (copied)
* \return true on success, false on memory exhaustion
*/
 
static bool html_replace_object(struct content_html_object *object, nsurl *url)
{
html_content *c;
hlcache_child_context child;
html_content *page;
nserror error;
 
assert(object != NULL);
 
c = (html_content *) object->parent;
 
child.charset = c->encoding;
child.quirks = c->base.quirks;
 
if (object->content != NULL) {
/* remove existing object */
if (content_get_status(object->content) != CONTENT_STATUS_DONE) {
c->base.active--;
LOG(("%d fetches active", c->base.active));
}
 
hlcache_handle_release(object->content);
object->content = NULL;
 
object->box->object = NULL;
}
 
/* initialise fetch */
error = hlcache_handle_retrieve(url, HLCACHE_RETRIEVE_SNIFF_TYPE,
content_get_url(&c->base), NULL,
html_object_callback, object, &child,
object->permitted_types,
&object->content);
 
if (error != NSERROR_OK)
return false;
 
for (page = c; page != NULL; page = page->page) {
page->base.active++;
LOG(("%d fetches active", c->base.active));
 
page->base.status = CONTENT_STATUS_READY;
}
 
return true;
}
 
/**
* schedule() callback for object refresh
*/
 
static void html_object_refresh(void *p)
{
struct content_html_object *object = p;
nsurl *refresh_url;
 
assert(content_get_type(object->content) == CONTENT_HTML);
 
refresh_url = content_get_refresh_url(object->content);
 
/* Ignore if refresh URL has gone
* (may happen if fetch errored) */
if (refresh_url == NULL)
return;
 
content_invalidate_reuse_data(object->content);
 
if (!html_replace_object(object, refresh_url)) {
/** \todo handle memory exhaustion */
}
}
 
 
 
 
 
/**
* Callback for fetchcache() for linked stylesheets.
*/
 
static nserror
html_convert_css_callback(hlcache_handle *css,
const hlcache_event *event,
void *pw)
{
html_content *parent = pw;
unsigned int i;
struct html_stylesheet *s;
 
/* Find sheet */
for (i = 0, s = parent->stylesheets;
i != parent->stylesheet_count; i++, s++) {
if (s->type == HTML_STYLESHEET_EXTERNAL &&
s->data.external == css)
break;
}
 
assert(i != parent->stylesheet_count);
 
switch (event->type) {
case CONTENT_MSG_LOADING:
break;
 
case CONTENT_MSG_READY:
break;
 
case CONTENT_MSG_DONE:
LOG(("done stylesheet slot %d '%s'", i,
nsurl_access(hlcache_handle_get_url(css))));
parent->base.active--;
LOG(("%d fetches active", parent->base.active));
break;
 
case CONTENT_MSG_ERROR:
LOG(("stylesheet %s failed: %s",
nsurl_access(hlcache_handle_get_url(css)),
event->data.error));
hlcache_handle_release(css);
s->data.external = NULL;
parent->base.active--;
LOG(("%d fetches active", parent->base.active));
content_add_error(&parent->base, "?", 0);
break;
 
case CONTENT_MSG_STATUS:
if (event->data.explicit_status_text == NULL) {
/* Object content's status text updated */
html_set_status(parent,
content_get_status_message(css));
content_broadcast(&parent->base, CONTENT_MSG_STATUS,
event->data);
} else {
/* Object content wants to set explicit message */
content_broadcast(&parent->base, CONTENT_MSG_STATUS,
event->data);
}
break;
 
default:
assert(0);
}
 
if (parent->base.active == 0)
html_finish_conversion(parent);
 
return NSERROR_OK;
}
 
/**
* Handle notification of inline style completion
*
* \param css Inline style object
* \param pw Private data
*/
static void html_inline_style_done(struct content_css_data *css, void *pw)
{
html_content *html = pw;
 
if (--html->base.active == 0)
html_finish_conversion(html);
}
 
/**
* Process an inline stylesheet in the document.
*
* \param c content structure
* \param index Index of stylesheet in stylesheet_content array,
* updated if successful
* \param style xml node of style element
* \return true on success, false if an error occurred
*/
 
static bool
html_process_style_element(html_content *c,
unsigned int *index,
dom_node *style)
{
dom_node *child, *next;
dom_string *val;
dom_exception exc;
struct html_stylesheet *stylesheets;
struct content_css_data *sheet;
nserror error;
 
/* type='text/css', or not present (invalid but common) */
exc = dom_element_get_attribute(style, corestring_dom_type, &val);
if (exc == DOM_NO_ERR && val != NULL) {
if (!dom_string_caseless_lwc_isequal(val,
corestring_lwc_text_css)) {
dom_string_unref(val);
return true;
}
dom_string_unref(val);
}
 
/* media contains 'screen' or 'all' or not present */
exc = dom_element_get_attribute(style, corestring_dom_media, &val);
if (exc == DOM_NO_ERR && val != NULL) {
if (strcasestr(dom_string_data(val), "screen") == NULL &&
strcasestr(dom_string_data(val),
"all") == NULL) {
dom_string_unref(val);
return true;
}
dom_string_unref(val);
}
 
/* Extend array */
stylesheets = realloc(c->stylesheets,
sizeof(struct html_stylesheet) * (*index + 1));
if (stylesheets == NULL)
goto no_memory;
 
c->stylesheets = stylesheets;
c->stylesheet_count++;
 
c->stylesheets[(*index)].type = HTML_STYLESHEET_INTERNAL;
c->stylesheets[(*index)].data.internal = NULL;
 
/* create stylesheet */
sheet = calloc(1, sizeof(struct content_css_data));
if (sheet == NULL) {
c->stylesheet_count--;
goto no_memory;
}
 
error = nscss_create_css_data(sheet,
nsurl_access(c->base_url), NULL, c->quirks,
html_inline_style_done, c);
if (error != NSERROR_OK) {
free(sheet);
c->stylesheet_count--;
content_broadcast_errorcode(&c->base, error);
return false;
}
 
/* can't just use xmlNodeGetContent(style), because that won't
* give the content of comments which may be used to 'hide'
* the content */
exc = dom_node_get_first_child(style, &child);
if (exc != DOM_NO_ERR) {
nscss_destroy_css_data(sheet);
free(sheet);
c->stylesheet_count--;
goto no_memory;
}
 
while (child != NULL) {
dom_string *data;
 
exc = dom_node_get_text_content(child, &data);
if (exc != DOM_NO_ERR) {
dom_node_unref(child);
nscss_destroy_css_data(sheet);
free(sheet);
c->stylesheet_count--;
goto no_memory;
}
 
if (nscss_process_css_data(sheet, dom_string_data(data),
dom_string_byte_length(data)) == false) {
dom_string_unref(data);
dom_node_unref(child);
nscss_destroy_css_data(sheet);
free(sheet);
c->stylesheet_count--;
goto no_memory;
}
 
dom_string_unref(data);
 
exc = dom_node_get_next_sibling(child, &next);
if (exc != DOM_NO_ERR) {
dom_node_unref(child);
nscss_destroy_css_data(sheet);
free(sheet);
c->stylesheet_count--;
goto no_memory;
}
 
dom_node_unref(child);
child = next;
}
 
c->base.active++;
LOG(("%d fetches active", c->base.active));
 
/* Convert the content -- manually, as we want the result */
if (nscss_convert_css_data(sheet) != CSS_OK) {
/* conversion failed */
c->base.active--;
LOG(("%d fetches active", c->base.active));
nscss_destroy_css_data(sheet);
free(sheet);
sheet = NULL;
}
 
/* Update index */
c->stylesheets[(*index)].data.internal = sheet;
(*index)++;
 
return true;
 
no_memory:
content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
return false;
}
 
 
 
struct find_stylesheet_ctx {
unsigned int count;
html_content *c;
};
 
/** callback to process stylesheet elements
*/
static bool
html_process_stylesheet(dom_node *node, dom_string *name, void *vctx)
{
struct find_stylesheet_ctx *ctx = (struct find_stylesheet_ctx *)vctx;
dom_string *rel, *type_attr, *media, *href;
struct html_stylesheet *stylesheets;
nsurl *joined;
dom_exception exc;
nserror ns_error;
hlcache_child_context child;
 
/* deal with style nodes */
if (dom_string_caseless_lwc_isequal(name, corestring_lwc_style)) {
if (!html_process_style_element(ctx->c, &ctx->count, node))
return false;
return true;
}
 
/* if it is not a link node skip it */
if (!dom_string_caseless_lwc_isequal(name, corestring_lwc_link)) {
return true;
}
 
/* rel=<space separated list, including 'stylesheet'> */
exc = dom_element_get_attribute(node,
corestring_dom_rel, &rel);
if (exc != DOM_NO_ERR || rel == NULL)
return true;
 
if (strcasestr(dom_string_data(rel), "stylesheet") == 0) {
dom_string_unref(rel);
return true;
} else if (strcasestr(dom_string_data(rel), "alternate") != 0) {
/* Ignore alternate stylesheets */
dom_string_unref(rel);
return true;
}
dom_string_unref(rel);
 
/* type='text/css' or not present */
exc = dom_element_get_attribute(node, corestring_dom_type, &type_attr);
if (exc == DOM_NO_ERR && type_attr != NULL) {
if (!dom_string_caseless_lwc_isequal(type_attr,
corestring_lwc_text_css)) {
dom_string_unref(type_attr);
return true;
}
dom_string_unref(type_attr);
}
 
/* media contains 'screen' or 'all' or not present */
exc = dom_element_get_attribute(node, corestring_dom_media, &media);
if (exc == DOM_NO_ERR && media != NULL) {
if (strcasestr(dom_string_data(media), "screen") == NULL &&
strcasestr(dom_string_data(media), "all") == NULL) {
dom_string_unref(media);
return true;
}
dom_string_unref(media);
}
 
/* href='...' */
exc = dom_element_get_attribute(node, corestring_dom_href, &href);
if (exc != DOM_NO_ERR || href == NULL)
return true;
 
/* TODO: only the first preferred stylesheets (ie.
* those with a title attribute) should be loaded
* (see HTML4 14.3) */
 
ns_error = nsurl_join(ctx->c->base_url, dom_string_data(href), &joined);
if (ns_error != NSERROR_OK) {
dom_string_unref(href);
goto no_memory;
}
dom_string_unref(href);
 
LOG(("linked stylesheet %i '%s'", ctx->count, nsurl_access(joined)));
 
/* start fetch */
stylesheets = realloc(ctx->c->stylesheets,
sizeof(struct html_stylesheet) * (ctx->count + 1));
if (stylesheets == NULL) {
nsurl_unref(joined);
ns_error = NSERROR_NOMEM;
goto no_memory;
}
 
ctx->c->stylesheets = stylesheets;
ctx->c->stylesheet_count++;
ctx->c->stylesheets[ctx->count].type = HTML_STYLESHEET_EXTERNAL;
 
child.charset = ctx->c->encoding;
child.quirks = ctx->c->base.quirks;
 
ns_error = hlcache_handle_retrieve(joined,
0,
content_get_url(&ctx->c->base),
NULL,
html_convert_css_callback,
ctx->c,
&child,
CONTENT_CSS,
&ctx->c->stylesheets[ctx->count].data.external);
 
nsurl_unref(joined);
 
if (ns_error != NSERROR_OK)
goto no_memory;
 
ctx->c->base.active++;
LOG(("%d fetches active", ctx->c->base.active));
 
ctx->count++;
 
return true;
 
no_memory:
content_broadcast_errorcode(&ctx->c->base, ns_error);
return false;
}
 
 
/**
* Process inline stylesheets and fetch linked stylesheets.
*
* Uses STYLE and LINK elements inside and outside HEAD
*
* \param c content structure
* \param html dom node of html element
* \return true on success, false if an error occurred
*/
 
static bool html_find_stylesheets(html_content *c, dom_node *html)
{
nserror ns_error;
bool result;
struct find_stylesheet_ctx ctx;
hlcache_child_context child;
 
/* setup context */
ctx.c = c;
ctx.count = STYLESHEET_START;
 
/* stylesheet 0 is the base style sheet,
* stylesheet 1 is the quirks mode style sheet,
* stylesheet 2 is the adblocking stylesheet,
* stylesheet 3 is the user stylesheet */
c->stylesheets = calloc(STYLESHEET_START, sizeof(struct html_stylesheet));
if (c->stylesheets == NULL) {
ns_error = NSERROR_NOMEM;
goto html_find_stylesheets_no_memory;
}
 
c->stylesheets[STYLESHEET_BASE].type = HTML_STYLESHEET_EXTERNAL;
c->stylesheets[STYLESHEET_BASE].data.external = NULL;
c->stylesheets[STYLESHEET_QUIRKS].type = HTML_STYLESHEET_EXTERNAL;
c->stylesheets[STYLESHEET_QUIRKS].data.external = NULL;
c->stylesheets[STYLESHEET_ADBLOCK].type = HTML_STYLESHEET_EXTERNAL;
c->stylesheets[STYLESHEET_ADBLOCK].data.external = NULL;
c->stylesheets[STYLESHEET_USER].type = HTML_STYLESHEET_EXTERNAL;
c->stylesheets[STYLESHEET_USER].data.external = NULL;
c->stylesheet_count = STYLESHEET_START;
 
child.charset = c->encoding;
child.quirks = c->base.quirks;
 
ns_error = hlcache_handle_retrieve(html_default_stylesheet_url, 0,
content_get_url(&c->base), NULL,
html_convert_css_callback, c, &child, CONTENT_CSS,
&c->stylesheets[STYLESHEET_BASE].data.external);
if (ns_error != NSERROR_OK)
goto html_find_stylesheets_no_memory;
 
c->base.active++;
LOG(("%d fetches active", c->base.active));
 
if (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL) {
ns_error = hlcache_handle_retrieve(html_quirks_stylesheet_url,
0, content_get_url(&c->base), NULL,
html_convert_css_callback, c, &child,
CONTENT_CSS,
&c->stylesheets[STYLESHEET_QUIRKS].data.external);
if (ns_error != NSERROR_OK)
goto html_find_stylesheets_no_memory;
 
c->base.active++;
LOG(("%d fetches active", c->base.active));
 
}
 
if (nsoption_bool(block_ads)) {
ns_error = hlcache_handle_retrieve(html_adblock_stylesheet_url,
0, content_get_url(&c->base), NULL,
html_convert_css_callback, c, &child, CONTENT_CSS,
&c->stylesheets[STYLESHEET_ADBLOCK].
data.external);
if (ns_error != NSERROR_OK)
goto html_find_stylesheets_no_memory;
 
c->base.active++;
LOG(("%d fetches active", c->base.active));
 
}
 
ns_error = hlcache_handle_retrieve(html_user_stylesheet_url, 0,
content_get_url(&c->base), NULL,
html_convert_css_callback, c, &child, CONTENT_CSS,
&c->stylesheets[STYLESHEET_USER].data.external);
if (ns_error != NSERROR_OK)
goto html_find_stylesheets_no_memory;
 
c->base.active++;
LOG(("%d fetches active", c->base.active));
 
result = libdom_treewalk(html, html_process_stylesheet, &ctx);
 
assert(c->stylesheet_count == ctx.count);
 
return result;
 
html_find_stylesheets_no_memory:
content_broadcast_errorcode(&c->base, ns_error);
return false;
}
 
/**
* Convert a CONTENT_HTML for display.
*
* The following steps are carried out in order:
*
* - parsing to an XML tree is completed
* - stylesheets are fetched
* - the XML tree is converted to a box tree and object fetches are started
*
* On exit, the content status will be either CONTENT_STATUS_DONE if the
* document is completely loaded or CONTENT_STATUS_READY if objects are still
* being fetched.
*/
 
static bool html_convert(struct content *c)
{
html_content *htmlc = (html_content *) c;
 
htmlc->base.active--; /* the html fetch is no longer active */
LOG(("%d fetches active", htmlc->base.active));
 
/* if there are no active fetches in progress no scripts are
* being fetched or they completed already.
*/
if (htmlc->base.active == 0) {
return html_begin_conversion(htmlc);
}
return true;
}
 
bool
html_begin_conversion(html_content *htmlc)
{
dom_node *html, *head;
nserror ns_error;
struct form *f;
dom_exception exc; /* returned by libdom functions */
dom_string *node_name = NULL;
dom_hubbub_error error;
 
/* complete parsing */
error = dom_hubbub_parser_completed(htmlc->parser);
if (error != DOM_HUBBUB_OK) {
LOG(("Parsing failed"));
 
content_broadcast_errorcode(&htmlc->base,
libdom_hubbub_error_to_nserror(error));
 
return false;
}
 
/* Give up processing if we've been aborted */
if (htmlc->aborted) {
content_broadcast_errorcode(&htmlc->base, NSERROR_STOPPED);
return false;
}
 
 
/* complete script execution */
html_scripts_exec(htmlc);
 
/* fire a simple event that bubbles named DOMContentLoaded at
* the Document.
*/
 
/* quirks mode */
exc = dom_document_get_quirks_mode(htmlc->document, &htmlc->quirks);
if (exc != DOM_NO_ERR) {
LOG(("error retrieving quirks"));
/** @todo should this be fatal to the conversion? */
}
LOG(("quirks set to %d", htmlc->quirks));
 
/* get encoding */
if (htmlc->encoding == NULL) {
const char *encoding;
 
encoding = dom_hubbub_parser_get_encoding(htmlc->parser,
&htmlc->encoding_source);
if (encoding == NULL) {
content_broadcast_errorcode(&htmlc->base,
NSERROR_NOMEM);
return false;
}
 
htmlc->encoding = strdup(encoding);
if (htmlc->encoding == NULL) {
content_broadcast_errorcode(&htmlc->base,
NSERROR_NOMEM);
return false;
}
}
 
/* locate root element and ensure it is html */
exc = dom_document_get_document_element(htmlc->document, (void *) &html);
if ((exc != DOM_NO_ERR) || (html == NULL)) {
LOG(("error retrieving html element from dom"));
content_broadcast_errorcode(&htmlc->base, NSERROR_DOM);
return false;
}
 
exc = dom_node_get_node_name(html, &node_name);
if ((exc != DOM_NO_ERR) ||
(node_name == NULL) ||
(!dom_string_caseless_lwc_isequal(node_name,
corestring_lwc_html))) {
LOG(("root element not html"));
content_broadcast_errorcode(&htmlc->base, NSERROR_DOM);
dom_node_unref(html);
return false;
}
dom_string_unref(node_name);
 
head = libdom_find_first_element(html, corestring_lwc_head);
if (head != NULL) {
ns_error = html_head(htmlc, head);
if (ns_error != NSERROR_OK) {
content_broadcast_errorcode(&htmlc->base, ns_error);
 
dom_node_unref(html);
dom_node_unref(head);
return false;
}
 
/* handle meta refresh */
ns_error = html_meta_refresh(htmlc, head);
if (ns_error != NSERROR_OK) {
content_broadcast_errorcode(&htmlc->base, ns_error);
 
dom_node_unref(html);
dom_node_unref(head);
return false;
}
}
 
/* Retrieve forms from parser */
htmlc->forms = html_forms_get_forms(htmlc->encoding,
(dom_html_document *) htmlc->document);
for (f = htmlc->forms; f != NULL; f = f->prev) {
nsurl *action;
 
/* Make all actions absolute */
if (f->action == NULL || f->action[0] == '\0') {
/* HTML5 4.10.22.3 step 9 */
nsurl *doc_addr = content_get_url(&htmlc->base);
ns_error = nsurl_join(htmlc->base_url,
nsurl_access(doc_addr),
&action);
} else {
ns_error = nsurl_join(htmlc->base_url,
f->action,
&action);
}
 
if (ns_error != NSERROR_OK) {
content_broadcast_errorcode(&htmlc->base, ns_error);
 
dom_node_unref(html);
dom_node_unref(head);
return false;
}
 
free(f->action);
f->action = strdup(nsurl_access(action));
nsurl_unref(action);
if (f->action == NULL) {
content_broadcast_errorcode(&htmlc->base,
NSERROR_NOMEM);
 
dom_node_unref(html);
dom_node_unref(head);
return false;
}
 
/* Ensure each form has a document encoding */
if (f->document_charset == NULL) {
f->document_charset = strdup(htmlc->encoding);
if (f->document_charset == NULL) {
content_broadcast_errorcode(&htmlc->base,
NSERROR_NOMEM);
dom_node_unref(html);
dom_node_unref(head);
return false;
}
}
}
 
dom_node_unref(head);
 
/* get stylesheets */
if (html_find_stylesheets(htmlc, html) == false) {
dom_node_unref(html);
return false;
}
 
dom_node_unref(html);
 
if (htmlc->base.active == 0) {
html_finish_conversion(htmlc);
}
 
return true;
}
 
 
 
 
/**
* Start a fetch for an object required by a page.
*
* \param c content of type CONTENT_HTML
* \param url URL of object to fetch (copied)
* \param box box that will contain the object
* \param permitted_types bitmap of acceptable types
* \param available_width estimate of width of object
* \param available_height estimate of height of object
* \param background this is a background image
* \return true on success, false on memory exhaustion
*/
 
bool html_fetch_object(html_content *c, nsurl *url, struct box *box,
content_type permitted_types,
int available_width, int available_height,
bool background)
{
struct content_html_object *object;
hlcache_child_context child;
nserror error;
 
/* If we've already been aborted, don't bother attempting the fetch */
if (c->aborted)
return true;
 
child.charset = c->encoding;
child.quirks = c->base.quirks;
 
object = calloc(1, sizeof(struct content_html_object));
if (object == NULL) {
return false;
}
 
object->parent = (struct content *) c;
object->next = NULL;
object->content = NULL;
object->box = box;
object->permitted_types = permitted_types;
object->background = background;
 
error = hlcache_handle_retrieve(url,
HLCACHE_RETRIEVE_SNIFF_TYPE,
content_get_url(&c->base), NULL,
html_object_callback, object, &child,
object->permitted_types, &object->content);
if (error != NSERROR_OK) {
free(object);
return error != NSERROR_NOMEM;
}
 
/* add to content object list */
object->next = c->object_list;
c->object_list = object;
 
c->num_objects++;
c->base.active++;
LOG(("%d fetches active", c->base.active));
 
return true;
}
 
 
 
 
 
/**
* Stop loading a CONTENT_HTML.
*/
 
static void html_stop(struct content *c)
{
html_content *htmlc = (html_content *) c;
struct content_html_object *object;
 
switch (c->status) {
case CONTENT_STATUS_LOADING:
/* Still loading; simply flag that we've been aborted
* html_convert/html_finish_conversion will do the rest */
htmlc->aborted = true;
break;
case CONTENT_STATUS_READY:
for (object = htmlc->object_list; object != NULL;
object = object->next) {
if (object->content == NULL)
continue;
 
if (content_get_status(object->content) ==
CONTENT_STATUS_DONE)
; /* already loaded: do nothing */
else if (content_get_status(object->content) ==
CONTENT_STATUS_READY)
hlcache_handle_abort(object->content);
/* Active count will be updated when
* html_object_callback receives
* CONTENT_MSG_DONE from this object */
else {
hlcache_handle_abort(object->content);
hlcache_handle_release(object->content);
object->content = NULL;
 
c->active--;
LOG(("%d fetches active", c->active));
 
}
}
 
/* If there are no further active fetches and we're still
* in the READY state, transition to the DONE state. */
if (c->status == CONTENT_STATUS_READY && c->active == 0) {
html_set_status(htmlc, "");
content_set_done(c);
}
 
break;
case CONTENT_STATUS_DONE:
/* Nothing to do */
break;
default:
LOG(("Unexpected status %d", c->status));
assert(0);
}
}
 
 
/**
* Reformat a CONTENT_HTML to a new width.
*/
 
static void html_reformat(struct content *c, int width, int height)
{
html_content *htmlc = (html_content *) c;
struct box *layout;
unsigned int time_before, time_taken;
 
time_before = wallclock();
 
layout_document(htmlc, width, height);
layout = htmlc->layout;
 
/* width and height are at least margin box of document */
c->width = layout->x + layout->padding[LEFT] + layout->width +
layout->padding[RIGHT] + layout->border[RIGHT].width +
layout->margin[RIGHT];
c->height = layout->y + layout->padding[TOP] + layout->height +
layout->padding[BOTTOM] + layout->border[BOTTOM].width +
layout->margin[BOTTOM];
 
/* if boxes overflow right or bottom edge, expand to contain it */
if (c->width < layout->x + layout->descendant_x1)
c->width = layout->x + layout->descendant_x1;
if (c->height < layout->y + layout->descendant_y1)
c->height = layout->y + layout->descendant_y1;
 
selection_reinit(&htmlc->sel, htmlc->layout);
 
time_taken = wallclock() - time_before;
c->reformat_time = wallclock() +
((time_taken * 3 < nsoption_int(min_reflow_period) ?
nsoption_int(min_reflow_period) : time_taken * 3));
}
 
 
/**
* Redraw a box.
*
* \param h content containing the box, of type CONTENT_HTML
* \param box box to redraw
*/
 
void html_redraw_a_box(hlcache_handle *h, struct box *box)
{
int x, y;
 
box_coords(box, &x, &y);
 
content_request_redraw(h, x, y,
box->padding[LEFT] + box->width + box->padding[RIGHT],
box->padding[TOP] + box->height + box->padding[BOTTOM]);
}
 
 
/**
* Redraw a box.
*
* \param h content containing the box, of type CONTENT_HTML
* \param box box to redraw
*/
 
void html__redraw_a_box(struct html_content *html, struct box *box)
{
int x, y;
 
box_coords(box, &x, &y);
 
content__request_redraw((struct content *)html, x, y,
box->padding[LEFT] + box->width + box->padding[RIGHT],
box->padding[TOP] + box->height + box->padding[BOTTOM]);
}
 
static void html_destroy_frameset(struct content_html_frames *frameset)
{
int i;
 
if (frameset->name) {
talloc_free(frameset->name);
frameset->name = NULL;
}
if (frameset->url) {
talloc_free(frameset->url);
frameset->url = NULL;
}
if (frameset->children) {
for (i = 0; i < (frameset->rows * frameset->cols); i++) {
if (frameset->children[i].name) {
talloc_free(frameset->children[i].name);
frameset->children[i].name = NULL;
}
if (frameset->children[i].url) {
nsurl_unref(frameset->children[i].url);
frameset->children[i].url = NULL;
}
if (frameset->children[i].children)
html_destroy_frameset(&frameset->children[i]);
}
talloc_free(frameset->children);
frameset->children = NULL;
}
}
 
static void html_destroy_iframe(struct content_html_iframe *iframe)
{
struct content_html_iframe *next;
next = iframe;
while ((iframe = next) != NULL) {
next = iframe->next;
if (iframe->name)
talloc_free(iframe->name);
if (iframe->url) {
nsurl_unref(iframe->url);
iframe->url = NULL;
}
talloc_free(iframe);
}
}
 
 
static void html_free_layout(html_content *htmlc)
{
if (htmlc->bctx != NULL) {
/* freeing talloc context should let the entire box
* set be destroyed
*/
talloc_free(htmlc->bctx);
}
}
 
/**
* Destroy a CONTENT_HTML and free all resources it owns.
*/
 
static void html_destroy(struct content *c)
{
html_content *html = (html_content *) c;
unsigned int i;
struct form *f, *g;
 
LOG(("content %p", c));
 
/* Destroy forms */
for (f = html->forms; f != NULL; f = g) {
g = f->prev;
 
form_free(f);
}
 
imagemap_destroy(html);
 
if (c->refresh)
nsurl_unref(c->refresh);
 
if (html->base_url)
nsurl_unref(html->base_url);
 
if (html->parser != NULL) {
dom_hubbub_parser_destroy(html->parser);
html->parser = NULL;
}
 
if (html->document != NULL) {
dom_node_unref(html->document);
}
 
/* Free base target */
if (html->base_target != NULL) {
free(html->base_target);
html->base_target = NULL;
}
 
/* Free frameset */
if (html->frameset != NULL) {
html_destroy_frameset(html->frameset);
talloc_free(html->frameset);
html->frameset = NULL;
}
 
/* Free iframes */
if (html->iframe != NULL) {
html_destroy_iframe(html->iframe);
html->iframe = NULL;
}
 
/* Destroy selection context */
if (html->select_ctx != NULL) {
css_select_ctx_destroy(html->select_ctx);
html->select_ctx = NULL;
}
 
if (html->universal != NULL) {
lwc_string_unref(html->universal);
html->universal = NULL;
}
 
/* Free stylesheets */
for (i = 0; i != html->stylesheet_count; i++) {
if (html->stylesheets[i].type == HTML_STYLESHEET_EXTERNAL &&
html->stylesheets[i].data.external != NULL) {
hlcache_handle_release(
html->stylesheets[i].data.external);
} else if (html->stylesheets[i].type ==
HTML_STYLESHEET_INTERNAL &&
html->stylesheets[i].data.internal != NULL) {
nscss_destroy_css_data(
html->stylesheets[i].data.internal);
}
}
free(html->stylesheets);
 
/* Free scripts */
html_free_scripts(html);
 
/* Free objects */
html_destroy_objects(html);
 
/* free layout */
html_free_layout(html);
}
 
 
static nserror html_clone(const struct content *old, struct content **newc)
{
/** \todo Clone HTML specifics */
 
/* In the meantime, we should never be called, as HTML contents
* cannot be shared and we're not intending to fix printing's
* cloning of documents. */
assert(0 && "html_clone should never be called");
 
return true;
}
 
/**
* Set the content status.
*/
 
void html_set_status(html_content *c, const char *extra)
{
content_set_status(&c->base, extra);
}
 
 
/**
* Handle a window containing a CONTENT_HTML being opened.
*/
 
static void
html_open(struct content *c,
struct browser_window *bw,
struct content *page,
struct object_params *params)
{
html_content *html = (html_content *) c;
struct content_html_object *object, *next;
 
html->bw = bw;
html->page = (html_content *) page;
 
/* text selection */
selection_init(&html->sel, html->layout);
 
for (object = html->object_list; object != NULL; object = next) {
next = object->next;
 
if (object->content == NULL)
continue;
 
if (content_get_type(object->content) == CONTENT_NONE)
continue;
 
content_open(object->content,
bw, c,
object->box->object_params);
}
}
 
 
/**
* Handle a window containing a CONTENT_HTML being closed.
*/
 
static void html_close(struct content *c)
{
html_content *html = (html_content *) c;
struct content_html_object *object, *next;
 
if (html->search != NULL)
search_destroy_context(html->search);
 
html->bw = NULL;
 
for (object = html->object_list; object != NULL; object = next) {
next = object->next;
 
if (object->content == NULL)
continue;
 
if (content_get_type(object->content) == CONTENT_NONE)
continue;
 
if (content_get_type(object->content) == CONTENT_HTML)
schedule_remove(html_object_refresh, object);
 
content_close(object->content);
}
}
 
 
/**
* Return an HTML content's selection context
*/
 
static struct selection *html_get_selection(struct content *c)
{
html_content *html = (html_content *) c;
 
return &html->sel;
}
 
 
/**
* Get access to any content, link URLs and objects (images) currently
* at the given (x, y) coordinates.
*
* \param c html content to look inside
* \param x x-coordinate of point of interest
* \param y y-coordinate of point of interest
* \param data pointer to contextual_content struct. Its fields are updated
* with pointers to any relevent content, or set to NULL if none.
*/
static void
html_get_contextual_content(struct content *c,
int x,
int y,
struct contextual_content *data)
{
html_content *html = (html_content *) c;
 
struct box *box = html->layout;
struct box *next;
int box_x = 0, box_y = 0;
 
while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
box = next;
 
if (box->style && css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)
continue;
 
if (box->iframe)
browser_window_get_contextual_content(box->iframe,
x - box_x, y - box_y, data);
 
if (box->object)
content_get_contextual_content(box->object,
x - box_x, y - box_y, data);
 
if (box->object)
data->object = box->object;
 
if (box->href)
data->link_url = nsurl_access(box->href);
 
if (box->usemap) {
const char *target = NULL;
nsurl *url = imagemap_get(html, box->usemap, box_x,
box_y, x, y, &target);
/* Box might have imagemap, but no actual link area
* at point */
if (url != NULL)
data->link_url = nsurl_access(url);
}
if (box->gadget) {
switch (box->gadget->type) {
case GADGET_TEXTBOX:
case GADGET_TEXTAREA:
case GADGET_PASSWORD:
data->form_features = CTX_FORM_TEXT;
break;
 
case GADGET_FILE:
data->form_features = CTX_FORM_FILE;
break;
 
default:
data->form_features = CTX_FORM_NONE;
break;
}
}
}
}
 
 
/**
* Scroll deepest thing within the content which can be scrolled at given point
*
* \param c html content to look inside
* \param x x-coordinate of point of interest
* \param y y-coordinate of point of interest
* \param scrx x-coordinate of point of interest
* \param scry y-coordinate of point of interest
* \return true iff scroll was consumed by something in the content
*/
static bool
html_scroll_at_point(struct content *c, int x, int y, int scrx, int scry)
{
html_content *html = (html_content *) c;
 
struct box *box = html->layout;
struct box *next;
int box_x = 0, box_y = 0;
bool handled_scroll = false;
 
/* TODO: invert order; visit deepest box first */
 
while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
box = next;
 
if (box->style && css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)
continue;
 
/* Pass into iframe */
if (box->iframe && browser_window_scroll_at_point(box->iframe,
x - box_x, y - box_y, scrx, scry) == true)
return true;
 
/* Pass into object */
if (box->object != NULL && content_scroll_at_point(
box->object, x - box_x, y - box_y,
scrx, scry) == true)
return true;
 
/* Handle box scrollbars */
if (box->scroll_y && scrollbar_scroll(box->scroll_y, scry))
handled_scroll = true;
 
if (box->scroll_x && scrollbar_scroll(box->scroll_x, scrx))
handled_scroll = true;
 
if (handled_scroll == true)
return true;
}
 
return false;
}
 
 
/**
* Drop a file onto a content at a particular point, or determine if a file
* may be dropped onto the content at given point.
*
* \param c html content to look inside
* \param x x-coordinate of point of interest
* \param y y-coordinate of point of interest
* \param file path to file to be dropped, or NULL to know if drop allowed
* \return true iff file drop has been handled, or if drop possible (NULL file)
*/
static bool html_drop_file_at_point(struct content *c, int x, int y, char *file)
{
html_content *html = (html_content *) c;
 
struct box *box = html->layout;
struct box *next;
struct box *file_box = NULL;
struct box *text_box = NULL;
int box_x = 0, box_y = 0;
 
/* Scan box tree for boxes that can handle drop */
while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
box = next;
 
if (box->style && css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)
continue;
 
if (box->iframe)
return browser_window_drop_file_at_point(box->iframe,
x - box_x, y - box_y, file);
 
if (box->object && content_drop_file_at_point(box->object,
x - box_x, y - box_y, file) == true)
return true;
 
if (box->gadget) {
switch (box->gadget->type) {
case GADGET_FILE:
file_box = box;
break;
 
case GADGET_TEXTBOX:
case GADGET_TEXTAREA:
case GADGET_PASSWORD:
text_box = box;
break;
 
default: /* appease compiler */
break;
}
}
}
 
if (!file_box && !text_box)
/* No box capable of handling drop */
return false;
 
if (file == NULL)
/* There is a box capable of handling drop here */
return true;
 
/* Handle the drop */
if (file_box) {
/* File dropped on file input */
utf8_convert_ret ret;
char *utf8_fn;
 
ret = utf8_from_local_encoding(file, 0,
&utf8_fn);
if (ret != UTF8_CONVERT_OK) {
/* A bad encoding should never happen */
assert(ret != UTF8_CONVERT_BADENC);
LOG(("utf8_from_local_encoding failed"));
/* Load was for us - just no memory */
return true;
}
 
/* Found: update form input */
free(file_box->gadget->value);
file_box->gadget->value = utf8_fn;
 
/* Redraw box. */
html__redraw_a_box(html, file_box);
 
} else if (html->bw != NULL) {
/* File dropped on text input */
 
size_t file_len;
FILE *fp = NULL;
char *buffer;
char *utf8_buff;
utf8_convert_ret ret;
unsigned int size;
struct browser_window *bw;
 
/* Open file */
fp = fopen(file, "rb");
if (fp == NULL) {
/* Couldn't open file, but drop was for us */
return true;
}
 
/* Get filesize */
fseek(fp, 0, SEEK_END);
file_len = ftell(fp);
fseek(fp, 0, SEEK_SET);
 
/* Allocate buffer for file data */
buffer = malloc(file_len + 1);
if (buffer == NULL) {
/* No memory, but drop was for us */
fclose(fp);
return true;
}
 
/* Stick file into buffer */
if (file_len != fread(buffer, 1, file_len, fp)) {
/* Failed, but drop was for us */
free(buffer);
fclose(fp);
return true;
}
 
/* Done with file */
fclose(fp);
 
/* Ensure buffer's string termination */
buffer[file_len] = '\0';
 
/* TODO: Sniff for text? */
 
/* Convert to UTF-8 */
ret = utf8_from_local_encoding(buffer, file_len, &utf8_buff);
if (ret != UTF8_CONVERT_OK) {
/* bad encoding shouldn't happen */
assert(ret != UTF8_CONVERT_BADENC);
LOG(("utf8_from_local_encoding failed"));
free(buffer);
warn_user("NoMemory", NULL);
return true;
}
 
/* Done with buffer */
free(buffer);
 
/* Get new length */
size = strlen(utf8_buff);
 
/* Simulate a click over the input box, to place caret */
browser_window_mouse_click(html->bw,
BROWSER_MOUSE_PRESS_1, x, y);
 
bw = browser_window_get_root(html->bw);
 
/* Paste the file as text */
browser_window_paste_text(bw, utf8_buff, size, true);
 
free(utf8_buff);
}
 
return true;
}
 
 
/**
* Dump debug info concerning the html_content
*
* \param bw The browser window
* \param bw The file to dump to
*/
static void html_debug_dump(struct content *c, FILE *f)
{
html_content *html = (html_content *) c;
 
assert(html != NULL);
assert(html->layout != NULL);
 
box_dump(f, html->layout, 0);
}
 
 
/**
* Set an HTML content's search context
*
* \param c content of type html
* \param s search context, or NULL if none
*/
 
void html_set_search(struct content *c, struct search_context *s)
{
html_content *html = (html_content *) c;
 
html->search = s;
}
 
 
/**
* Return an HTML content's search context
*
* \param c content of type html
* \return content's search context, or NULL if none
*/
 
struct search_context *html_get_search(struct content *c)
{
html_content *html = (html_content *) c;
 
return html->search;
}
 
 
#if ALWAYS_DUMP_FRAMESET
/**
* Print a frameset tree to stderr.
*/
 
static void
html_dump_frameset(struct content_html_frames *frame, unsigned int depth)
{
unsigned int i;
int row, col, index;
const char *unit[] = {"px", "%", "*"};
const char *scrolling[] = {"auto", "yes", "no"};
 
assert(frame);
 
fprintf(stderr, "%p ", frame);
 
fprintf(stderr, "(%i %i) ", frame->rows, frame->cols);
 
fprintf(stderr, "w%g%s ", frame->width.value, unit[frame->width.unit]);
fprintf(stderr, "h%g%s ", frame->height.value,unit[frame->height.unit]);
fprintf(stderr, "(margin w%i h%i) ",
frame->margin_width, frame->margin_height);
 
if (frame->name)
fprintf(stderr, "'%s' ", frame->name);
if (frame->url)
fprintf(stderr, "<%s> ", frame->url);
 
if (frame->no_resize)
fprintf(stderr, "noresize ");
fprintf(stderr, "(scrolling %s) ", scrolling[frame->scrolling]);
if (frame->border)
fprintf(stderr, "border %x ",
(unsigned int) frame->border_colour);
 
fprintf(stderr, "\n");
 
if (frame->children) {
for (row = 0; row != frame->rows; row++) {
for (col = 0; col != frame->cols; col++) {
for (i = 0; i != depth; i++)
fprintf(stderr, " ");
fprintf(stderr, "(%i %i): ", row, col);
index = (row * frame->cols) + col;
html_dump_frameset(&frame->children[index],
depth + 1);
}
}
}
}
 
#endif
 
/**
* Retrieve HTML document tree
*
* \param h HTML content to retrieve document tree from
* \return Pointer to document tree
*/
dom_document *html_get_document(hlcache_handle *h)
{
html_content *c = (html_content *) hlcache_handle_get_content(h);
 
assert(c != NULL);
 
return c->document;
}
 
/**
* Retrieve box tree
*
* \param h HTML content to retrieve tree from
* \return Pointer to box tree
*
* \todo This API must die, as must all use of the box tree outside render/
*/
struct box *html_get_box_tree(hlcache_handle *h)
{
html_content *c = (html_content *) hlcache_handle_get_content(h);
 
assert(c != NULL);
 
return c->layout;
}
 
/**
* Retrieve the charset of an HTML document
*
* \param h Content to retrieve charset from
* \return Pointer to charset, or NULL
*/
const char *html_get_encoding(hlcache_handle *h)
{
html_content *c = (html_content *) hlcache_handle_get_content(h);
 
assert(c != NULL);
 
return c->encoding;
}
 
/**
* Retrieve the charset of an HTML document
*
* \param h Content to retrieve charset from
* \return Pointer to charset, or NULL
*/
dom_hubbub_encoding_source html_get_encoding_source(hlcache_handle *h)
{
html_content *c = (html_content *) hlcache_handle_get_content(h);
 
assert(c != NULL);
 
return c->encoding_source;
}
 
/**
* Retrieve framesets used in an HTML document
*
* \param h Content to inspect
* \return Pointer to framesets, or NULL if none
*/
struct content_html_frames *html_get_frameset(hlcache_handle *h)
{
html_content *c = (html_content *) hlcache_handle_get_content(h);
 
assert(c != NULL);
 
return c->frameset;
}
 
/**
* Retrieve iframes used in an HTML document
*
* \param h Content to inspect
* \return Pointer to iframes, or NULL if none
*/
struct content_html_iframe *html_get_iframe(hlcache_handle *h)
{
html_content *c = (html_content *) hlcache_handle_get_content(h);
 
assert(c != NULL);
 
return c->iframe;
}
 
/**
* Retrieve an HTML content's base URL
*
* \param h Content to retrieve base target from
* \return Pointer to URL
*/
nsurl *html_get_base_url(hlcache_handle *h)
{
html_content *c = (html_content *) hlcache_handle_get_content(h);
 
assert(c != NULL);
 
return c->base_url;
}
 
/**
* Retrieve an HTML content's base target
*
* \param h Content to retrieve base target from
* \return Pointer to target, or NULL if none
*/
const char *html_get_base_target(hlcache_handle *h)
{
html_content *c = (html_content *) hlcache_handle_get_content(h);
 
assert(c != NULL);
 
return c->base_target;
}
 
/**
* Retrieve stylesheets used by HTML document
*
* \param h Content to retrieve stylesheets from
* \param n Pointer to location to receive number of sheets
* \return Pointer to array of stylesheets
*/
struct html_stylesheet *html_get_stylesheets(hlcache_handle *h, unsigned int *n)
{
html_content *c = (html_content *) hlcache_handle_get_content(h);
 
assert(c != NULL);
assert(n != NULL);
 
*n = c->stylesheet_count;
 
return c->stylesheets;
}
 
/**
* Retrieve objects used by HTML document
*
* \param h Content to retrieve objects from
* \param n Pointer to location to receive number of objects
* \return Pointer to list of objects
*/
struct content_html_object *html_get_objects(hlcache_handle *h, unsigned int *n)
{
html_content *c = (html_content *) hlcache_handle_get_content(h);
 
assert(c != NULL);
assert(n != NULL);
 
*n = c->num_objects;
 
return c->object_list;
}
 
/**
* Retrieve layout coordinates of box with given id
*
* \param h HTML document to search
* \param frag_id String containing an element id
* \param x Updated to global x coord iff id found
* \param y Updated to global y coord iff id found
* \return true iff id found
*/
bool html_get_id_offset(hlcache_handle *h, lwc_string *frag_id, int *x, int *y)
{
struct box *pos;
struct box *layout;
 
if (content_get_type(h) != CONTENT_HTML)
return false;
 
layout = html_get_box_tree(h);
 
if ((pos = box_find_by_id(layout, frag_id)) != 0) {
box_coords(pos, x, y);
return true;
}
return false;
}
 
/**
* Compute the type of a content
*
* \return CONTENT_HTML
*/
static content_type html_content_type(void)
{
return CONTENT_HTML;
}
 
 
static void html_fini(void)
{
box_construct_fini();
 
if (html_user_stylesheet_url != NULL) {
nsurl_unref(html_user_stylesheet_url);
html_user_stylesheet_url = NULL;
}
 
if (html_quirks_stylesheet_url != NULL) {
nsurl_unref(html_quirks_stylesheet_url);
html_quirks_stylesheet_url = NULL;
}
 
if (html_adblock_stylesheet_url != NULL) {
nsurl_unref(html_adblock_stylesheet_url);
html_adblock_stylesheet_url = NULL;
}
 
if (html_default_stylesheet_url != NULL) {
nsurl_unref(html_default_stylesheet_url);
html_default_stylesheet_url = NULL;
}
 
if (html_charset != NULL) {
lwc_string_unref(html_charset);
html_charset = NULL;
}
}
 
static const content_handler html_content_handler = {
.fini = html_fini,
.create = html_create,
.process_data = html_process_data,
.data_complete = html_convert,
.reformat = html_reformat,
.destroy = html_destroy,
.stop = html_stop,
.mouse_track = html_mouse_track,
.mouse_action = html_mouse_action,
.redraw = html_redraw,
.open = html_open,
.close = html_close,
.get_selection = html_get_selection,
.get_contextual_content = html_get_contextual_content,
.scroll_at_point = html_scroll_at_point,
.drop_file_at_point = html_drop_file_at_point,
.debug_dump = html_debug_dump,
.clone = html_clone,
.type = html_content_type,
.no_share = true,
};
 
nserror html_init(void)
{
uint32_t i;
lwc_error lerror;
nserror error;
 
lerror = lwc_intern_string("charset", SLEN("charset"), &html_charset);
if (lerror != lwc_error_ok) {
error = NSERROR_NOMEM;
goto error;
}
 
error = nsurl_create("resource:default.css",
&html_default_stylesheet_url);
if (error != NSERROR_OK)
goto error;
 
error = nsurl_create("resource:adblock.css",
&html_adblock_stylesheet_url);
if (error != NSERROR_OK)
goto error;
 
error = nsurl_create("resource:quirks.css",
&html_quirks_stylesheet_url);
if (error != NSERROR_OK)
goto error;
 
error = nsurl_create("resource:user.css",
&html_user_stylesheet_url);
if (error != NSERROR_OK)
goto error;
 
error = box_construct_init();
if (error != NSERROR_OK)
goto error;
 
for (i = 0; i < NOF_ELEMENTS(html_types); i++) {
error = content_factory_register_handler(html_types[i],
&html_content_handler);
if (error != NSERROR_OK)
goto error;
}
 
return NSERROR_OK;
 
error:
html_fini();
 
return error;
}
 
/**
* Get the browser window containing an HTML content
*
* \param c HTML content
* \return the browser window
*/
struct browser_window *html_get_browser_window(struct content *c)
{
html_content *html = (html_content *) c;
 
assert(c != NULL);
assert(c->handler == &html_content_handler);
 
return html->bw;
}
/programs/network/netsurf/netsurf/render/html.h
0,0 → 1,189
/*
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for text/html (interface).
*
* These functions should in general be called via the content interface.
*/
 
#ifndef _NETSURF_RENDER_HTML_H_
#define _NETSURF_RENDER_HTML_H_
 
#include <stdbool.h>
 
#include <dom/dom.h>
#include <dom/bindings/hubbub/parser.h>
 
#include "content/content_type.h"
#include "css/css.h"
#include "desktop/mouse.h"
#include "desktop/plot_style.h"
#include "desktop/frame_types.h"
 
struct fetch_multipart_data;
struct box;
struct rect;
struct browser_window;
struct content;
struct hlcache_handle;
struct http_parameter;
struct imagemap;
struct object_params;
struct plotters;
struct scrollbar;
struct scrollbar_msg_data;
struct search_context;
 
/**
* Container for stylesheets used by an HTML document
*/
struct html_stylesheet {
/** Type of sheet */
enum { HTML_STYLESHEET_EXTERNAL, HTML_STYLESHEET_INTERNAL } type;
union {
struct hlcache_handle *external;
struct content_css_data *internal;
} data; /**< Sheet data */
};
 
/**
* Container for scripts used by an HTML document
*/
struct html_script {
/** Type of script */
enum html_script_type { HTML_SCRIPT_INLINE,
HTML_SCRIPT_SYNC,
HTML_SCRIPT_DEFER,
HTML_SCRIPT_ASYNC } type;
union {
struct hlcache_handle *handle;
struct dom_string *string;
} data; /**< Script data */
struct dom_string *mimetype;
struct dom_string *encoding;
bool already_started;
bool parser_inserted;
bool force_async;
bool ready_exec;
bool async;
bool defer;
};
 
 
/** An object (<img>, <object>, etc.) in a CONTENT_HTML document. */
struct content_html_object {
struct content *parent; /**< Parent document */
struct content_html_object *next; /**< Next in chain */
 
struct hlcache_handle *content; /**< Content, or 0. */
struct box *box; /**< Node in box tree containing it. */
/** Bitmap of acceptable content types */
content_type permitted_types;
bool background; /**< This object is a background image. */
};
 
struct html_scrollbar_data {
struct content *c;
struct box *box;
};
 
/** Frame tree (<frameset>, <frame>) */
struct content_html_frames {
int cols; /** number of columns in frameset */
int rows; /** number of rows in frameset */
 
struct frame_dimension width; /** frame width */
struct frame_dimension height; /** frame width */
int margin_width; /** frame margin width */
int margin_height; /** frame margin height */
 
char *name; /** frame name (for targetting) */
nsurl *url; /** frame url */
 
bool no_resize; /** frame is not resizable */
frame_scrolling scrolling; /** scrolling characteristics */
bool border; /** frame has a border */
colour border_colour; /** frame border colour */
 
struct content_html_frames *children; /** [cols * rows] children */
};
 
/** Inline frame list (<iframe>) */
struct content_html_iframe {
struct box *box;
 
int margin_width; /** frame margin width */
int margin_height; /** frame margin height */
 
char *name; /** frame name (for targetting) */
nsurl *url; /** frame url */
 
frame_scrolling scrolling; /** scrolling characteristics */
bool border; /** frame has a border */
colour border_colour; /** frame border colour */
 
struct content_html_iframe *next;
};
 
/* entries in stylesheet_content */
#define STYLESHEET_BASE 0 /* base style sheet */
#define STYLESHEET_QUIRKS 1 /* quirks mode stylesheet */
#define STYLESHEET_ADBLOCK 2 /* adblocking stylesheet */
#define STYLESHEET_USER 3 /* user stylesheet */
#define STYLESHEET_START 4 /* start of document stylesheets */
 
/** Render padding and margin box outlines in html_redraw(). */
extern bool html_redraw_debug;
 
nserror html_init(void);
 
void html_redraw_a_box(struct hlcache_handle *h, struct box *box);
 
void html_overflow_scroll_drag_end(struct scrollbar *scrollbar,
browser_mouse_state mouse, int x, int y);
 
bool text_redraw(const char *utf8_text, size_t utf8_len,
size_t offset, int space,
const plot_font_style_t *fstyle,
int x, int y,
const struct rect *clip,
int height,
float scale,
bool excluded,
struct content *c,
const struct selection *sel,
struct search_context *search,
const struct redraw_context *ctx);
 
dom_document *html_get_document(struct hlcache_handle *h);
struct box *html_get_box_tree(struct hlcache_handle *h);
const char *html_get_encoding(struct hlcache_handle *h);
dom_hubbub_encoding_source html_get_encoding_source(struct hlcache_handle *h);
struct content_html_frames *html_get_frameset(struct hlcache_handle *h);
struct content_html_iframe *html_get_iframe(struct hlcache_handle *h);
nsurl *html_get_base_url(struct hlcache_handle *h);
const char *html_get_base_target(struct hlcache_handle *h);
struct html_stylesheet *html_get_stylesheets(struct hlcache_handle *h,
unsigned int *n);
struct content_html_object *html_get_objects(struct hlcache_handle *h,
unsigned int *n);
bool html_get_id_offset(struct hlcache_handle *h, lwc_string *frag_id,
int *x, int *y);
 
#endif
/programs/network/netsurf/netsurf/render/html_forms.c
0,0 → 1,574
/*
* Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
 
#include "render/form.h"
#include "render/html_internal.h"
#include "utils/corestrings.h"
 
#include "utils/log.h"
 
/**
* process form element from dom
*/
static struct form *
parse_form_element(const char *docenc, dom_node *node)
{
dom_string *ds_action = NULL;
dom_string *ds_charset = NULL;
dom_string *ds_target = NULL;
dom_string *ds_method = NULL;
dom_string *ds_enctype = NULL;
char *action = NULL, *charset = NULL, *target = NULL;
form_method method;
dom_html_form_element *formele = (dom_html_form_element *)(node);
struct form * ret = NULL;
 
/* Retrieve the attributes from the node */
if (dom_html_form_element_get_action(formele,
&ds_action) != DOM_NO_ERR)
goto out;
 
if (dom_html_form_element_get_accept_charset(formele,
&ds_charset) != DOM_NO_ERR)
goto out;
 
if (dom_html_form_element_get_target(formele,
&ds_target) != DOM_NO_ERR)
goto out;
 
if (dom_html_form_element_get_method(formele,
&ds_method) != DOM_NO_ERR)
goto out;
 
if (dom_html_form_element_get_enctype(formele,
&ds_enctype) != DOM_NO_ERR)
goto out;
 
/* Extract the plain attributes ready for use. We have to do this
* because we cannot guarantee that the dom_strings are NULL terminated
* and thus we copy them.
*/
if (ds_action != NULL)
action = strndup(dom_string_data(ds_action),
dom_string_byte_length(ds_action));
 
if (ds_charset != NULL)
charset = strndup(dom_string_data(ds_charset),
dom_string_byte_length(ds_charset));
 
if (ds_target != NULL)
target = strndup(dom_string_data(ds_target),
dom_string_byte_length(ds_target));
 
/* Determine the method */
method = method_GET;
if (ds_method != NULL) {
if (dom_string_caseless_lwc_isequal(ds_method,
corestring_lwc_post)) {
method = method_POST_URLENC;
if (ds_enctype != NULL) {
if (dom_string_caseless_lwc_isequal(ds_enctype,
corestring_lwc_multipart_form_data)) {
 
method = method_POST_MULTIPART;
}
}
}
}
 
/* Construct the form object */
ret = form_new(node, action, target, method, charset, docenc);
 
out:
if (ds_action != NULL)
dom_string_unref(ds_action);
if (ds_charset != NULL)
dom_string_unref(ds_charset);
if (ds_target != NULL)
dom_string_unref(ds_target);
if (ds_method != NULL)
dom_string_unref(ds_method);
if (ds_enctype != NULL)
dom_string_unref(ds_enctype);
if (action != NULL)
free(action);
if (charset != NULL)
free(charset);
if (target != NULL)
free(target);
return ret;
}
 
/* documented in html_internal.h */
struct form *html_forms_get_forms(const char *docenc, dom_html_document *doc)
{
dom_html_collection *forms;
struct form *ret = NULL, *newf;
dom_node *node;
unsigned long n;
uint32_t nforms;
 
if (doc == NULL)
return NULL;
 
/* Attempt to build a set of all the forms */
if (dom_html_document_get_forms(doc, &forms) != DOM_NO_ERR)
return NULL;
 
/* Count the number of forms so we can iterate */
if (dom_html_collection_get_length(forms, &nforms) != DOM_NO_ERR)
goto out;
 
/* Iterate the forms collection, making form structs for returning */
for (n = 0; n < nforms; ++n) {
if (dom_html_collection_item(forms, n, &node) != DOM_NO_ERR) {
goto out;
}
newf = parse_form_element(docenc, node);
dom_node_unref(node);
if (newf == NULL) {
goto err;
}
newf->prev = ret;
ret = newf;
}
 
/* All went well */
goto out;
err:
while (ret != NULL) {
struct form *prev = ret->prev;
/* Destroy ret */
free(ret);
ret = prev;
}
out:
/* Finished with the collection, return it */
dom_html_collection_unref(forms);
 
return ret;
}
 
static struct form *
find_form(struct form *forms, dom_html_form_element *form)
{
while (forms != NULL) {
if (forms->node == form)
break;
forms = forms->prev;
}
 
return forms;
}
 
static struct form_control *
parse_button_element(struct form *forms, dom_html_button_element *button)
{
struct form_control *control = NULL;
dom_exception err;
dom_html_form_element *form = NULL;
dom_string *ds_type = NULL;
dom_string *ds_value = NULL;
dom_string *ds_name = NULL;
 
err = dom_html_button_element_get_form(button, &form);
if (err != DOM_NO_ERR)
goto out;
 
err = dom_html_button_element_get_type(button, &ds_type);
if (err != DOM_NO_ERR)
goto out;
 
if (ds_type == NULL) {
control = form_new_control(button, GADGET_SUBMIT);
} else {
if (dom_string_caseless_lwc_isequal(ds_type,
corestring_lwc_submit)) {
control = form_new_control(button, GADGET_SUBMIT);
} else if (dom_string_caseless_lwc_isequal(ds_type,
corestring_lwc_reset)) {
control = form_new_control(button, GADGET_RESET);
} else {
control = form_new_control(button, GADGET_BUTTON);
}
}
 
if (control == NULL)
goto out;
 
err = dom_html_button_element_get_value(button, &ds_value);
if (err != DOM_NO_ERR)
goto out;
err = dom_html_button_element_get_name(button, &ds_name);
if (err != DOM_NO_ERR)
goto out;
 
if (ds_value != NULL) {
control->value = strndup(
dom_string_data(ds_value),
dom_string_byte_length(ds_value));
 
if (control->value == NULL) {
form_free_control(control);
control = NULL;
goto out;
}
}
 
if (ds_name != NULL) {
control->name = strndup(
dom_string_data(ds_name),
dom_string_byte_length(ds_name));
 
if (control->name == NULL) {
form_free_control(control);
control = NULL;
goto out;
}
}
 
if (form != NULL && control != NULL)
form_add_control(find_form(forms, form), control);
 
out:
if (form != NULL)
dom_node_unref(form);
if (ds_type != NULL)
dom_string_unref(ds_type);
if (ds_value != NULL)
dom_string_unref(ds_value);
if (ds_name != NULL)
dom_string_unref(ds_name);
 
return control;
}
 
static struct form_control *
parse_input_element(struct form *forms, dom_html_input_element *input)
{
struct form_control *control = NULL;
dom_html_form_element *form = NULL;
dom_string *ds_type = NULL;
dom_string *ds_name = NULL;
dom_string *ds_value = NULL;
 
char *name = NULL;
 
if (dom_html_input_element_get_form(input, &form) != DOM_NO_ERR)
goto out;
 
if (dom_html_input_element_get_type(input, &ds_type) != DOM_NO_ERR)
goto out;
 
if (dom_html_input_element_get_name(input, &ds_name) != DOM_NO_ERR)
goto out;
 
if (ds_name != NULL)
name = strndup(dom_string_data(ds_name),
dom_string_byte_length(ds_name));
 
if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
corestring_lwc_password)) {
control = form_new_control(input, GADGET_PASSWORD);
} else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
corestring_lwc_file)) {
control = form_new_control(input, GADGET_FILE);
} else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
corestring_lwc_hidden)) {
control = form_new_control(input, GADGET_HIDDEN);
} else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
corestring_lwc_checkbox)) {
control = form_new_control(input, GADGET_CHECKBOX);
} else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
corestring_lwc_radio)) {
control = form_new_control(input, GADGET_RADIO);
} else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
corestring_lwc_submit)) {
control = form_new_control(input, GADGET_SUBMIT);
} else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
corestring_lwc_reset)) {
control = form_new_control(input, GADGET_RESET);
} else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
corestring_lwc_button)) {
control = form_new_control(input, GADGET_BUTTON);
} else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
corestring_lwc_image)) {
control = form_new_control(input, GADGET_IMAGE);
} else {
control = form_new_control(input, GADGET_TEXTBOX);
}
 
if (control == NULL)
goto out;
 
if (name != NULL) {
/* Hand the name string over */
control->name = name;
name = NULL;
}
 
if (control->type == GADGET_CHECKBOX || control->type == GADGET_RADIO) {
bool selected;
if (dom_html_input_element_get_checked(
input, &selected) == DOM_NO_ERR) {
control->selected = selected;
}
}
 
if (control->type == GADGET_PASSWORD ||
control->type == GADGET_TEXTBOX) {
int32_t maxlength;
if (dom_html_input_element_get_max_length(
input, &maxlength) != DOM_NO_ERR) {
maxlength = -1;
}
 
if (maxlength >= 0) {
/* Got valid maxlength */
control->maxlength = maxlength;
} else {
/* Input has no maxlength attr, or
* dom_html_input_element_get_max_length failed.
*
* Set it to something insane. */
control->maxlength = UINT_MAX;
}
}
 
if (control->type != GADGET_FILE && control->type != GADGET_IMAGE) {
if (dom_html_input_element_get_value(
input, &ds_value) == DOM_NO_ERR) {
if (ds_value != NULL) {
control->value = strndup(
dom_string_data(ds_value),
dom_string_byte_length(ds_value));
if (control->value == NULL) {
form_free_control(control);
control = NULL;
goto out;
}
control->length = strlen(control->value);
}
}
 
if (control->type == GADGET_TEXTBOX ||
control->type == GADGET_PASSWORD) {
if (control->value == NULL) {
control->value = strdup("");
if (control->value == NULL) {
form_free_control(control);
control = NULL;
goto out;
}
 
control->length = 0;
}
 
control->initial_value = strdup(control->value);
if (control->initial_value == NULL) {
form_free_control(control);
control = NULL;
goto out;
}
}
}
 
if (form != NULL && control != NULL)
form_add_control(find_form(forms, form), control);
 
out:
if (form != NULL)
dom_node_unref(form);
if (ds_type != NULL)
dom_string_unref(ds_type);
if (ds_name != NULL)
dom_string_unref(ds_name);
if (ds_value != NULL)
dom_string_unref(ds_value);
 
if (name != NULL)
free(name);
 
return control;
}
 
static struct form_control *
parse_textarea_element(struct form *forms, dom_html_text_area_element *ta)
{
struct form_control *control = NULL;
dom_html_form_element *form = NULL;
dom_string *ds_name = NULL;
 
char *name = NULL;
 
if (dom_html_text_area_element_get_form(ta, &form) != DOM_NO_ERR)
goto out;
 
if (dom_html_text_area_element_get_name(ta, &ds_name) != DOM_NO_ERR)
goto out;
 
if (ds_name != NULL)
name = strndup(dom_string_data(ds_name),
dom_string_byte_length(ds_name));
 
control = form_new_control(ta, GADGET_TEXTAREA);
 
if (control == NULL)
goto out;
 
if (name != NULL) {
/* Hand the name string over */
control->name = name;
name = NULL;
}
 
if (form != NULL && control != NULL)
form_add_control(find_form(forms, form), control);
 
out:
if (form != NULL)
dom_node_unref(form);
if (ds_name != NULL)
dom_string_unref(ds_name);
 
if (name != NULL)
free(name);
 
 
return control;
}
 
static struct form_control *
parse_select_element(struct form *forms, dom_html_select_element *select)
{
struct form_control *control = NULL;
dom_html_form_element *form = NULL;
dom_string *ds_name = NULL;
 
char *name = NULL;
 
if (dom_html_select_element_get_form(select, &form) != DOM_NO_ERR)
goto out;
 
if (dom_html_select_element_get_name(select, &ds_name) != DOM_NO_ERR)
goto out;
 
if (ds_name != NULL)
name = strndup(dom_string_data(ds_name),
dom_string_byte_length(ds_name));
 
control = form_new_control(select, GADGET_SELECT);
 
if (control == NULL)
goto out;
 
if (name != NULL) {
/* Hand the name string over */
control->name = name;
name = NULL;
}
 
dom_html_select_element_get_multiple(select,
&(control->data.select.multiple));
 
if (form != NULL && control != NULL)
form_add_control(find_form(forms, form), control);
 
out:
if (form != NULL)
dom_node_unref(form);
if (ds_name != NULL)
dom_string_unref(ds_name);
 
if (name != NULL)
free(name);
 
 
return control;
}
 
 
static struct form_control *
invent_fake_gadget(dom_node *node)
{
struct form_control *ctl = form_new_control(node, GADGET_HIDDEN);
if (ctl != NULL) {
ctl->value = strdup("");
ctl->initial_value = strdup("");
ctl->name = strdup("foo");
 
if (ctl->value == NULL || ctl->initial_value == NULL ||
ctl->name == NULL) {
form_free_control(ctl);
ctl = NULL;
}
}
return ctl;
}
 
/* documented in html_internal.h */
struct form_control *html_forms_get_control_for_node(struct form *forms, dom_node *node)
{
struct form *f;
struct form_control *ctl = NULL;
dom_exception err;
dom_string *ds_name = NULL;
 
/* Step one, see if we already have a control */
for (f = forms; f != NULL; f = f->prev) {
for (ctl = f->controls; ctl != NULL; ctl = ctl->next) {
if (ctl->node == node)
return ctl;
}
}
 
/* Step two, extract the node's name so we can construct a gadget. */
err = dom_element_get_tag_name(node, &ds_name);
if (err == DOM_NO_ERR && ds_name != NULL) {
 
/* Step three, attempt to work out what gadget to make */
if (dom_string_caseless_lwc_isequal(ds_name,
corestring_lwc_button)) {
ctl = parse_button_element(forms,
(dom_html_button_element *) node);
} else if (dom_string_caseless_lwc_isequal(ds_name,
corestring_lwc_input)) {
ctl = parse_input_element(forms,
(dom_html_input_element *) node);
} else if (dom_string_caseless_lwc_isequal(ds_name,
corestring_lwc_textarea)) {
ctl = parse_textarea_element(forms,
(dom_html_text_area_element *) node);
} else if (dom_string_caseless_lwc_isequal(ds_name,
corestring_lwc_select)) {
ctl = parse_select_element(forms,
(dom_html_select_element *) node);
}
}
 
/* If all else fails, fake gadget time */
if (ctl == NULL)
ctl = invent_fake_gadget(node);
 
if (ds_name != NULL)
dom_string_unref(ds_name);
 
return ctl;
}
 
/programs/network/netsurf/netsurf/render/html_interaction.c
0,0 → 1,990
/*
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
* Copyright 2006 Richard Wilson <info@tinct.net>
* Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* User interaction with a CONTENT_HTML (implementation).
*/
 
#include <assert.h>
#include <stdbool.h>
 
#include <dom/dom.h>
 
#include "content/content.h"
#include "desktop/browser.h"
#include "desktop/frames.h"
#include "desktop/mouse.h"
#include "desktop/options.h"
#include "desktop/scrollbar.h"
#include "desktop/selection.h"
#include "desktop/textinput.h"
#include "render/box.h"
#include "render/font.h"
#include "render/form.h"
#include "render/html_internal.h"
#include "render/imagemap.h"
#include "render/textinput.h"
#include "javascript/js.h"
#include "utils/messages.h"
#include "utils/utils.h"
 
 
/**
* Get pointer shape for given box
*
* \param box box in question
* \param imagemap whether an imagemap applies to the box
*/
 
static browser_pointer_shape get_pointer_shape(struct box *box, bool imagemap)
{
browser_pointer_shape pointer;
css_computed_style *style;
enum css_cursor_e cursor;
lwc_string **cursor_uris;
 
if (box->type == BOX_FLOAT_LEFT || box->type == BOX_FLOAT_RIGHT)
style = box->children->style;
else
style = box->style;
 
if (style == NULL)
return BROWSER_POINTER_DEFAULT;
 
cursor = css_computed_cursor(style, &cursor_uris);
 
switch (cursor) {
case CSS_CURSOR_AUTO:
if (box->href || (box->gadget &&
(box->gadget->type == GADGET_IMAGE ||
box->gadget->type == GADGET_SUBMIT)) ||
imagemap) {
/* link */
pointer = BROWSER_POINTER_POINT;
} else if (box->gadget &&
(box->gadget->type == GADGET_TEXTBOX ||
box->gadget->type == GADGET_PASSWORD ||
box->gadget->type == GADGET_TEXTAREA)) {
/* text input */
pointer = BROWSER_POINTER_CARET;
} else {
/* html content doesn't mind */
pointer = BROWSER_POINTER_AUTO;
}
break;
case CSS_CURSOR_CROSSHAIR:
pointer = BROWSER_POINTER_CROSS;
break;
case CSS_CURSOR_POINTER:
pointer = BROWSER_POINTER_POINT;
break;
case CSS_CURSOR_MOVE:
pointer = BROWSER_POINTER_MOVE;
break;
case CSS_CURSOR_E_RESIZE:
pointer = BROWSER_POINTER_RIGHT;
break;
case CSS_CURSOR_W_RESIZE:
pointer = BROWSER_POINTER_LEFT;
break;
case CSS_CURSOR_N_RESIZE:
pointer = BROWSER_POINTER_UP;
break;
case CSS_CURSOR_S_RESIZE:
pointer = BROWSER_POINTER_DOWN;
break;
case CSS_CURSOR_NE_RESIZE:
pointer = BROWSER_POINTER_RU;
break;
case CSS_CURSOR_SW_RESIZE:
pointer = BROWSER_POINTER_LD;
break;
case CSS_CURSOR_SE_RESIZE:
pointer = BROWSER_POINTER_RD;
break;
case CSS_CURSOR_NW_RESIZE:
pointer = BROWSER_POINTER_LU;
break;
case CSS_CURSOR_TEXT:
pointer = BROWSER_POINTER_CARET;
break;
case CSS_CURSOR_WAIT:
pointer = BROWSER_POINTER_WAIT;
break;
case CSS_CURSOR_PROGRESS:
pointer = BROWSER_POINTER_PROGRESS;
break;
case CSS_CURSOR_HELP:
pointer = BROWSER_POINTER_HELP;
break;
default:
pointer = BROWSER_POINTER_DEFAULT;
break;
}
 
return pointer;
}
 
 
/**
* Start drag scrolling the contents of a box
*
* \param box the box to be scrolled
* \param x x ordinate of initial mouse position
* \param y y ordinate
*/
 
static void html_box_drag_start(struct box *box, int x, int y)
{
int box_x, box_y;
int scroll_mouse_x, scroll_mouse_y;
 
box_coords(box, &box_x, &box_y);
 
if (box->scroll_x != NULL) {
scroll_mouse_x = x - box_x ;
scroll_mouse_y = y - (box_y + box->padding[TOP] +
box->height + box->padding[BOTTOM] -
SCROLLBAR_WIDTH);
scrollbar_start_content_drag(box->scroll_x,
scroll_mouse_x, scroll_mouse_y);
} else if (box->scroll_y != NULL) {
scroll_mouse_x = x - (box_x + box->padding[LEFT] +
box->width + box->padding[RIGHT] -
SCROLLBAR_WIDTH);
scroll_mouse_y = y - box_y;
 
scrollbar_start_content_drag(box->scroll_y,
scroll_mouse_x, scroll_mouse_y);
}
}
 
 
/**
* End overflow scroll scrollbar drags
*
* \param h html content's high level cache entry
* \param mouse state of mouse buttons and modifier keys
* \param x coordinate of mouse
* \param y coordinate of mouse
*/
static size_t html_selection_drag_end(struct html_content *html,
browser_mouse_state mouse, int x, int y, int dir)
{
int pixel_offset;
struct box *box;
int dx, dy;
size_t idx = 0;
 
box = box_pick_text_box(html, x, y, dir, &dx, &dy);
if (box) {
plot_font_style_t fstyle;
 
font_plot_style_from_css(box->style, &fstyle);
 
nsfont.font_position_in_string(&fstyle, box->text, box->length,
dx, &idx, &pixel_offset);
 
idx += box->byte_offset;
}
 
return idx;
}
 
 
/**
* Handle mouse tracking (including drags) in an HTML content window.
*
* \param c content of type html
* \param bw browser window
* \param mouse state of mouse buttons and modifier keys
* \param x coordinate of mouse
* \param y coordinate of mouse
*/
 
void html_mouse_track(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
html_content *html = (html_content*) c;
browser_drag_type drag_type = browser_window_get_drag_type(bw);
 
if (drag_type == DRAGGING_SELECTION && !mouse) {
int dir = -1;
size_t idx;
 
if (selection_dragging_start(&html->sel))
dir = 1;
 
idx = html_selection_drag_end(html, mouse, x, y, dir);
 
if (idx != 0)
selection_track(&html->sel, mouse, idx);
 
browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);
}
 
switch (drag_type) {
case DRAGGING_SELECTION: {
struct box *box;
int dir = -1;
int dx, dy;
 
if (selection_dragging_start(&html->sel))
dir = 1;
 
box = box_pick_text_box(html, x, y, dir, &dx, &dy);
 
if (box) {
int pixel_offset;
size_t idx;
plot_font_style_t fstyle;
 
font_plot_style_from_css(box->style, &fstyle);
 
nsfont.font_position_in_string(&fstyle,
box->text, box->length,
dx, &idx, &pixel_offset);
 
selection_track(&html->sel, mouse,
box->byte_offset + idx);
}
}
break;
 
default:
html_mouse_action(c, bw, mouse, x, y);
break;
}
}
 
 
/**
* Handle mouse clicks and movements in an HTML content window.
*
* \param c content of type html
* \param bw browser window
* \param mouse state of mouse buttons and modifier keys
* \param x coordinate of mouse
* \param y coordinate of mouse
*
* This function handles both hovering and clicking. It is important that the
* code path is identical (except that hovering doesn't carry out the action),
* so that the status bar reflects exactly what will happen. Having separate
* code paths opens the possibility that an attacker will make the status bar
* show some harmless action where clicking will be harmful.
*/
 
void html_mouse_action(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
html_content *html = (html_content *) c;
enum { ACTION_NONE, ACTION_SUBMIT, ACTION_GO } action = ACTION_NONE;
const char *title = 0;
nsurl *url = 0;
const char *target = 0;
char status_buffer[200];
const char *status = 0;
browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT;
bool imagemap = false;
int box_x = 0, box_y = 0;
int gadget_box_x = 0, gadget_box_y = 0;
int html_object_pos_x = 0, html_object_pos_y = 0;
int text_box_x = 0;
struct box *url_box = 0;
struct box *gadget_box = 0;
struct box *text_box = 0;
struct box *box;
struct form_control *gadget = 0;
hlcache_handle *object = NULL;
struct box *html_object_box = NULL;
struct browser_window *iframe = NULL;
struct box *next_box;
struct box *drag_candidate = NULL;
struct scrollbar *scrollbar = NULL;
plot_font_style_t fstyle;
int scroll_mouse_x = 0, scroll_mouse_y = 0;
int padding_left, padding_right, padding_top, padding_bottom;
browser_drag_type drag_type = browser_window_get_drag_type(bw);
union content_msg_data msg_data;
struct dom_node *node = NULL;
 
if (drag_type != DRAGGING_NONE && !mouse &&
html->visible_select_menu != NULL) {
/* drag end: select menu */
form_select_mouse_drag_end(html->visible_select_menu,
mouse, x, y);
}
 
if (html->visible_select_menu != NULL) {
box = html->visible_select_menu->box;
box_coords(box, &box_x, &box_y);
 
box_x -= box->border[LEFT].width;
box_y += box->height + box->border[BOTTOM].width +
box->padding[BOTTOM] + box->padding[TOP];
status = form_select_mouse_action(html->visible_select_menu,
mouse, x - box_x, y - box_y);
if (status != NULL) {
msg_data.explicit_status_text = status;
content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
} else {
int width, height;
form_select_get_dimensions(html->visible_select_menu,
&width, &height);
html->visible_select_menu = NULL;
browser_window_redraw_rect(bw, box_x, box_y,
width, height);
}
return;
}
 
if (!mouse && html->scrollbar != NULL) {
/* drag end: scrollbar */
html_overflow_scroll_drag_end(html->scrollbar, mouse, x, y);
}
 
if (html->scrollbar != NULL) {
struct html_scrollbar_data *data =
scrollbar_get_data(html->scrollbar);
box = data->box;
box_coords(box, &box_x, &box_y);
if (scrollbar_is_horizontal(html->scrollbar)) {
scroll_mouse_x = x - box_x ;
scroll_mouse_y = y - (box_y + box->padding[TOP] +
box->height + box->padding[BOTTOM] -
SCROLLBAR_WIDTH);
status = scrollbar_mouse_action(html->scrollbar, mouse,
scroll_mouse_x, scroll_mouse_y);
} else {
scroll_mouse_x = x - (box_x + box->padding[LEFT] +
box->width + box->padding[RIGHT] -
SCROLLBAR_WIDTH);
scroll_mouse_y = y - box_y;
status = scrollbar_mouse_action(html->scrollbar, mouse,
scroll_mouse_x, scroll_mouse_y);
}
 
msg_data.explicit_status_text = status;
content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
return;
}
 
/* Content related drags handled by now */
browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);
 
/* search the box tree for a link, imagemap, form control, or
* box with scrollbars
*/
 
box = html->layout;
 
/* Consider the margins of the html page now */
box_x = box->margin[LEFT];
box_y = box->margin[TOP];
 
/* descend through visible boxes setting more specific values for:
* box - deepest box at point
* html_object_box - html object
* html_object_pos_x - html object
* html_object_pos_y - html object
* object - non html object
* iframe - iframe
* url - href or imagemap
* target - href or imagemap or gadget
* url_box - href or imagemap
* imagemap - imagemap
* gadget - gadget
* gadget_box - gadget
* gadget_box_x - gadget
* gadget_box_y - gadget
* title - title
* pointer
*
* drag_candidate - first box with scroll
* padding_left - box with scroll
* padding_right
* padding_top
* padding_bottom
* scrollbar - inside padding box stops decent
* scroll_mouse_x - inside padding box stops decent
* scroll_mouse_y - inside padding box stops decent
*
* text_box - text box
* text_box_x - text_box
*/
while ((next_box = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
box = next_box;
 
if ((box->style != NULL) &&
(css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)) {
continue;
}
 
if (box->node != NULL) {
node = box->node;
}
 
if (box->object) {
if (content_get_type(box->object) == CONTENT_HTML) {
html_object_box = box;
html_object_pos_x = box_x;
html_object_pos_y = box_y;
} else {
object = box->object;
}
}
 
if (box->iframe) {
iframe = box->iframe;
}
 
if (box->href) {
url = box->href;
target = box->target;
url_box = box;
}
 
if (box->usemap) {
url = imagemap_get(html, box->usemap,
box_x, box_y, x, y, &target);
if (url) {
imagemap = true;
url_box = box;
}
}
 
if (box->gadget) {
gadget = box->gadget;
gadget_box = box;
gadget_box_x = box_x;
gadget_box_y = box_y;
if (gadget->form)
target = gadget->form->target;
}
 
if (box->title) {
title = box->title;
}
 
pointer = get_pointer_shape(box, false);
if ((box->scroll_x != NULL) ||
(box->scroll_y != NULL)) {
 
if (drag_candidate == NULL) {
drag_candidate = box;
}
 
padding_left = box_x +
scrollbar_get_offset(box->scroll_x);
padding_right = padding_left + box->padding[LEFT] +
box->width + box->padding[RIGHT];
padding_top = box_y +
scrollbar_get_offset(box->scroll_y);
padding_bottom = padding_top + box->padding[TOP] +
box->height + box->padding[BOTTOM];
if ((x > padding_left) &&
(x < padding_right) &&
(y > padding_top) &&
(y < padding_bottom)) {
/* mouse inside padding box */
if ((box->scroll_y != NULL) &&
(x > (padding_right - SCROLLBAR_WIDTH))) {
/* mouse above vertical box scroll */
scrollbar = box->scroll_y;
scroll_mouse_x = x - (padding_right -
SCROLLBAR_WIDTH);
scroll_mouse_y = y - padding_top;
break;
} else if ((box->scroll_x != NULL) &&
(y > (padding_bottom - SCROLLBAR_WIDTH))) {
/* mouse above horizontal box scroll */
scrollbar = box->scroll_x;
scroll_mouse_x = x - padding_left;
scroll_mouse_y = y - (padding_bottom -
SCROLLBAR_WIDTH);
break;
}
}
}
 
if (box->text && !box->object) {
text_box = box;
text_box_x = box_x;
}
}
 
/* use of box_x, box_y, or content below this point is probably a
* mistake; they will refer to the last box returned by box_at_point */
 
if (scrollbar) {
status = scrollbar_mouse_action(scrollbar, mouse,
scroll_mouse_x, scroll_mouse_y);
pointer = BROWSER_POINTER_DEFAULT;
} else if (gadget) {
switch (gadget->type) {
case GADGET_SELECT:
status = messages_get("FormSelect");
pointer = BROWSER_POINTER_MENU;
if (mouse & BROWSER_MOUSE_CLICK_1 &&
nsoption_bool(core_select_menu)) {
html->visible_select_menu = gadget;
form_open_select_menu(c, gadget,
form_select_menu_callback,
c);
pointer = BROWSER_POINTER_DEFAULT;
} else if (mouse & BROWSER_MOUSE_CLICK_1)
gui_create_form_select_menu(bw, gadget);
break;
case GADGET_CHECKBOX:
status = messages_get("FormCheckbox");
if (mouse & BROWSER_MOUSE_CLICK_1) {
gadget->selected = !gadget->selected;
html__redraw_a_box(html, gadget_box);
}
break;
case GADGET_RADIO:
status = messages_get("FormRadio");
if (mouse & BROWSER_MOUSE_CLICK_1)
form_radio_set(html, gadget);
break;
case GADGET_IMAGE:
if (mouse & BROWSER_MOUSE_CLICK_1) {
gadget->data.image.mx = x - gadget_box_x;
gadget->data.image.my = y - gadget_box_y;
}
/* drop through */
case GADGET_SUBMIT:
if (gadget->form) {
snprintf(status_buffer, sizeof status_buffer,
messages_get("FormSubmit"),
gadget->form->action);
status = status_buffer;
pointer = get_pointer_shape(gadget_box, false);
if (mouse & (BROWSER_MOUSE_CLICK_1 |
BROWSER_MOUSE_CLICK_2))
action = ACTION_SUBMIT;
} else {
status = messages_get("FormBadSubmit");
}
break;
case GADGET_TEXTAREA:
status = messages_get("FormTextarea");
pointer = get_pointer_shape(gadget_box, false);
 
if (mouse & (BROWSER_MOUSE_PRESS_1 |
BROWSER_MOUSE_PRESS_2)) {
if (text_box && selection_root(&html->sel) !=
gadget_box)
selection_init(&html->sel, gadget_box);
 
textinput_textarea_click(c, mouse,
gadget_box,
gadget_box_x,
gadget_box_y,
x - gadget_box_x,
y - gadget_box_y);
}
 
if (text_box) {
int pixel_offset;
size_t idx;
 
font_plot_style_from_css(text_box->style,
&fstyle);
 
nsfont.font_position_in_string(&fstyle,
text_box->text,
text_box->length,
x - gadget_box_x - text_box->x,
&idx,
&pixel_offset);
 
selection_click(&html->sel, mouse,
text_box->byte_offset + idx);
 
if (selection_dragging(&html->sel)) {
browser_window_set_drag_type(bw,
DRAGGING_SELECTION,
NULL);
status = messages_get("Selecting");
}
}
else if (mouse & BROWSER_MOUSE_PRESS_1)
selection_clear(&html->sel, true);
break;
case GADGET_TEXTBOX:
case GADGET_PASSWORD:
status = messages_get("FormTextbox");
pointer = get_pointer_shape(gadget_box, false);
 
if ((mouse & BROWSER_MOUSE_PRESS_1) &&
!(mouse & (BROWSER_MOUSE_MOD_1 |
BROWSER_MOUSE_MOD_2))) {
textinput_input_click(c,
gadget_box,
gadget_box_x,
gadget_box_y,
x - gadget_box_x,
y - gadget_box_y);
}
if (text_box) {
int pixel_offset;
size_t idx;
 
if (mouse & (BROWSER_MOUSE_DRAG_1 |
BROWSER_MOUSE_DRAG_2))
selection_init(&html->sel, gadget_box);
 
font_plot_style_from_css(text_box->style,
&fstyle);
 
nsfont.font_position_in_string(&fstyle,
text_box->text,
text_box->length,
x - gadget_box_x - text_box->x,
&idx,
&pixel_offset);
 
selection_click(&html->sel, mouse,
text_box->byte_offset + idx);
 
if (selection_dragging(&html->sel))
browser_window_set_drag_type(bw,
DRAGGING_SELECTION,
NULL);
}
else if (mouse & BROWSER_MOUSE_PRESS_1)
selection_clear(&html->sel, true);
break;
case GADGET_HIDDEN:
/* not possible: no box generated */
break;
case GADGET_RESET:
status = messages_get("FormReset");
break;
case GADGET_FILE:
status = messages_get("FormFile");
break;
case GADGET_BUTTON:
/* This gadget cannot be activated */
status = messages_get("FormButton");
break;
}
 
} else if (object && (mouse & BROWSER_MOUSE_MOD_2)) {
 
if (mouse & BROWSER_MOUSE_DRAG_2) {
msg_data.dragsave.type = CONTENT_SAVE_NATIVE;
msg_data.dragsave.content = object;
content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data);
 
} else if (mouse & BROWSER_MOUSE_DRAG_1) {
msg_data.dragsave.type = CONTENT_SAVE_ORIG;
msg_data.dragsave.content = object;
content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data);
}
 
/* \todo should have a drag-saving object msg */
 
} else if (iframe) {
int pos_x, pos_y;
float scale = browser_window_get_scale(bw);
 
browser_window_get_position(iframe, false, &pos_x, &pos_y);
 
pos_x /= scale;
pos_y /= scale;
 
if (mouse & BROWSER_MOUSE_CLICK_1 ||
mouse & BROWSER_MOUSE_CLICK_2) {
browser_window_mouse_click(iframe, mouse,
x - pos_x, y - pos_y);
} else {
browser_window_mouse_track(iframe, mouse,
x - pos_x, y - pos_y);
}
} else if (html_object_box) {
if (mouse & BROWSER_MOUSE_CLICK_1 ||
mouse & BROWSER_MOUSE_CLICK_2) {
content_mouse_action(html_object_box->object,
bw, mouse,
x - html_object_pos_x,
y - html_object_pos_y);
} else {
content_mouse_track(html_object_box->object,
bw, mouse,
x - html_object_pos_x,
y - html_object_pos_y);
}
} else if (url) {
if (title) {
snprintf(status_buffer, sizeof status_buffer, "%s: %s",
nsurl_access(url), title);
status = status_buffer;
} else
status = nsurl_access(url);
 
pointer = get_pointer_shape(url_box, imagemap);
 
if (mouse & BROWSER_MOUSE_CLICK_1 &&
mouse & BROWSER_MOUSE_MOD_1) {
/* force download of link */
browser_window_go_post(bw, nsurl_access(url), 0, 0,
false,
nsurl_access(content_get_url(c)),
true, true, 0);
 
} else if (mouse & BROWSER_MOUSE_CLICK_2 &&
mouse & BROWSER_MOUSE_MOD_1) {
msg_data.savelink.url = nsurl_access(url);
msg_data.savelink.title = title;
content_broadcast(c, CONTENT_MSG_SAVELINK, msg_data);
 
} else if (mouse & (BROWSER_MOUSE_CLICK_1 |
BROWSER_MOUSE_CLICK_2))
action = ACTION_GO;
} else {
bool done = false;
 
/* frame resizing */
if (browser_window_frame_resize_start(bw, mouse, x, y,
&pointer)) {
if (mouse & (BROWSER_MOUSE_DRAG_1 |
BROWSER_MOUSE_DRAG_2)) {
status = messages_get("FrameDrag");
}
done = true;
}
 
/* if clicking in the main page, remove the selection from any
* text areas */
if (!done) {
struct box *layout = html->layout;
 
if (mouse && (mouse < BROWSER_MOUSE_MOD_1) &&
selection_root(&html->sel) != layout) {
selection_init(&html->sel, layout);
}
 
if (text_box) {
int pixel_offset;
size_t idx;
 
font_plot_style_from_css(text_box->style,
&fstyle);
 
nsfont.font_position_in_string(&fstyle,
text_box->text,
text_box->length,
x - text_box_x,
&idx,
&pixel_offset);
 
if (selection_click(&html->sel, mouse,
text_box->byte_offset + idx)) {
/* key presses must be directed at the
* main browser window, paste text
* operations ignored */
 
if (selection_dragging(&html->sel)) {
browser_window_set_drag_type(bw,
DRAGGING_SELECTION,
NULL);
status = messages_get(
"Selecting");
}
 
done = true;
}
 
} else if (mouse & BROWSER_MOUSE_PRESS_1)
selection_clear(&html->sel, true);
}
 
if (!done) {
if (title)
status = title;
 
if (mouse & BROWSER_MOUSE_DRAG_1) {
if (mouse & BROWSER_MOUSE_MOD_2) {
msg_data.dragsave.type =
CONTENT_SAVE_COMPLETE;
msg_data.dragsave.content = NULL;
content_broadcast(c,
CONTENT_MSG_DRAGSAVE,
msg_data);
} else {
if (drag_candidate == NULL) {
browser_window_page_drag_start(
bw, x, y);
} else {
html_box_drag_start(
drag_candidate,
x, y);
}
pointer = BROWSER_POINTER_MOVE;
}
}
else if (mouse & BROWSER_MOUSE_DRAG_2) {
if (mouse & BROWSER_MOUSE_MOD_2) {
msg_data.dragsave.type =
CONTENT_SAVE_SOURCE;
msg_data.dragsave.content = NULL;
content_broadcast(c,
CONTENT_MSG_DRAGSAVE,
msg_data);
} else {
if (drag_candidate == NULL) {
browser_window_page_drag_start(
bw, x, y);
} else {
html_box_drag_start(
drag_candidate,
x, y);
}
pointer = BROWSER_POINTER_MOVE;
}
}
}
if (mouse && mouse < BROWSER_MOUSE_MOD_1) {
/* ensure key presses still act on the browser window */
browser_window_remove_caret(bw);
}
}
 
if (!iframe && !html_object_box) {
msg_data.explicit_status_text = status;
content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
 
msg_data.pointer = pointer;
content_broadcast(c, CONTENT_MSG_POINTER, msg_data);
}
 
/* fire dom click event */
if ((mouse & BROWSER_MOUSE_CLICK_1) ||
(mouse & BROWSER_MOUSE_CLICK_2)) {
js_fire_event(html->jscontext, "click", html->document, node);
}
 
/* deferred actions that can cause this browser_window to be destroyed
* and must therefore be done after set_status/pointer
*/
switch (action) {
case ACTION_SUBMIT:
form_submit(content_get_url(c),
browser_window_find_target(bw, target, mouse),
gadget->form, gadget);
break;
case ACTION_GO:
browser_window_go(browser_window_find_target(bw, target, mouse),
nsurl_access(url),
nsurl_access(content_get_url(c)), true);
break;
case ACTION_NONE:
break;
}
}
 
 
/**
* Callback for in-page scrollbars.
*/
void html_overflow_scroll_callback(void *client_data,
struct scrollbar_msg_data *scrollbar_data)
{
struct html_scrollbar_data *data = client_data;
html_content *html = (html_content *)data->c;
struct box *box = data->box;
union content_msg_data msg_data;
switch(scrollbar_data->msg) {
case SCROLLBAR_MSG_MOVED:
html__redraw_a_box(html, box);
break;
case SCROLLBAR_MSG_SCROLL_START:
{
struct rect rect = {
.x0 = scrollbar_data->x0,
.y0 = scrollbar_data->y0,
.x1 = scrollbar_data->x1,
.y1 = scrollbar_data->y1
};
browser_window_set_drag_type(html->bw,
DRAGGING_CONTENT_SCROLLBAR, &rect);
 
html->scrollbar = scrollbar_data->scrollbar;
}
break;
case SCROLLBAR_MSG_SCROLL_FINISHED:
html->scrollbar = NULL;
 
browser_window_set_drag_type(html->bw,
DRAGGING_NONE, NULL);
 
msg_data.pointer = BROWSER_POINTER_AUTO;
content_broadcast(data->c, CONTENT_MSG_POINTER,
msg_data);
break;
}
}
 
 
/**
* End overflow scroll scrollbar drags
*
* \param scroll scrollbar widget
* \param mouse state of mouse buttons and modifier keys
* \param x coordinate of mouse
* \param y coordinate of mouse
*/
void html_overflow_scroll_drag_end(struct scrollbar *scrollbar,
browser_mouse_state mouse, int x, int y)
{
int scroll_mouse_x, scroll_mouse_y, box_x, box_y;
struct html_scrollbar_data *data = scrollbar_get_data(scrollbar);
struct box *box;
 
box = data->box;
box_coords(box, &box_x, &box_y);
 
if (scrollbar_is_horizontal(scrollbar)) {
scroll_mouse_x = x - box_x;
scroll_mouse_y = y - (box_y + box->padding[TOP] +
box->height + box->padding[BOTTOM] -
SCROLLBAR_WIDTH);
scrollbar_mouse_drag_end(scrollbar, mouse,
scroll_mouse_x, scroll_mouse_y);
} else {
scroll_mouse_x = x - (box_x + box->padding[LEFT] +
box->width + box->padding[RIGHT] -
SCROLLBAR_WIDTH);
scroll_mouse_y = y - box_y;
scrollbar_mouse_drag_end(scrollbar, mouse,
scroll_mouse_x, scroll_mouse_y);
}
}
/programs/network/netsurf/netsurf/render/html_internal.h
0,0 → 1,193
/*
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for text/html (private data).
*/
 
#ifndef NETSURF_RENDER_HTML_INTERNAL_H_
#define NETSURF_RENDER_HTML_INTERNAL_H_
 
#include "content/content_protected.h"
#include "desktop/selection.h"
#include "render/html.h"
#include <dom/functypes.h>
 
/** Data specific to CONTENT_HTML. */
typedef struct html_content {
struct content base;
 
dom_hubbub_parser *parser; /**< Parser object handle */
 
/** Document tree */
dom_document *document;
/** Quirkyness of document */
dom_document_quirks_mode quirks;
 
/** Encoding of source, NULL if unknown. */
char *encoding;
/** Source of encoding information. */
dom_hubbub_encoding_source encoding_source;
 
/** Base URL (may be a copy of content->url). */
nsurl *base_url;
/** Base target */
char *base_target;
 
/** Content has been aborted in the LOADING state */
bool aborted;
 
/** A talloc context purely for the render box tree */
int *bctx;
/** Box tree, or NULL. */
struct box *layout;
/** Document background colour. */
colour background_colour;
/** Font callback table */
const struct font_functions *font_func;
 
/** Number of entries in scripts */
unsigned int scripts_count;
/** Scripts */
struct html_script *scripts;
/** javascript context */
struct jscontext *jscontext;
 
/** Number of entries in stylesheet_content. */
unsigned int stylesheet_count;
/** Stylesheets. Each may be NULL. */
struct html_stylesheet *stylesheets;
/**< Style selection context */
css_select_ctx *select_ctx;
/**< Universal selector */
lwc_string *universal;
 
/** Number of entries in object_list. */
unsigned int num_objects;
/** List of objects. */
struct content_html_object *object_list;
/** Forms, in reverse order to document. */
struct form *forms;
/** Hash table of imagemaps. */
struct imagemap **imagemaps;
 
/** Browser window containing this document, or NULL if not open. */
struct browser_window *bw;
 
/** Frameset information */
struct content_html_frames *frameset;
 
/** Inline frame information */
struct content_html_iframe *iframe;
 
/** Content of type CONTENT_HTML containing this, or NULL if not an
* object within a page. */
struct html_content *page;
 
/** Scrollbar capturing all mouse events, updated to any active HTML
* scrollbar, or NULL when no scrollbar drags active */
struct scrollbar *scrollbar;
 
/** Open core-handled form SELECT menu,
* or NULL if none currently open. */
struct form_control *visible_select_menu;
 
/** Selection state */
struct selection sel;
 
/** Context for free text search, or NULL if none */
struct search_context *search;
 
} html_content;
 
 
bool html_fetch_object(html_content *c, nsurl *url, struct box *box,
content_type permitted_types,
int available_width, int available_height,
bool background);
 
void html_set_status(html_content *c, const char *extra);
 
void html__redraw_a_box(html_content *html, struct box *box);
 
struct browser_window *html_get_browser_window(struct content *c);
struct search_context *html_get_search(struct content *c);
void html_set_search(struct content *c, struct search_context *s);
 
/**
* Complete conversion of an HTML document
*
* \param htmlc Content to convert
*/
void html_finish_conversion(html_content *htmlc);
 
/**
* Begin conversion of an HTML document
*
* \param htmlc Content to convert
*/
bool html_begin_conversion(html_content *htmlc);
 
/* in render/html_redraw.c */
bool html_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx);
 
/* in render/html_interaction.c */
void html_mouse_track(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
void html_mouse_action(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
void html_overflow_scroll_callback(void *client_data,
struct scrollbar_msg_data *scrollbar_data);
 
 
/* in render/html_script.c */
dom_hubbub_error html_process_script(void *ctx, dom_node *node);
void html_free_scripts(html_content *html);
bool html_scripts_exec(html_content *c);
 
/* in render/html_forms.c */
struct form *html_forms_get_forms(const char *docenc, dom_html_document *doc);
struct form_control *html_forms_get_control_for_node(struct form *forms, dom_node *node);
 
/* Useful dom_string pointers */
struct dom_string;
 
extern struct dom_string *html_dom_string_map;
extern struct dom_string *html_dom_string_id;
extern struct dom_string *html_dom_string_name;
extern struct dom_string *html_dom_string_area;
extern struct dom_string *html_dom_string_a;
extern struct dom_string *html_dom_string_nohref;
extern struct dom_string *html_dom_string_href;
extern struct dom_string *html_dom_string_target;
extern struct dom_string *html_dom_string_shape;
extern struct dom_string *html_dom_string_default;
extern struct dom_string *html_dom_string_rect;
extern struct dom_string *html_dom_string_rectangle;
extern struct dom_string *html_dom_string_coords;
extern struct dom_string *html_dom_string_circle;
extern struct dom_string *html_dom_string_poly;
extern struct dom_string *html_dom_string_polygon;
extern struct dom_string *html_dom_string_text_javascript;
extern struct dom_string *html_dom_string_type;
extern struct dom_string *html_dom_string_src;
 
#endif
 
 
/programs/network/netsurf/netsurf/render/html_redraw.c
0,0 → 1,2537
/*
* Copyright 2004-2008 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004-2007 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2004-2007 Richard Wilson <info@tinct.net>
* Copyright 2005-2006 Adrian Lees <adrianl@users.sourceforge.net>
* Copyright 2006 Rob Kendrick <rjek@netsurf-browser.org>
* Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
* Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Redraw of a CONTENT_HTML (implementation).
*/
 
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <dom/dom.h>
#include "utils/config.h"
#include "content/content_protected.h"
#include "css/css.h"
#include "css/utils.h"
#include "desktop/plotters.h"
#include "desktop/selection.h"
#include "desktop/options.h"
#include "desktop/print.h"
#include "desktop/scrollbar.h"
#include "image/bitmap.h"
#include "render/box.h"
#include "render/font.h"
#include "render/form.h"
#include "render/html_internal.h"
#include "render/layout.h"
#include "render/search.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
 
 
 
 
bool html_redraw_debug = false;
 
/**
* Determine if a box has a background that needs drawing
*
* \param box Box to consider
* \return True if box has a background, false otherwise.
*/
static bool html_redraw_box_has_background(struct box *box)
{
if (box->background != NULL)
return true;
 
if (box->style != NULL) {
css_color colour;
 
css_computed_background_color(box->style, &colour);
 
if (nscss_color_is_transparent(colour) == false)
return true;
}
 
return false;
}
 
/**
* Find the background box for a box
*
* \param box Box to find background box for
* \return Pointer to background box, or NULL if there is none
*/
static struct box *html_redraw_find_bg_box(struct box *box)
{
/* Thanks to backwards compatibility, CSS defines the following:
*
* + If the box is for the root element and it has a background,
* use that (and then process the body box with no special case)
* + If the box is for the root element and it has no background,
* then use the background (if any) from the body element as if
* it were specified on the root. Then, when the box for the body
* element is processed, ignore the background.
* + For any other box, just use its own styling.
*/
if (box->parent == NULL) {
/* Root box */
if (html_redraw_box_has_background(box))
return box;
 
/* No background on root box: consider body box, if any */
if (box->children != NULL) {
if (html_redraw_box_has_background(box->children))
return box->children;
}
} else if (box->parent != NULL && box->parent->parent == NULL) {
/* Body box: only render background if root has its own */
if (html_redraw_box_has_background(box) &&
html_redraw_box_has_background(box->parent))
return box;
} else {
/* Any other box */
if (html_redraw_box_has_background(box))
return box;
}
 
return NULL;
}
 
/**
* Redraw a short text string, complete with highlighting
* (for selection/search)
*
* \param utf8_text pointer to UTF-8 text string
* \param utf8_len length of string, in bytes
* \param offset byte offset within textual representation
* \param space width of space that follows string (0 = no space)
* \param fstyle text style to use (pass text size unscaled)
* \param x x ordinate at which to plot text
* \param y y ordinate at which to plot text
* \param clip pointer to current clip rectangle
* \param height height of text string
* \param scale current display scale (1.0 = 100%)
* \param excluded exclude this text string from the selection
* \param ctx current redraw context
* \return true iff successful and redraw should proceed
*/
 
bool text_redraw(const char *utf8_text, size_t utf8_len,
size_t offset, int space, const plot_font_style_t *fstyle,
int x, int y, const struct rect *clip, int height,
float scale, bool excluded, struct content *c,
const struct selection *sel, struct search_context *search,
const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
bool highlighted = false;
plot_font_style_t plot_fstyle = *fstyle;
 
/* Need scaled text size to pass to plotters */
plot_fstyle.size *= scale;
 
/* is this box part of a selection? */
if (!excluded && ctx->interactive == true) {
unsigned len = utf8_len + (space ? 1 : 0);
unsigned start_idx;
unsigned end_idx;
 
/* first try the browser window's current selection */
if (selection_defined(sel) && selection_highlighted(sel,
offset, offset + len,
&start_idx, &end_idx)) {
highlighted = true;
}
 
/* what about the current search operation, if any? */
if (!highlighted && (search != NULL) &&
search_term_highlighted(c,
offset, offset + len,
&start_idx, &end_idx,
search)) {
highlighted = true;
}
 
/* \todo make search terms visible within selected text */
if (highlighted) {
struct rect r;
unsigned endtxt_idx = end_idx;
bool clip_changed = false;
bool text_visible = true;
int startx, endx;
plot_style_t *pstyle_fill_hback = plot_style_fill_white;
plot_font_style_t fstyle_hback = plot_fstyle;
 
if (end_idx > utf8_len) {
/* adjust for trailing space, not present in
* utf8_text */
assert(end_idx == utf8_len + 1);
endtxt_idx = utf8_len;
}
 
if (!nsfont.font_width(fstyle, utf8_text, start_idx,
&startx))
startx = 0;
 
if (!nsfont.font_width(fstyle, utf8_text, endtxt_idx,
&endx))
endx = 0;
 
/* is there a trailing space that should be highlighted
* as well? */
if (end_idx > utf8_len) {
endx += space;
}
 
if (scale != 1.0) {
startx *= scale;
endx *= scale;
}
 
/* draw any text preceding highlighted portion */
if (start_idx > 0 &&
!plot->text(x, y + (int)(height * 0.75 * scale),
utf8_text, start_idx,
&plot_fstyle))
return false;
 
/* decide whether highlighted portion is to be
* white-on-black or black-on-white */
if ((fstyle->background & 0x808080) == 0x808080)
pstyle_fill_hback = plot_style_fill_black;
 
/* highlighted portion */
if (!plot->rectangle(x + startx, y, x + endx,
y + height * scale,
pstyle_fill_hback))
return false;
 
if (start_idx > 0) {
int px0 = max(x + startx, clip->x0);
int px1 = min(x + endx, clip->x1);
 
if (px0 < px1) {
r.x0 = px0;
r.y0 = clip->y0;
r.x1 = px1;
r.y1 = clip->y1;
if (!plot->clip(&r))
return false;
clip_changed = true;
} else {
text_visible = false;
}
}
 
fstyle_hback.background =
pstyle_fill_hback->fill_colour;
fstyle_hback.foreground =
pstyle_fill_hback->fill_colour ^ 0xffffff;
 
if (text_visible &&
!plot->text(x, y + (int)(height * 0.75 * scale),
utf8_text, endtxt_idx,
&fstyle_hback))
return false;
 
/* draw any text succeeding highlighted portion */
if (endtxt_idx < utf8_len) {
int px0 = max(x + endx, clip->x0);
if (px0 < clip->x1) {
 
r.x0 = px0;
r.y0 = clip->y0;
r.x1 = clip->x1;
r.y1 = clip->y1;
if (!plot->clip(&r))
return false;
 
clip_changed = true;
 
if (!plot->text(x, y + (int)
(height * 0.75 * scale),
utf8_text, utf8_len,
&plot_fstyle))
return false;
}
}
 
if (clip_changed &&
!plot->clip(clip))
return false;
}
}
 
if (!highlighted) {
if (!plot->text(x, y + (int) (height * 0.75 * scale),
utf8_text, utf8_len,
&plot_fstyle))
return false;
}
return true;
}
 
static plot_style_t plot_style_bdr = {
.stroke_type = PLOT_OP_TYPE_DASH,
};
static plot_style_t plot_style_fillbdr = {
.fill_type = PLOT_OP_TYPE_SOLID,
};
static plot_style_t plot_style_fillbdr_dark = {
.fill_type = PLOT_OP_TYPE_SOLID,
};
static plot_style_t plot_style_fillbdr_light = {
.fill_type = PLOT_OP_TYPE_SOLID,
};
static plot_style_t plot_style_fillbdr_ddark = {
.fill_type = PLOT_OP_TYPE_SOLID,
};
static plot_style_t plot_style_fillbdr_dlight = {
.fill_type = PLOT_OP_TYPE_SOLID,
};
 
/**
* Draw one border.
*
* \param side index of border side (TOP, RIGHT, BOTTOM, LEFT)
* \param p array of precomputed border vertices
* \param c colour for border
* \param style border line style
* \param thickness border thickness
* \param rectangular whether border is rectangular
* \param ctx current redraw context
* \return true if successful, false otherwise
*/
 
static bool html_redraw_border_plot(const int side, const int *p, colour c,
enum css_border_style_e style, int thickness, bool rectangular,
const struct rect *clip, const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
int z[8]; /* Vertices of border part */
unsigned int light = side;
plot_style_t *plot_style_bdr_in;
plot_style_t *plot_style_bdr_out;
 
if (c == NS_TRANSPARENT)
return true;
 
plot_style_bdr.stroke_type = PLOT_OP_TYPE_DASH;
plot_style_bdr.stroke_colour = c;
plot_style_bdr.stroke_width = thickness;
plot_style_fillbdr.fill_colour = c;
plot_style_fillbdr_dark.fill_colour = darken_colour(c);
plot_style_fillbdr_light.fill_colour = lighten_colour(c);
plot_style_fillbdr_ddark.fill_colour = double_darken_colour(c);
plot_style_fillbdr_dlight.fill_colour = double_lighten_colour(c);
 
switch (style) {
case CSS_BORDER_STYLE_DOTTED:
plot_style_bdr.stroke_type = PLOT_OP_TYPE_DOT;
/* fall through */
case CSS_BORDER_STYLE_DASHED:
if (!plot->line((p[0] + p[2]) / 2,
(p[1] + p[3]) / 2,
(p[4] + p[6]) / 2,
(p[5] + p[7]) / 2,
&plot_style_bdr))
return false;
break;
 
case CSS_BORDER_STYLE_SOLID:
/* fall through to default */
default:
if (rectangular || thickness == 1) {
int x0, y0, x1, y1;
if (side == TOP || side == RIGHT) {
x0 = p[2]; y0 = p[3];
x1 = p[6]; y1 = p[7];
x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
x1 + p[4] - p[6] : x1;
} else {
x0 = p[6]; y0 = p[7];
x1 = p[2]; y1 = p[3];
y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
y1 + p[1] - p[3] : y1;
}
/* find intersection of clip rectangle and border */
x0 = (clip->x0 > x0) ? clip->x0 : x0;
y0 = (clip->y0 > y0) ? clip->y0 : y0;
x1 = (clip->x1 < x1) ? clip->x1 : x1;
y1 = (clip->y1 < y1) ? clip->y1 : y1;
if ((x0 < x1) && (y0 < y1)) {
/* valid clip rectangles only */
if (!plot->rectangle(x0, y0, x1, y1,
&plot_style_fillbdr))
return false;
}
} else {
if (!plot->polygon(p, 4, &plot_style_fillbdr))
return false;
}
break;
 
case CSS_BORDER_STYLE_DOUBLE:
z[0] = p[0];
z[1] = p[1];
z[2] = (p[0] * 2 + p[2]) / 3;
z[3] = (p[1] * 2 + p[3]) / 3;
z[4] = (p[6] * 2 + p[4]) / 3;
z[5] = (p[7] * 2 + p[5]) / 3;
z[6] = p[6];
z[7] = p[7];
if (!plot->polygon(z, 4, &plot_style_fillbdr))
return false;
z[0] = p[2];
z[1] = p[3];
z[2] = (p[2] * 2 + p[0]) / 3;
z[3] = (p[3] * 2 + p[1]) / 3;
z[4] = (p[4] * 2 + p[6]) / 3;
z[5] = (p[5] * 2 + p[7]) / 3;
z[6] = p[4];
z[7] = p[5];
if (!plot->polygon(z, 4, &plot_style_fillbdr))
return false;
break;
 
case CSS_BORDER_STYLE_GROOVE:
light = 3 - light;
/* fall through */
case CSS_BORDER_STYLE_RIDGE:
/* choose correct colours for each part of the border line */
if (light <= 1) {
plot_style_bdr_in = &plot_style_fillbdr_dark;
plot_style_bdr_out = &plot_style_fillbdr_light;
} else {
plot_style_bdr_in = &plot_style_fillbdr_light;
plot_style_bdr_out = &plot_style_fillbdr_dark;
}
 
/* Render border */
if ((rectangular || thickness == 2) && thickness != 1) {
/* Border made up from two parts and can be plotted
* with rectangles */
int x0, y0, x1, y1;
 
/* First part */
if (side == TOP || side == RIGHT) {
x0 = (p[0] + p[2]) / 2; y0 = (p[1] + p[3]) / 2;
x1 = p[6]; y1 = p[7];
} else {
x0 = p[6]; y0 = p[7];
x1 = (p[0] + p[2]) / 2; y1 = (p[1] + p[3]) / 2;
}
/* find intersection of clip rectangle and border */
x0 = (clip->x0 > x0) ? clip->x0 : x0;
y0 = (clip->y0 > y0) ? clip->y0 : y0;
x1 = (clip->x1 < x1) ? clip->x1 : x1;
y1 = (clip->y1 < y1) ? clip->y1 : y1;
if ((x0 < x1) && (y0 < y1)) {
/* valid clip rectangles only */
if (!plot->rectangle(x0, y0, x1, y1,
plot_style_bdr_in))
return false;
}
 
/* Second part */
if (side == TOP || side == RIGHT) {
x0 = p[2]; y0 = p[3];
x1 = (p[6] + p[4]) / 2; y1 = (p[7] + p[5]) / 2;
} else {
x0 = (p[6] + p[4]) / 2; y0 = (p[7] + p[5]) / 2;
x1 = p[2]; y1 = p[3];
}
/* find intersection of clip rectangle and border */
x0 = (clip->x0 > x0) ? clip->x0 : x0;
y0 = (clip->y0 > y0) ? clip->y0 : y0;
x1 = (clip->x1 < x1) ? clip->x1 : x1;
y1 = (clip->y1 < y1) ? clip->y1 : y1;
if ((x0 < x1) && (y0 < y1)) {
/* valid clip rectangles only */
if (!plot->rectangle(x0, y0, x1, y1,
plot_style_bdr_out))
return false;
}
} else if (thickness == 1) {
/* Border made up from one part which can be plotted
* as a rectangle */
int x0, y0, x1, y1;
if (side == TOP || side == RIGHT) {
x0 = p[2]; y0 = p[3];
x1 = p[6]; y1 = p[7];
x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
x1 + p[4] - p[6] : x1;
/* find intersection of clip rectangle and
* border */
x0 = (clip->x0 > x0) ? clip->x0 : x0;
y0 = (clip->y0 > y0) ? clip->y0 : y0;
x1 = (clip->x1 < x1) ? clip->x1 : x1;
y1 = (clip->y1 < y1) ? clip->y1 : y1;
if ((x0 < x1) && (y0 < y1)) {
/* valid clip rectangles only */
if (!plot->rectangle(x0, y0, x1, y1,
plot_style_bdr_in))
return false;
}
} else {
x0 = p[6]; y0 = p[7];
x1 = p[2]; y1 = p[3];
y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
y1 + p[1] - p[3] : y1;
/* find intersection of clip rectangle and
* border */
x0 = (clip->x0 > x0) ? clip->x0 : x0;
y0 = (clip->y0 > y0) ? clip->y0 : y0;
x1 = (clip->x1 < x1) ? clip->x1 : x1;
y1 = (clip->y1 < y1) ? clip->y1 : y1;
if ((x0 < x1) && (y0 < y1)) {
/* valid clip rectangles only */
if (!plot->rectangle(x0, y0, x1, y1,
plot_style_bdr_out))
return false;
}
}
} else {
/* Border made up from two parts and can't be plotted
* with rectangles */
z[0] = p[0];
z[1] = p[1];
z[2] = (p[0] + p[2]) / 2;
z[3] = (p[1] + p[3]) / 2;
z[4] = (p[6] + p[4]) / 2;
z[5] = (p[7] + p[5]) / 2;
z[6] = p[6];
z[7] = p[7];
if (!plot->polygon(z, 4, plot_style_bdr_in))
return false;
z[0] = p[2];
z[1] = p[3];
z[6] = p[4];
z[7] = p[5];
if (!plot->polygon(z, 4, plot_style_bdr_out))
return false;
}
break;
 
case CSS_BORDER_STYLE_INSET:
light = (light + 2) % 4;
/* fall through */
case CSS_BORDER_STYLE_OUTSET:
/* choose correct colours for each part of the border line */
switch (light) {
case 0:
plot_style_bdr_in = &plot_style_fillbdr_light;
plot_style_bdr_out = &plot_style_fillbdr_dlight;
break;
case 1:
plot_style_bdr_in = &plot_style_fillbdr_ddark;
plot_style_bdr_out = &plot_style_fillbdr_dark;
break;
case 2:
plot_style_bdr_in = &plot_style_fillbdr_dark;
plot_style_bdr_out = &plot_style_fillbdr_ddark;
break;
case 3:
plot_style_bdr_in = &plot_style_fillbdr_dlight;
plot_style_bdr_out = &plot_style_fillbdr_light;
break;
default:
plot_style_bdr_in = &plot_style_fillbdr;
plot_style_bdr_out = &plot_style_fillbdr;
break;
}
 
/* Render border */
if ((rectangular || thickness == 2) && thickness != 1) {
/* Border made up from two parts and can be plotted
* with rectangles */
int x0, y0, x1, y1;
 
/* First part */
if (side == TOP || side == RIGHT) {
x0 = (p[0] + p[2]) / 2; y0 = (p[1] + p[3]) / 2;
x1 = p[6]; y1 = p[7];
} else {
x0 = p[6]; y0 = p[7];
x1 = (p[0] + p[2]) / 2; y1 = (p[1] + p[3]) / 2;
}
/* find intersection of clip rectangle and border */
x0 = (clip->x0 > x0) ? clip->x0 : x0;
y0 = (clip->y0 > y0) ? clip->y0 : y0;
x1 = (clip->x1 < x1) ? clip->x1 : x1;
y1 = (clip->y1 < y1) ? clip->y1 : y1;
if ((x0 < x1) && (y0 < y1)) {
/* valid clip rectangles only */
if (!plot->rectangle(x0, y0, x1, y1,
plot_style_bdr_in))
return false;
}
 
/* Second part */
if (side == TOP || side == RIGHT) {
x0 = p[2]; y0 = p[3];
x1 = (p[6] + p[4]) / 2; y1 = (p[7] + p[5]) / 2;
} else {
x0 = (p[6] + p[4]) / 2; y0 = (p[7] + p[5]) / 2;
x1 = p[2]; y1 = p[3];
}
/* find intersection of clip rectangle and border */
x0 = (clip->x0 > x0) ? clip->x0 : x0;
y0 = (clip->y0 > y0) ? clip->y0 : y0;
x1 = (clip->x1 < x1) ? clip->x1 : x1;
y1 = (clip->y1 < y1) ? clip->y1 : y1;
if ((x0 < x1) && (y0 < y1)) {
/* valid clip rectangles only */
if (!plot->rectangle(x0, y0, x1, y1,
plot_style_bdr_out))
return false;
}
} else if (thickness == 1) {
/* Border made up from one part which can be plotted
* as a rectangle */
int x0, y0, x1, y1;
if (side == TOP || side == RIGHT) {
x0 = p[2]; y0 = p[3];
x1 = p[6]; y1 = p[7];
x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
x1 + p[4] - p[6] : x1;
/* find intersection of clip rectangle and
* border */
x0 = (clip->x0 > x0) ? clip->x0 : x0;
y0 = (clip->y0 > y0) ? clip->y0 : y0;
x1 = (clip->x1 < x1) ? clip->x1 : x1;
y1 = (clip->y1 < y1) ? clip->y1 : y1;
if ((x0 < x1) && (y0 < y1)) {
/* valid clip rectangles only */
if (!plot->rectangle(x0, y0, x1, y1,
plot_style_bdr_in))
return false;
}
} else {
x0 = p[6]; y0 = p[7];
x1 = p[2]; y1 = p[3];
y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
y1 + p[1] - p[3] : y1;
/* find intersection of clip rectangle and
* border */
x0 = (clip->x0 > x0) ? clip->x0 : x0;
y0 = (clip->y0 > y0) ? clip->y0 : y0;
x1 = (clip->x1 < x1) ? clip->x1 : x1;
y1 = (clip->y1 < y1) ? clip->y1 : y1;
if ((x0 < x1) && (y0 < y1)) {
/* valid clip rectangles only */
if (!plot->rectangle(x0, y0, x1, y1,
plot_style_bdr_out))
return false;
}
}
} else {
/* Border made up from two parts and can't be plotted
* with rectangles */
z[0] = p[0];
z[1] = p[1];
z[2] = (p[0] + p[2]) / 2;
z[3] = (p[1] + p[3]) / 2;
z[4] = (p[6] + p[4]) / 2;
z[5] = (p[7] + p[5]) / 2;
z[6] = p[6];
z[7] = p[7];
if (!plot->polygon(z, 4, plot_style_bdr_in))
return false;
z[0] = p[2];
z[1] = p[3];
z[6] = p[4];
z[7] = p[5];
if (!plot->polygon(z, 4, plot_style_bdr_out))
return false;
}
break;
}
 
return true;
}
 
 
/**
* Draw borders for a box.
*
* \param box box to draw
* \param x_parent coordinate of left padding edge of parent of box
* \param y_parent coordinate of top padding edge of parent of box
* \param p_width width of padding box
* \param p_height height of padding box
* \param scale scale for redraw
* \param ctx current redraw context
* \return true if successful, false otherwise
*/
 
static bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
int p_width, int p_height, const struct rect *clip, float scale,
const struct redraw_context *ctx)
{
unsigned int sides[] = { LEFT, RIGHT, TOP, BOTTOM };
int top = box->border[TOP].width;
int right = box->border[RIGHT].width;
int bottom = box->border[BOTTOM].width;
int left = box->border[LEFT].width;
int x, y;
unsigned int i, side;
int p[8]; /* Box border vertices */
int z[8]; /* Border vertices */
bool square_end_1 = false;
bool square_end_2 = false;
 
x = x_parent + box->x;
y = y_parent + box->y;
 
if (scale != 1.0) {
top *= scale;
right *= scale;
bottom *= scale;
left *= scale;
x *= scale;
y *= scale;
}
 
assert(box->style);
 
/* Calculate border vertices
*
* A----------------------+
* | \ / |
* | B--------------+ |
* | | | |
* | +--------------C |
* | / \ |
* +----------------------D
*/
p[0] = x - left; p[1] = y - top; /* A */
p[2] = x; p[3] = y; /* B */
p[4] = x + p_width; p[5] = y + p_height; /* C */
p[6] = x + p_width + right; p[7] = y + p_height + bottom; /* D */
 
for (i = 0; i != 4; i++) {
colour col = 0;
side = sides[i]; /* plot order */
 
if (box->border[side].width == 0 ||
nscss_color_is_transparent(box->border[side].c))
continue;
 
switch (side) {
case LEFT:
square_end_1 = (top == 0);
square_end_2 = (bottom == 0);
 
z[0] = p[0]; z[1] = p[7];
z[2] = p[2]; z[3] = p[5];
z[4] = p[2]; z[5] = p[3];
z[6] = p[0]; z[7] = p[1];
 
if (nscss_color_is_transparent(box->border[TOP].c) ==
false &&
box->border[TOP].style !=
CSS_BORDER_STYLE_DOUBLE) {
/* make border overhang top corner fully,
* if top border is opaque */
z[5] -= top;
square_end_1 = true;
}
if (nscss_color_is_transparent(box->border[BOTTOM].c) ==
false &&
box->border[BOTTOM].style !=
CSS_BORDER_STYLE_DOUBLE) {
/* make border overhang bottom corner fully,
* if bottom border is opaque */
z[3] += bottom;
square_end_2 = true;
}
 
col = nscss_color_to_ns(box->border[side].c);
 
if (!html_redraw_border_plot(side, z, col,
box->border[side].style,
box->border[side].width * scale,
square_end_1 && square_end_2,
clip, ctx))
return false;
break;
case RIGHT:
square_end_1 = (top == 0);
square_end_2 = (bottom == 0);
 
z[0] = p[6]; z[1] = p[1];
z[2] = p[4]; z[3] = p[3];
z[4] = p[4]; z[5] = p[5];
z[6] = p[6]; z[7] = p[7];
 
if (nscss_color_is_transparent(box->border[TOP].c) ==
false &&
box->border[TOP].style !=
CSS_BORDER_STYLE_DOUBLE) {
/* make border overhang top corner fully,
* if top border is opaque */
z[3] -= top;
square_end_1 = true;
}
if (nscss_color_is_transparent(box->border[BOTTOM].c) ==
false &&
box->border[BOTTOM].style !=
CSS_BORDER_STYLE_DOUBLE) {
/* make border overhang bottom corner fully,
* if bottom border is opaque */
z[5] += bottom;
square_end_2 = true;
}
 
col = nscss_color_to_ns(box->border[side].c);
 
if (!html_redraw_border_plot(side, z, col,
box->border[side].style,
box->border[side].width * scale,
square_end_1 && square_end_2,
clip, ctx))
return false;
break;
case TOP:
if (clip->y0 > p[3])
/* clip rectangle is below border; nothing to
* plot */
continue;
 
square_end_1 = (left == 0);
square_end_2 = (right == 0);
 
z[0] = p[2]; z[1] = p[3];
z[2] = p[0]; z[3] = p[1];
z[4] = p[6]; z[5] = p[1];
z[6] = p[4]; z[7] = p[3];
 
if (box->border[TOP].style ==
CSS_BORDER_STYLE_SOLID &&
box->border[TOP].c ==
box->border[LEFT].c) {
/* don't bother overlapping left corner if
* it's the same colour anyway */
z[2] += left;
square_end_1 = true;
}
if (box->border[TOP].style ==
CSS_BORDER_STYLE_SOLID &&
box->border[TOP].c ==
box->border[RIGHT].c) {
/* don't bother overlapping right corner if
* it's the same colour anyway */
z[4] -= right;
square_end_2 = true;
}
 
col = nscss_color_to_ns(box->border[side].c);
 
if (!html_redraw_border_plot(side, z, col,
box->border[side].style,
box->border[side].width * scale,
square_end_1 && square_end_2,
clip, ctx))
return false;
break;
case BOTTOM:
if (clip->y1 < p[5])
/* clip rectangle is above border; nothing to
* plot */
continue;
 
square_end_1 = (left == 0);
square_end_2 = (right == 0);
 
z[0] = p[4]; z[1] = p[5];
z[2] = p[6]; z[3] = p[7];
z[4] = p[0]; z[5] = p[7];
z[6] = p[2]; z[7] = p[5];
 
if (box->border[BOTTOM].style ==
CSS_BORDER_STYLE_SOLID &&
box->border[BOTTOM].c ==
box->border[LEFT].c) {
/* don't bother overlapping left corner if
* it's the same colour anyway */
z[4] += left;
square_end_1 = true;
}
if (box->border[BOTTOM].style ==
CSS_BORDER_STYLE_SOLID &&
box->border[BOTTOM].c ==
box->border[RIGHT].c) {
/* don't bother overlapping right corner if
* it's the same colour anyway */
z[2] -= right;
square_end_2 = true;
}
 
col = nscss_color_to_ns(box->border[side].c);
 
if (!html_redraw_border_plot(side, z, col,
box->border[side].style,
box->border[side].width * scale,
square_end_1 && square_end_2,
clip, ctx))
return false;
break;
default:
assert(side == TOP || side == BOTTOM ||
side == LEFT || side == RIGHT);
break;
}
}
 
return true;
}
 
 
/**
* Draw an inline's borders.
*
* \param box BOX_INLINE which created the border
* \param b coordinates of border edge rectangle
* \param scale scale for redraw
* \param first true if this is the first rectangle associated with the inline
* \param last true if this is the last rectangle associated with the inline
* \param ctx current redraw context
* \return true if successful, false otherwise
*/
 
static bool html_redraw_inline_borders(struct box *box, struct rect b,
const struct rect *clip, float scale, bool first, bool last,
const struct redraw_context *ctx)
{
int top = box->border[TOP].width;
int right = box->border[RIGHT].width;
int bottom = box->border[BOTTOM].width;
int left = box->border[LEFT].width;
colour col;
int p[8]; /* Box border vertices */
int z[8]; /* Border vertices */
bool square_end_1;
bool square_end_2;
 
if (scale != 1.0) {
top *= scale;
right *= scale;
bottom *= scale;
left *= scale;
}
 
/* Calculate border vertices
*
* A----------------------+
* | \ / |
* | B--------------+ |
* | | | |
* | +--------------C |
* | / \ |
* +----------------------D
*/
p[0] = b.x0; p[1] = b.y0; /* A */
p[2] = first ? b.x0 + left : b.x0; p[3] = b.y0 + top; /* B */
p[4] = last ? b.x1 - right : b.x1; p[5] = b.y1 - bottom; /* C */
p[6] = b.x1; p[7] = b.y1; /* D */
 
assert(box->style);
 
/* Left */
square_end_1 = (top == 0);
square_end_2 = (bottom == 0);
if (left != 0 && first && nscss_color_is_transparent(
box->border[LEFT].c) == false) {
col = nscss_color_to_ns(box->border[LEFT].c);
 
z[0] = p[0]; z[1] = p[7];
z[2] = p[2]; z[3] = p[5];
z[4] = p[2]; z[5] = p[3];
z[6] = p[0]; z[7] = p[1];
 
if (nscss_color_is_transparent(box->border[TOP].c) == false &&
box->border[TOP].style !=
CSS_BORDER_STYLE_DOUBLE) {
/* make border overhang top corner fully,
* if top border is opaque */
z[5] -= top;
square_end_1 = true;
}
 
if (nscss_color_is_transparent(box->border[BOTTOM].c) ==
false &&
box->border[BOTTOM].style !=
CSS_BORDER_STYLE_DOUBLE) {
/* make border overhang bottom corner fully,
* if bottom border is opaque */
z[3] += bottom;
square_end_2 = true;
}
 
if (!html_redraw_border_plot(LEFT, z, col,
box->border[LEFT].style,
left, square_end_1 && square_end_2,
clip, ctx))
return false;
}
 
/* Right */
square_end_1 = (top == 0);
square_end_2 = (bottom == 0);
if (right != 0 && last && nscss_color_is_transparent(
box->border[RIGHT].c) == false) {
col = nscss_color_to_ns(box->border[RIGHT].c);
 
z[0] = p[6]; z[1] = p[1];
z[2] = p[4]; z[3] = p[3];
z[4] = p[4]; z[5] = p[5];
z[6] = p[6]; z[7] = p[7];
 
if (nscss_color_is_transparent(box->border[TOP].c) == false &&
box->border[TOP].style !=
CSS_BORDER_STYLE_DOUBLE) {
/* make border overhang top corner fully,
* if top border is opaque */
z[3] -= top;
square_end_1 = true;
}
 
if (nscss_color_is_transparent(box->border[BOTTOM].c) ==
false &&
box->border[BOTTOM].style !=
CSS_BORDER_STYLE_DOUBLE) {
/* make border overhang bottom corner fully,
* if bottom border is opaque */
z[5] += bottom;
square_end_2 = true;
}
 
if (!html_redraw_border_plot(RIGHT, z, col,
box->border[RIGHT].style,
right, square_end_1 && square_end_2,
clip, ctx))
return false;
}
 
/* Top */
square_end_1 = (left == 0);
square_end_2 = (right == 0);
if (top != 0 && nscss_color_is_transparent(
box->border[TOP].c) == false) {
col = nscss_color_to_ns(box->border[TOP].c);
 
z[0] = p[2]; z[1] = p[3];
z[2] = p[0]; z[3] = p[1];
z[4] = p[6]; z[5] = p[1];
z[6] = p[4]; z[7] = p[3];
 
if (first && box->border[TOP].style ==
CSS_BORDER_STYLE_SOLID &&
box->border[TOP].c ==
box->border[LEFT].c) {
/* don't bother overlapping left corner if
* it's the same colour anyway */
z[2] += left;
square_end_1 = true;
}
 
if (last && box->border[TOP].style ==
CSS_BORDER_STYLE_SOLID &&
box->border[TOP].c ==
box->border[RIGHT].c) {
/* don't bother overlapping right corner if
* it's the same colour anyway */
z[4] -= right;
square_end_2 = true;
}
 
if (!html_redraw_border_plot(TOP, z, col,
box->border[TOP].style,
top, square_end_1 && square_end_2,
clip, ctx))
return false;
}
 
/* Bottom */
square_end_1 = (left == 0);
square_end_2 = (right == 0);
if (bottom != 0 && nscss_color_is_transparent(
box->border[BOTTOM].c) == false) {
col = nscss_color_to_ns(box->border[BOTTOM].c);
 
z[0] = p[4]; z[1] = p[5];
z[2] = p[6]; z[3] = p[7];
z[4] = p[0]; z[5] = p[7];
z[6] = p[2]; z[7] = p[5];
 
if (first && box->border[BOTTOM].style ==
CSS_BORDER_STYLE_SOLID &&
box->border[BOTTOM].c ==
box->border[LEFT].c) {
/* don't bother overlapping left corner if
* it's the same colour anyway */
z[4] += left;
square_end_1 = true;
}
 
if (last && box->border[BOTTOM].style ==
CSS_BORDER_STYLE_SOLID &&
box->border[BOTTOM].c ==
box->border[RIGHT].c) {
/* don't bother overlapping right corner if
* it's the same colour anyway */
z[2] -= right;
square_end_2 = true;
}
 
if (!html_redraw_border_plot(BOTTOM, z, col,
box->border[BOTTOM].style,
bottom, square_end_1 && square_end_2,
clip, ctx))
return false;
}
 
return true;
}
 
 
/**
* Plot a checkbox.
*
* \param x left coordinate
* \param y top coordinate
* \param width dimensions of checkbox
* \param height dimensions of checkbox
* \param selected the checkbox is selected
* \param ctx current redraw context
* \return true if successful, false otherwise
*/
 
static bool html_redraw_checkbox(int x, int y, int width, int height,
bool selected, const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
double z = width * 0.15;
if (z == 0)
z = 1;
 
if (!(plot->rectangle(x, y, x + width, y + height,
plot_style_fill_wbasec) &&
plot->line(x, y, x + width, y, plot_style_stroke_darkwbasec) &&
plot->line(x, y, x, y + height, plot_style_stroke_darkwbasec) &&
plot->line(x + width, y, x + width, y + height,
plot_style_stroke_lightwbasec) &&
plot->line(x, y + height, x + width, y + height,
plot_style_stroke_lightwbasec)))
return false;
 
if (selected) {
if (width < 12 || height < 12) {
/* render a solid box instead of a tick */
if (!plot->rectangle(x + z + z, y + z + z,
x + width - z, y + height - z,
plot_style_fill_wblobc))
return false;
} else {
/* render a tick, as it'll fit comfortably */
if (!(plot->line(x + width - z,
y + z,
x + (z * 3),
y + height - z,
plot_style_stroke_wblobc) &&
 
plot->line(x + (z * 3),
y + height - z,
x + z + z,
y + (height / 2),
plot_style_stroke_wblobc)))
return false;
}
}
return true;
}
 
 
/**
* Plot a radio icon.
*
* \param x left coordinate
* \param y top coordinate
* \param width dimensions of radio icon
* \param height dimensions of radio icon
* \param selected the radio icon is selected
* \param ctx current redraw context
* \return true if successful, false otherwise
*/
static bool html_redraw_radio(int x, int y, int width, int height,
bool selected, const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
 
/* plot background of radio button */
if (!plot->disc(x + width * 0.5,
y + height * 0.5,
width * 0.5 - 1,
plot_style_fill_wbasec))
return false;
 
/* plot dark arc */
if (!plot->arc(x + width * 0.5,
y + height * 0.5,
width * 0.5 - 1,
45,
225,
plot_style_fill_darkwbasec))
return false;
 
/* plot light arc */
if (!plot->arc(x + width * 0.5,
y + height * 0.5,
width * 0.5 - 1,
225,
45,
plot_style_fill_lightwbasec))
return false;
 
if (selected) {
/* plot selection blob */
if (!plot->disc(x + width * 0.5,
y + height * 0.5,
width * 0.3 - 1,
plot_style_fill_wblobc))
return false;
}
 
return true;
}
 
 
/**
* Plot a file upload input.
*
* \param x left coordinate
* \param y top coordinate
* \param width dimensions of input
* \param height dimensions of input
* \param box box of input
* \param scale scale for redraw
* \param background_colour current background colour
* \param ctx current redraw context
* \return true if successful, false otherwise
*/
 
static bool html_redraw_file(int x, int y, int width, int height,
struct box *box, float scale, colour background_colour,
const struct redraw_context *ctx)
{
int text_width;
const char *text;
size_t length;
plot_font_style_t fstyle;
 
font_plot_style_from_css(box->style, &fstyle);
fstyle.background = background_colour;
 
if (box->gadget->value)
text = box->gadget->value;
else
text = messages_get("Form_Drop");
length = strlen(text);
 
if (!nsfont.font_width(&fstyle, text, length, &text_width))
return false;
text_width *= scale;
if (width < text_width + 8)
x = x + width - text_width - 4;
else
x = x + 4;
 
return ctx->plot->text(x, y + height * 0.75, text, length, &fstyle);
}
 
 
/**
* Plot background images.
*
* \param x coordinate of box
* \param y coordinate of box
* \param box box to draw background image of
* \param scale scale for redraw
* \param clip current clip rectangle
* \param background_colour current background colour
* \param background box containing background details (usually ::box)
* \param ctx current redraw context
* \return true if successful, false otherwise
*
* The reason for the presence of ::background is the backwards compatibility
* mess that is backgrounds on <body>. The background will be drawn relative
* to ::box, using the background information contained within ::background.
*/
 
static bool html_redraw_background(int x, int y, struct box *box, float scale,
const struct rect *clip, colour *background_colour,
struct box *background, const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
bool repeat_x = false;
bool repeat_y = false;
bool plot_colour = true;
bool plot_content;
bool clip_to_children = false;
struct box *clip_box = box;
int ox = x, oy = y;
int width, height;
css_fixed hpos = 0, vpos = 0;
css_unit hunit = CSS_UNIT_PX, vunit = CSS_UNIT_PX;
struct box *parent;
struct rect r = *clip;
css_color bgcol;
plot_style_t pstyle_fill_bg = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = *background_colour,
};
 
if (ctx->background_images == false)
return true;
 
plot_content = (background->background != NULL);
 
if (plot_content) {
if (!box->parent) {
/* Root element, special case:
* background origin calc. is based on margin box */
x -= box->margin[LEFT] * scale;
y -= box->margin[TOP] * scale;
width = box->margin[LEFT] + box->padding[LEFT] +
box->width + box->padding[RIGHT] +
box->margin[RIGHT];
height = box->margin[TOP] + box->padding[TOP] +
box->height + box->padding[BOTTOM] +
box->margin[BOTTOM];
} else {
width = box->padding[LEFT] + box->width +
box->padding[RIGHT];
height = box->padding[TOP] + box->height +
box->padding[BOTTOM];
}
/* handle background-repeat */
switch (css_computed_background_repeat(background->style)) {
case CSS_BACKGROUND_REPEAT_REPEAT:
repeat_x = repeat_y = true;
/* optimisation: only plot the colour if
* bitmap is not opaque */
plot_colour = !content_get_opaque(background->background);
break;
 
case CSS_BACKGROUND_REPEAT_REPEAT_X:
repeat_x = true;
break;
 
case CSS_BACKGROUND_REPEAT_REPEAT_Y:
repeat_y = true;
break;
 
case CSS_BACKGROUND_REPEAT_NO_REPEAT:
break;
 
default:
break;
}
 
/* handle background-position */
css_computed_background_position(background->style,
&hpos, &hunit, &vpos, &vunit);
if (hunit == CSS_UNIT_PCT) {
x += (width -
content_get_width(background->background)) *
scale * FIXTOFLT(hpos) / 100.;
} else {
x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit,
background->style)) * scale);
}
 
if (vunit == CSS_UNIT_PCT) {
y += (height -
content_get_height(background->background)) *
scale * FIXTOFLT(vpos) / 100.;
} else {
y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
background->style)) * scale);
}
}
 
/* special case for table rows as their background needs
* to be clipped to all the cells */
if (box->type == BOX_TABLE_ROW) {
css_fixed h = 0, v = 0;
css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
 
for (parent = box->parent;
((parent) && (parent->type != BOX_TABLE));
parent = parent->parent);
assert(parent && (parent->style));
 
css_computed_border_spacing(parent->style, &h, &hu, &v, &vu);
 
clip_to_children = (h > 0) || (v > 0);
 
if (clip_to_children)
clip_box = box->children;
}
 
for (; clip_box; clip_box = clip_box->next) {
/* clip to child boxes if needed */
if (clip_to_children) {
assert(clip_box->type == BOX_TABLE_CELL);
 
/* update clip.* to the child cell */
r.x0 = ox + (clip_box->x * scale);
r.y0 = oy + (clip_box->y * scale);
r.x1 = r.x0 + (clip_box->padding[LEFT] +
clip_box->width +
clip_box->padding[RIGHT]) * scale;
r.y1 = r.y0 + (clip_box->padding[TOP] +
clip_box->height +
clip_box->padding[BOTTOM]) * scale;
 
if (r.x0 < clip->x0) r.x0 = clip->x0;
if (r.y0 < clip->y0) r.y0 = clip->y0;
if (r.x1 > clip->x1) r.x1 = clip->x1;
if (r.y1 > clip->y1) r.y1 = clip->y1;
 
css_computed_background_color(clip_box->style, &bgcol);
 
/* <td> attributes override <tr> */
/* if the background content is opaque there
* is no need to plot underneath it.
*/
if ((r.x0 >= r.x1) ||
(r.y0 >= r.y1) ||
(nscss_color_is_transparent(bgcol) == false) ||
((clip_box->background != NULL) &&
content_get_opaque(clip_box->background)))
continue;
}
 
/* plot the background colour */
css_computed_background_color(background->style, &bgcol);
 
if (nscss_color_is_transparent(bgcol) == false) {
*background_colour = nscss_color_to_ns(bgcol);
pstyle_fill_bg.fill_colour = *background_colour;
if (plot_colour)
if (!plot->rectangle(r.x0, r.y0, r.x1, r.y1,
&pstyle_fill_bg))
return false;
}
/* and plot the image */
if (plot_content) {
width = content_get_width(background->background);
height = content_get_height(background->background);
 
/* ensure clip area only as large as required */
if (!repeat_x) {
if (r.x0 < x)
r.x0 = x;
if (r.x1 > x + width * scale)
r.x1 = x + width * scale;
}
if (!repeat_y) {
if (r.y0 < y)
r.y0 = y;
if (r.y1 > y + height * scale)
r.y1 = y + height * scale;
}
/* valid clipping rectangles only */
if ((r.x0 < r.x1) && (r.y0 < r.y1)) {
struct content_redraw_data bg_data;
 
if (!plot->clip(&r))
return false;
 
bg_data.x = x;
bg_data.y = y;
bg_data.width = ceilf(width * scale);
bg_data.height = ceilf(height * scale);
bg_data.background_colour = *background_colour;
bg_data.scale = scale;
bg_data.repeat_x = repeat_x;
bg_data.repeat_y = repeat_y;
 
if (!content_redraw(background->background,
&bg_data, &r, ctx))
return false;
}
}
 
/* only <tr> rows being clipped to child boxes loop */
if (!clip_to_children)
return true;
}
return true;
}
 
 
/**
* Plot an inline's background and/or background image.
*
* \param x coordinate of box
* \param y coordinate of box
* \param box BOX_INLINE which created the background
* \param scale scale for redraw
* \param clip coordinates of clip rectangle
* \param b coordinates of border edge rectangle
* \param first true if this is the first rectangle associated with the inline
* \param last true if this is the last rectangle associated with the inline
* \param background_colour updated to current background colour if plotted
* \param ctx current redraw context
* \return true if successful, false otherwise
*/
 
static bool html_redraw_inline_background(int x, int y, struct box *box,
float scale, const struct rect *clip, struct rect b,
bool first, bool last, colour *background_colour,
const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
struct rect r = *clip;
bool repeat_x = false;
bool repeat_y = false;
bool plot_colour = true;
bool plot_content;
css_fixed hpos = 0, vpos = 0;
css_unit hunit = CSS_UNIT_PX, vunit = CSS_UNIT_PX;
css_color bgcol;
plot_style_t pstyle_fill_bg = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = *background_colour,
};
 
plot_content = (box->background != NULL);
 
if (html_redraw_printing && nsoption_bool(remove_backgrounds))
return true;
 
if (plot_content) {
/* handle background-repeat */
switch (css_computed_background_repeat(box->style)) {
case CSS_BACKGROUND_REPEAT_REPEAT:
repeat_x = repeat_y = true;
/* optimisation: only plot the colour if
* bitmap is not opaque
*/
plot_colour = !content_get_opaque(box->background);
break;
 
case CSS_BACKGROUND_REPEAT_REPEAT_X:
repeat_x = true;
break;
 
case CSS_BACKGROUND_REPEAT_REPEAT_Y:
repeat_y = true;
break;
 
case CSS_BACKGROUND_REPEAT_NO_REPEAT:
break;
 
default:
break;
}
 
/* handle background-position */
css_computed_background_position(box->style,
&hpos, &hunit, &vpos, &vunit);
if (hunit == CSS_UNIT_PCT) {
x += (b.x1 - b.x0 -
content_get_width(box->background) *
scale) * FIXTOFLT(hpos) / 100.;
 
if (!repeat_x && ((hpos < 2 && !first) ||
(hpos > 98 && !last))){
plot_content = false;
}
} else {
x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit,
box->style)) * scale);
}
 
if (vunit == CSS_UNIT_PCT) {
y += (b.y1 - b.y0 -
content_get_height(box->background) *
scale) * FIXTOFLT(vpos) / 100.;
} else {
y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
box->style)) * scale);
}
}
 
/* plot the background colour */
css_computed_background_color(box->style, &bgcol);
 
if (nscss_color_is_transparent(bgcol) == false) {
*background_colour = nscss_color_to_ns(bgcol);
pstyle_fill_bg.fill_colour = *background_colour;
 
if (plot_colour)
if (!plot->rectangle(r.x0, r.y0, r.x1, r.y1,
&pstyle_fill_bg))
return false;
}
/* and plot the image */
if (plot_content) {
int width = content_get_width(box->background);
int height = content_get_height(box->background);
 
if (!repeat_x) {
if (r.x0 < x)
r.x0 = x;
if (r.x1 > x + width * scale)
r.x1 = x + width * scale;
}
if (!repeat_y) {
if (r.y0 < y)
r.y0 = y;
if (r.y1 > y + height * scale)
r.y1 = y + height * scale;
}
/* valid clipping rectangles only */
if ((r.x0 < r.x1) && (r.y0 < r.y1)) {
struct content_redraw_data bg_data;
 
if (!plot->clip(&r))
return false;
 
bg_data.x = x;
bg_data.y = y;
bg_data.width = ceilf(width * scale);
bg_data.height = ceilf(height * scale);
bg_data.background_colour = *background_colour;
bg_data.scale = scale;
bg_data.repeat_x = repeat_x;
bg_data.repeat_y = repeat_y;
 
if (!content_redraw(box->background, &bg_data, &r, ctx))
return false;
}
}
 
return true;
}
 
 
/**
* Plot text decoration for an inline box.
*
* \param box box to plot decorations for, of type BOX_INLINE
* \param x x coordinate of parent of box
* \param y y coordinate of parent of box
* \param scale scale for redraw
* \param colour colour for decorations
* \param ratio position of line as a ratio of line height
* \param ctx current redraw context
* \return true if successful, false otherwise
*/
 
static bool html_redraw_text_decoration_inline(struct box *box, int x, int y,
float scale, colour colour, float ratio,
const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
struct box *c;
plot_style_t plot_style_box = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = colour,
};
 
for (c = box->next;
c && c != box->inline_end;
c = c->next) {
if (c->type != BOX_TEXT)
continue;
if (!plot->line((x + c->x) * scale,
(y + c->y + c->height * ratio) * scale,
(x + c->x + c->width) * scale,
(y + c->y + c->height * ratio) * scale,
&plot_style_box))
return false;
}
return true;
}
 
 
/**
* Plot text decoration for an non-inline box.
*
* \param box box to plot decorations for, of type other than BOX_INLINE
* \param x x coordinate of box
* \param y y coordinate of box
* \param scale scale for redraw
* \param colour colour for decorations
* \param ratio position of line as a ratio of line height
* \param ctx current redraw context
* \return true if successful, false otherwise
*/
 
static bool html_redraw_text_decoration_block(struct box *box, int x, int y,
float scale, colour colour, float ratio,
const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
struct box *c;
plot_style_t plot_style_box = {
.stroke_type = PLOT_OP_TYPE_SOLID,
.stroke_colour = colour,
};
 
/* draw through text descendants */
for (c = box->children; c; c = c->next) {
if (c->type == BOX_TEXT) {
if (!plot->line((x + c->x) * scale,
(y + c->y + c->height * ratio) * scale,
(x + c->x + c->width) * scale,
(y + c->y + c->height * ratio) * scale,
&plot_style_box))
return false;
} else if (c->type == BOX_INLINE_CONTAINER ||
c->type == BOX_BLOCK) {
if (!html_redraw_text_decoration_block(c,
x + c->x, y + c->y,
scale, colour, ratio, ctx))
return false;
}
}
return true;
}
 
 
/**
* Plot text decoration for a box.
*
* \param box box to plot decorations for
* \param x_parent x coordinate of parent of box
* \param y_parent y coordinate of parent of box
* \param scale scale for redraw
* \param background_colour current background colour
* \param ctx current redraw context
* \return true if successful, false otherwise
*/
 
static bool html_redraw_text_decoration(struct box *box,
int x_parent, int y_parent, float scale,
colour background_colour, const struct redraw_context *ctx)
{
static const enum css_text_decoration_e decoration[] = {
CSS_TEXT_DECORATION_UNDERLINE, CSS_TEXT_DECORATION_OVERLINE,
CSS_TEXT_DECORATION_LINE_THROUGH };
static const float line_ratio[] = { 0.9, 0.1, 0.5 };
colour fgcol;
unsigned int i;
css_color col;
 
css_computed_color(box->style, &col);
fgcol = nscss_color_to_ns(col);
 
/* antialias colour for under/overline */
if (html_redraw_printing == false)
fgcol = blend_colour(background_colour, fgcol);
 
if (box->type == BOX_INLINE) {
if (!box->inline_end)
return true;
for (i = 0; i != NOF_ELEMENTS(decoration); i++)
if (css_computed_text_decoration(box->style) &
decoration[i])
if (!html_redraw_text_decoration_inline(box,
x_parent, y_parent, scale,
fgcol, line_ratio[i], ctx))
return false;
} else {
for (i = 0; i != NOF_ELEMENTS(decoration); i++)
if (css_computed_text_decoration(box->style) &
decoration[i])
if (!html_redraw_text_decoration_block(box,
x_parent + box->x,
y_parent + box->y,
scale,
fgcol, line_ratio[i], ctx))
return false;
}
 
return true;
}
 
 
/**
* Redraw the text content of a box, possibly partially highlighted
* because the text has been selected, or matches a search operation.
*
* \param box box with text content
* \param x x co-ord of box
* \param y y co-ord of box
* \param clip current clip rectangle
* \param scale current scale setting (1.0 = 100%)
* \param current_background_color
* \param ctx current redraw context
* \return true iff successful and redraw should proceed
*/
 
static bool html_redraw_text_box(const html_content *html, struct box *box,
int x, int y, const struct rect *clip, float scale,
colour current_background_color,
const struct redraw_context *ctx)
{
bool excluded = (box->object != NULL);
plot_font_style_t fstyle;
 
font_plot_style_from_css(box->style, &fstyle);
fstyle.background = current_background_color;
 
if (!text_redraw(box->text, box->length, box->byte_offset,
box->space, &fstyle, x, y,
clip, box->height, scale, excluded,
(struct content *)html, &html->sel,
html->search, ctx))
return false;
 
return true;
}
 
bool html_redraw_box(const html_content *html, struct box *box,
int x_parent, int y_parent,
const struct rect *clip, float scale,
colour current_background_color,
const struct redraw_context *ctx);
 
/**
* Draw the various children of a box.
*
* \param html html content
* \param box box to draw children of
* \param x_parent coordinate of parent box
* \param y_parent coordinate of parent box
* \param clip clip rectangle
* \param scale scale for redraw
* \param current_background_color background colour under this box
* \param ctx current redraw context
* \return true if successful, false otherwise
*/
 
static bool html_redraw_box_children(const html_content *html, struct box *box,
int x_parent, int y_parent,
const struct rect *clip, float scale,
colour current_background_color,
const struct redraw_context *ctx)
{
struct box *c;
 
for (c = box->children; c; c = c->next) {
 
if (c->type != BOX_FLOAT_LEFT && c->type != BOX_FLOAT_RIGHT)
if (!html_redraw_box(html, c,
x_parent + box->x -
scrollbar_get_offset(box->scroll_x),
y_parent + box->y -
scrollbar_get_offset(box->scroll_y),
clip, scale, current_background_color,
ctx))
return false;
}
for (c = box->float_children; c; c = c->next_float)
if (!html_redraw_box(html, c,
x_parent + box->x -
scrollbar_get_offset(box->scroll_x),
y_parent + box->y -
scrollbar_get_offset(box->scroll_y),
clip, scale, current_background_color,
ctx))
return false;
 
return true;
}
 
/**
* Recursively draw a box.
*
* \param html html content
* \param box box to draw
* \param x_parent coordinate of parent box
* \param y_parent coordinate of parent box
* \param clip clip rectangle
* \param scale scale for redraw
* \param current_background_color background colour under this box
* \param ctx current redraw context
* \return true if successful, false otherwise
*
* x, y, clip_[xy][01] are in target coordinates.
*/
 
bool html_redraw_box(const html_content *html, struct box *box,
int x_parent, int y_parent,
const struct rect *clip, const float scale,
colour current_background_color,
const struct redraw_context *ctx)
{
const struct plotter_table *plot = ctx->plot;
int x, y;
int width, height;
int padding_left, padding_top, padding_width, padding_height;
int border_left, border_top, border_right, border_bottom;
struct rect r;
int x_scrolled, y_scrolled;
struct box *bg_box = NULL;
bool has_x_scroll, has_y_scroll;
css_computed_clip_rect css_rect;
 
if (html_redraw_printing && (box->flags & PRINTED))
return true;
 
/* avoid trivial FP maths */
if (scale == 1.0) {
x = x_parent + box->x;
y = y_parent + box->y;
width = box->width;
height = box->height;
padding_left = box->padding[LEFT];
padding_top = box->padding[TOP];
padding_width = padding_left + box->width + box->padding[RIGHT];
padding_height = padding_top + box->height +
box->padding[BOTTOM];
border_left = box->border[LEFT].width;
border_top = box->border[TOP].width;
border_right = box->border[RIGHT].width;
border_bottom = box->border[BOTTOM].width;
} else {
x = (x_parent + box->x) * scale;
y = (y_parent + box->y) * scale;
width = box->width * scale;
height = box->height * scale;
/* left and top padding values are normally zero,
* so avoid trivial FP maths */
padding_left = box->padding[LEFT] ? box->padding[LEFT] * scale
: 0;
padding_top = box->padding[TOP] ? box->padding[TOP] * scale
: 0;
padding_width = (box->padding[LEFT] + box->width +
box->padding[RIGHT]) * scale;
padding_height = (box->padding[TOP] + box->height +
box->padding[BOTTOM]) * scale;
border_left = box->border[LEFT].width * scale;
border_top = box->border[TOP].width * scale;
border_right = box->border[RIGHT].width * scale;
border_bottom = box->border[BOTTOM].width * scale;
}
 
/* calculate rectangle covering this box and descendants */
if (box->style && css_computed_overflow(box->style) !=
CSS_OVERFLOW_VISIBLE) {
/* box contents clipped to box size */
r.x0 = x - border_left;
r.y0 = y - border_top;
r.x1 = x + padding_width + border_right;
r.y1 = y + padding_height + border_bottom;
} else {
/* box contents can hang out of the box; use descendant box */
if (scale == 1.0) {
r.x0 = x + box->descendant_x0;
r.y0 = y + box->descendant_y0;
r.x1 = x + box->descendant_x1 + 1;
r.y1 = y + box->descendant_y1 + 1;
} else {
r.x0 = x + box->descendant_x0 * scale;
r.y0 = y + box->descendant_y0 * scale;
r.x1 = x + box->descendant_x1 * scale + 1;
r.y1 = y + box->descendant_y1 * scale + 1;
}
if (!box->parent) {
/* root element */
int margin_left, margin_right;
int margin_top, margin_bottom;
if (scale == 1.0) {
margin_left = box->margin[LEFT];
margin_top = box->margin[TOP];
margin_right = box->margin[RIGHT];
margin_bottom = box->margin[BOTTOM];
} else {
margin_left = box->margin[LEFT] * scale;
margin_top = box->margin[TOP] * scale;
margin_right = box->margin[RIGHT] * scale;
margin_bottom = box->margin[BOTTOM] * scale;
}
r.x0 = x - border_left - margin_left < r.x0 ?
x - border_left - margin_left : r.x0;
r.y0 = y - border_top - margin_top < r.y0 ?
y - border_top - margin_top : r.y0;
r.x1 = x + padding_width + border_right +
margin_right > r.x1 ?
x + padding_width + border_right +
margin_right : r.x1;
r.y1 = y + padding_height + border_bottom +
margin_bottom > r.y1 ?
y + padding_height + border_bottom +
margin_bottom : r.y1;
}
}
 
/* return if the rectangle is completely outside the clip rectangle */
if (clip->y1 < r.y0 || r.y1 < clip->y0 ||
clip->x1 < r.x0 || r.x1 < clip->x0)
return true;
 
/*if the rectangle is under the page bottom but it can fit in a page,
don't print it now*/
if (html_redraw_printing) {
if (r.y1 > html_redraw_printing_border) {
if (r.y1 - r.y0 <= html_redraw_printing_border &&
(box->type == BOX_TEXT ||
box->type == BOX_TABLE_CELL
|| box->object || box->gadget)) {
/*remember the highest of all points from the
not printed elements*/
if (r.y0 < html_redraw_printing_top_cropped)
html_redraw_printing_top_cropped = r.y0;
return true;
}
}
else box->flags |= PRINTED; /*it won't be printed anymore*/
}
 
/* if visibility is hidden render children only */
if (box->style && css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN) {
if ((plot->group_start) && (!plot->group_start("hidden box")))
return false;
if (!html_redraw_box_children(html, box, x_parent, y_parent,
&r, scale, current_background_color, ctx))
return false;
return ((!plot->group_end) || (plot->group_end()));
}
 
if ((plot->group_start) && (!plot->group_start("vis box")))
return false;
 
 
if (box->style != NULL &&
css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE &&
css_computed_clip(box->style, &css_rect) ==
CSS_CLIP_RECT) {
/* We have an absolutly positioned box with a clip rect */
if (css_rect.left_auto == false)
r.x0 = x - border_left + FIXTOINT(nscss_len2px(
css_rect.left, css_rect.lunit,
box->style));
 
if (css_rect.top_auto == false)
r.y0 = y - border_top + FIXTOINT(nscss_len2px(
css_rect.top, css_rect.tunit,
box->style));
 
if (css_rect.right_auto == false)
r.x1 = x - border_left + FIXTOINT(nscss_len2px(
css_rect.right, css_rect.runit,
box->style));
 
if (css_rect.bottom_auto == false)
r.y1 = y - border_top + FIXTOINT(nscss_len2px(
css_rect.bottom, css_rect.bunit,
box->style));
 
/* find intersection of clip rectangle and box */
if (r.x0 < clip->x0) r.x0 = clip->x0;
if (r.y0 < clip->y0) r.y0 = clip->y0;
if (clip->x1 < r.x1) r.x1 = clip->x1;
if (clip->y1 < r.y1) r.y1 = clip->y1;
/* no point trying to draw 0-width/height boxes */
if (r.x0 == r.x1 || r.y0 == r.y1)
/* not an error */
return ((!plot->group_end) || (plot->group_end()));
/* clip to it */
if (!plot->clip(&r))
return false;
 
} else if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
box->type == BOX_TABLE_CELL || box->object) {
/* find intersection of clip rectangle and box */
if (r.x0 < clip->x0) r.x0 = clip->x0;
if (r.y0 < clip->y0) r.y0 = clip->y0;
if (clip->x1 < r.x1) r.x1 = clip->x1;
if (clip->y1 < r.y1) r.y1 = clip->y1;
/* no point trying to draw 0-width/height boxes */
if (r.x0 == r.x1 || r.y0 == r.y1)
/* not an error */
return ((!plot->group_end) || (plot->group_end()));
/* clip to it */
if (!plot->clip(&r))
return false;
} else {
/* clip box is fine, clip to it */
r = *clip;
if (!plot->clip(&r))
return false;
}
 
/* background colour and image for block level content and replaced
* inlines */
 
bg_box = html_redraw_find_bg_box(box);
 
/* bg_box == NULL implies that this box should not have
* its background rendered. Otherwise filter out linebreaks,
* optimize away non-differing inlines, only plot background
* for BOX_TEXT it's in an inline */
if (bg_box && bg_box->type != BOX_BR &&
bg_box->type != BOX_TEXT &&
bg_box->type != BOX_INLINE_END &&
(bg_box->type != BOX_INLINE || bg_box->object ||
bg_box->flags & IFRAME || box->flags & REPLACE_DIM)) {
/* find intersection of clip box and border edge */
struct rect p;
p.x0 = x - border_left < r.x0 ? r.x0 : x - border_left;
p.y0 = y - border_top < r.y0 ? r.y0 : y - border_top;
p.x1 = x + padding_width + border_right < r.x1 ?
x + padding_width + border_right : r.x1;
p.y1 = y + padding_height + border_bottom < r.y1 ?
y + padding_height + border_bottom : r.y1;
if (!box->parent) {
/* Root element, special case:
* background covers margins too */
int m_left, m_top, m_right, m_bottom;
if (scale == 1.0) {
m_left = box->margin[LEFT];
m_top = box->margin[TOP];
m_right = box->margin[RIGHT];
m_bottom = box->margin[BOTTOM];
} else {
m_left = box->margin[LEFT] * scale;
m_top = box->margin[TOP] * scale;
m_right = box->margin[RIGHT] * scale;
m_bottom = box->margin[BOTTOM] * scale;
}
p.x0 = p.x0 - m_left < r.x0 ? r.x0 : p.x0 - m_left;
p.y0 = p.y0 - m_top < r.y0 ? r.y0 : p.y0 - m_top;
p.x1 = p.x1 + m_right < r.x1 ? p.x1 + m_right : r.x1;
p.y1 = p.y1 + m_bottom < r.y1 ? p.y1 + m_bottom : r.y1;
}
/* valid clipping rectangles only */
if ((p.x0 < p.x1) && (p.y0 < p.y1)) {
/* plot background */
if (!html_redraw_background(x, y, box, scale, &p,
&current_background_color, bg_box, ctx))
return false;
/* restore previous graphics window */
if (!plot->clip(&r))
return false;
}
}
 
/* borders for block level content and replaced inlines */
if (box->style && box->type != BOX_TEXT &&
box->type != BOX_INLINE_END &&
(box->type != BOX_INLINE || box->object ||
box->flags & IFRAME || box->flags & REPLACE_DIM) &&
(border_top || border_right ||
border_bottom || border_left)) {
if (!html_redraw_borders(box, x_parent, y_parent,
padding_width, padding_height, &r,
scale, ctx))
return false;
}
 
/* backgrounds and borders for non-replaced inlines */
if (box->style && box->type == BOX_INLINE && box->inline_end &&
(html_redraw_box_has_background(box) ||
border_top || border_right ||
border_bottom || border_left)) {
/* inline backgrounds and borders span other boxes and may
* wrap onto separate lines */
struct box *ib;
struct rect b; /* border edge rectangle */
struct rect p; /* clipped rect */
bool first = true;
int ib_x;
int ib_y = y;
int ib_p_width;
int ib_b_left, ib_b_right;
 
b.x0 = x - border_left;
b.x1 = x + padding_width + border_right;
b.y0 = y - border_top;
b.y1 = y + padding_height + border_bottom;
 
p.x0 = b.x0 < r.x0 ? r.x0 : b.x0;
p.x1 = b.x1 < r.x1 ? b.x1 : r.x1;
p.y0 = b.y0 < r.y0 ? r.y0 : b.y0;
p.y1 = b.y1 < r.y1 ? b.y1 : r.y1;
for (ib = box; ib; ib = ib->next) {
/* to get extents of rectangle(s) associated with
* inline, cycle though all boxes in inline, skipping
* over floats */
if (ib->type == BOX_FLOAT_LEFT ||
ib->type == BOX_FLOAT_RIGHT)
continue;
if (scale == 1.0) {
ib_x = x_parent + ib->x;
ib_y = y_parent + ib->y;
ib_p_width = ib->padding[LEFT] + ib->width +
ib->padding[RIGHT];
ib_b_left = ib->border[LEFT].width;
ib_b_right = ib->border[RIGHT].width;
} else {
ib_x = (x_parent + ib->x) * scale;
ib_y = (y_parent + ib->y) * scale;
ib_p_width = (ib->padding[LEFT] + ib->width +
ib->padding[RIGHT]) * scale;
ib_b_left = ib->border[LEFT].width * scale;
ib_b_right = ib->border[RIGHT].width * scale;
}
 
if ((ib->flags & NEW_LINE) && ib != box) {
/* inline element has wrapped, plot background
* and borders */
if (!html_redraw_inline_background(
x, y, box, scale, &p, b,
first, false,
&current_background_color, ctx))
return false;
/* restore previous graphics window */
if (!plot->clip(&r))
return false;
if (!html_redraw_inline_borders(box, b, &r,
scale, first, false, ctx))
return false;
/* reset coords */
b.x0 = ib_x - ib_b_left;
b.y0 = ib_y - border_top - padding_top;
b.y1 = ib_y + padding_height - padding_top +
border_bottom;
 
p.x0 = b.x0 < r.x0 ? r.x0 : b.x0;
p.y0 = b.y0 < r.y0 ? r.y0 : b.y0;
p.y1 = b.y1 < r.y1 ? b.y1 : r.y1;
 
first = false;
}
 
/* increase width for current box */
b.x1 = ib_x + ib_p_width + ib_b_right;
p.x1 = b.x1 < r.x1 ? b.x1 : r.x1;
 
if (ib == box->inline_end)
/* reached end of BOX_INLINE span */
break;
}
/* plot background and borders for last rectangle of
* the inline */
if (!html_redraw_inline_background(x, ib_y, box, scale, &p, b,
first, true, &current_background_color, ctx))
return false;
/* restore previous graphics window */
if (!plot->clip(&r))
return false;
if (!html_redraw_inline_borders(box, b, &r, scale, first, true,
ctx))
return false;
 
}
 
/* Debug outlines */
if (html_redraw_debug) {
int margin_left, margin_right;
int margin_top, margin_bottom;
if (scale == 1.0) {
/* avoid trivial fp maths */
margin_left = box->margin[LEFT];
margin_top = box->margin[TOP];
margin_right = box->margin[RIGHT];
margin_bottom = box->margin[BOTTOM];
} else {
margin_left = box->margin[LEFT] * scale;
margin_top = box->margin[TOP] * scale;
margin_right = box->margin[RIGHT] * scale;
margin_bottom = box->margin[BOTTOM] * scale;
}
/* Content edge -- blue */
if (!plot->rectangle(x + padding_left,
y + padding_top,
x + padding_left + width,
y + padding_top + height,
plot_style_content_edge))
return false;
/* Padding edge -- red */
if (!plot->rectangle(x, y,
x + padding_width, y + padding_height,
plot_style_padding_edge))
return false;
/* Margin edge -- yellow */
if (!plot->rectangle(
x - border_left - margin_left,
y - border_top - margin_top,
x + padding_width + border_right +
margin_right,
y + padding_height + border_bottom +
margin_bottom,
plot_style_margin_edge))
return false;
}
 
/* clip to the padding edge for objects, or boxes with overflow hidden
* or scroll */
if ((box->style && css_computed_overflow(box->style) !=
CSS_OVERFLOW_VISIBLE) || box->object ||
box->flags & IFRAME) {
r.x0 = x;
r.y0 = y;
r.x1 = x + padding_width;
r.y1 = y + padding_height;
if (r.x0 < clip->x0) r.x0 = clip->x0;
if (r.y0 < clip->y0) r.y0 = clip->y0;
if (clip->x1 < r.x1) r.x1 = clip->x1;
if (clip->y1 < r.y1) r.y1 = clip->y1;
if (r.x1 <= r.x0 || r.y1 <= r.y0)
return ((!plot->group_end) || (plot->group_end()));
if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
box->type == BOX_TABLE_CELL || box->object) {
if (!plot->clip(&r))
return false;
}
}
 
/* text decoration */
if (box->type != BOX_TEXT && box->style &&
css_computed_text_decoration(box->style) !=
CSS_TEXT_DECORATION_NONE)
if (!html_redraw_text_decoration(box, x_parent, y_parent,
scale, current_background_color, ctx))
return false;
 
if (box->object && width != 0 && height != 0) {
struct content_redraw_data obj_data;
 
x_scrolled = x - scrollbar_get_offset(box->scroll_x) * scale;
y_scrolled = y - scrollbar_get_offset(box->scroll_y) * scale;
 
obj_data.x = x_scrolled + padding_left;
obj_data.y = y_scrolled + padding_top;
obj_data.width = width;
obj_data.height = height;
obj_data.background_colour = current_background_color;
obj_data.scale = scale;
obj_data.repeat_x = false;
obj_data.repeat_y = false;
 
if (content_get_type(box->object) == CONTENT_HTML) {
obj_data.x /= scale;
obj_data.y /= scale;
}
 
if (!content_redraw(box->object, &obj_data, &r, ctx)) {
/* Show image fail */
/* Unicode (U+FFFC) 'OBJECT REPLACEMENT CHARACTER' */
const char *obj = "\xef\xbf\xbc";
int obj_width;
int obj_x = x + padding_left;
if (!plot->rectangle(x + padding_left,
y + padding_top,
x + padding_left + width - 1,
y + padding_top + height - 1,
plot_style_broken_object))
return false;
if (!nsfont.font_width(plot_fstyle_broken_object, obj,
sizeof(obj) - 1, &obj_width))
obj_x += 1;
else
obj_x += width / 2 - obj_width / 2;
 
if (!plot->text(obj_x, y + padding_top + (int)
(height * 0.75),
obj, sizeof(obj) - 1,
plot_fstyle_broken_object))
return false;
}
 
} else if (box->iframe) {
/* Offset is passed to browser window redraw unscaled */
browser_window_redraw(box->iframe,
(x + padding_left) / scale,
(y + padding_top) / scale, &r, ctx);
 
} else if (box->gadget && box->gadget->type == GADGET_CHECKBOX) {
if (!html_redraw_checkbox(x + padding_left, y + padding_top,
width, height, box->gadget->selected, ctx))
return false;
 
} else if (box->gadget && box->gadget->type == GADGET_RADIO) {
if (!html_redraw_radio(x + padding_left, y + padding_top,
width, height, box->gadget->selected, ctx))
return false;
 
} else if (box->gadget && box->gadget->type == GADGET_FILE) {
if (!html_redraw_file(x + padding_left, y + padding_top,
width, height, box, scale,
current_background_color, ctx))
return false;
 
} else if (box->text) {
if (!html_redraw_text_box(html, box, x, y, &r, scale,
current_background_color, ctx))
return false;
 
} else {
if (!html_redraw_box_children(html, box, x_parent, y_parent, &r,
scale, current_background_color, ctx))
return false;
}
 
if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
box->type == BOX_TABLE_CELL || box->type == BOX_INLINE)
if (!plot->clip(clip))
return false;
 
/* list marker */
if (box->list_marker)
if (!html_redraw_box(html, box->list_marker,
x_parent + box->x -
scrollbar_get_offset(box->scroll_x),
y_parent + box->y -
scrollbar_get_offset(box->scroll_y),
clip, scale, current_background_color, ctx))
return false;
 
/* scrollbars */
if (((box->style && box->type != BOX_BR &&
box->type != BOX_TABLE && box->type != BOX_INLINE &&
(css_computed_overflow(box->style) ==
CSS_OVERFLOW_SCROLL ||
css_computed_overflow(box->style) ==
CSS_OVERFLOW_AUTO)) || (box->object &&
content_get_type(box->object) == CONTENT_HTML)) &&
box->parent != NULL) {
 
has_x_scroll = box_hscrollbar_present(box);
has_y_scroll = box_vscrollbar_present(box);
 
if (!box_handle_scrollbars((struct content *)html,
box, has_x_scroll, has_y_scroll))
return false;
if (box->scroll_x != NULL)
scrollbar_redraw(box->scroll_x,
x_parent + box->x,
y_parent + box->y + box->padding[TOP] +
box->height + box->padding[BOTTOM] -
SCROLLBAR_WIDTH, clip, scale, ctx);
if (box->scroll_y != NULL)
scrollbar_redraw(box->scroll_y,
x_parent + box->x + box->padding[LEFT] +
box->width + box->padding[RIGHT] -
SCROLLBAR_WIDTH,
y_parent + box->y, clip, scale, ctx);
}
 
if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
box->type == BOX_TABLE_CELL || box->type == BOX_INLINE)
if (!plot->clip(clip))
return false;
 
return ((!plot->group_end) || (plot->group_end()));
}
 
/**
* Draw a CONTENT_HTML using the current set of plotters (plot).
*
* \param c content of type CONTENT_HTML
* \param data redraw data for this content redraw
* \param clip current clip region
* \param ctx current redraw context
* \return true if successful, false otherwise
*
* x, y, clip_[xy][01] are in target coordinates.
*/
 
bool html_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
html_content *html = (html_content *) c;
struct box *box;
bool result = true;
bool select, select_only;
plot_style_t pstyle_fill_bg = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = data->background_colour,
};
 
box = html->layout;
assert(box);
 
/* The select menu needs special treating because, when opened, it
* reaches beyond its layout box.
*/
select = false;
select_only = false;
if (ctx->interactive && html->visible_select_menu != NULL) {
struct form_control *control = html->visible_select_menu;
select = true;
/* check if the redraw rectangle is completely inside of the
select menu */
select_only = form_clip_inside_select_menu(control,
data->scale, clip);
}
if (!select_only) {
/* clear to background colour */
result = ctx->plot->clip(clip);
if (html->background_colour != NS_TRANSPARENT)
pstyle_fill_bg.fill_colour = html->background_colour;
result &= ctx->plot->rectangle(clip->x0, clip->y0,
clip->x1, clip->y1,
&pstyle_fill_bg);
result &= html_redraw_box(html, box, data->x, data->y, clip,
data->scale, pstyle_fill_bg.fill_colour, ctx);
}
 
if (select) {
int menu_x, menu_y;
box = html->visible_select_menu->box;
box_coords(box, &menu_x, &menu_y);
menu_x -= box->border[LEFT].width;
menu_y += box->height + box->border[BOTTOM].width +
box->padding[BOTTOM] + box->padding[TOP];
result &= form_redraw_select_menu(html->visible_select_menu,
data->x + menu_x, data->y + menu_y,
data->scale, clip, ctx);
}
 
return result;
 
}
/programs/network/netsurf/netsurf/render/html_script.c
0,0 → 1,602
/*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for text/html scripts (implementation).
*/
 
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
 
#include "utils/config.h"
#include "utils/corestrings.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "javascript/js.h"
#include "content/content_protected.h"
#include "content/fetch.h"
#include "content/hlcache.h"
#include "render/html_internal.h"
 
typedef bool (script_handler_t)(struct jscontext *jscontext, const char *data, size_t size) ;
 
 
static script_handler_t *select_script_handler(content_type ctype)
{
if (ctype == CONTENT_JS) {
return js_exec;
}
return NULL;
}
 
 
/* attempt defer and async script execution
*
* execute scripts using algorithm found in:
* http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#the-script-element
*
*/
bool html_scripts_exec(html_content *c)
{
unsigned int i;
struct html_script *s;
script_handler_t *script_handler;
 
if (c->jscontext == NULL)
return false;
 
for (i = 0, s = c->scripts; i != c->scripts_count; i++, s++) {
if (s->already_started) {
continue;
}
 
if ((s->type == HTML_SCRIPT_ASYNC) ||
(s->type == HTML_SCRIPT_DEFER)) {
/* ensure script content is present */
if (s->data.handle == NULL)
continue;
 
/* ensure script content fetch status is not an error */
if (content_get_status(s->data.handle) ==
CONTENT_STATUS_ERROR)
continue;
 
/* ensure script handler for content type */
script_handler = select_script_handler(
content_get_type(s->data.handle));
if (script_handler == NULL)
continue; /* unsupported type */
 
if (content_get_status(s->data.handle) ==
CONTENT_STATUS_DONE) {
/* external script is now available */
const char *data;
unsigned long size;
data = content_get_source_data(
s->data.handle, &size );
script_handler(c->jscontext, data, size);
 
s->already_started = true;
 
}
}
}
 
return true;
}
 
/* create new html script entry */
static struct html_script *
html_process_new_script(html_content *c,
dom_string *mimetype,
enum html_script_type type)
{
struct html_script *nscript;
/* add space for new script entry */
nscript = realloc(c->scripts,
sizeof(struct html_script) * (c->scripts_count + 1));
if (nscript == NULL) {
return NULL;
}
 
c->scripts = nscript;
 
/* increment script entry count */
nscript = &c->scripts[c->scripts_count];
c->scripts_count++;
 
nscript->already_started = false;
nscript->parser_inserted = false;
nscript->force_async = true;
nscript->ready_exec = false;
nscript->async = false;
nscript->defer = false;
 
nscript->type = type;
 
nscript->mimetype = dom_string_ref(mimetype); /* reference mimetype */
 
return nscript;
}
 
/**
* Callback for asyncronous scripts
*/
static nserror
convert_script_async_cb(hlcache_handle *script,
const hlcache_event *event,
void *pw)
{
html_content *parent = pw;
unsigned int i;
struct html_script *s;
 
/* Find script */
for (i = 0, s = parent->scripts; i != parent->scripts_count; i++, s++) {
if (s->type == HTML_SCRIPT_ASYNC && s->data.handle == script)
break;
}
 
assert(i != parent->scripts_count);
 
switch (event->type) {
case CONTENT_MSG_LOADING:
break;
 
case CONTENT_MSG_READY:
break;
 
case CONTENT_MSG_DONE:
LOG(("script %d done '%s'", i,
nsurl_access(hlcache_handle_get_url(script))));
parent->base.active--;
LOG(("%d fetches active", parent->base.active));
 
 
 
break;
 
case CONTENT_MSG_ERROR:
LOG(("script %s failed: %s",
nsurl_access(hlcache_handle_get_url(script)),
event->data.error));
hlcache_handle_release(script);
s->data.handle = NULL;
parent->base.active--;
LOG(("%d fetches active", parent->base.active));
content_add_error(&parent->base, "?", 0);
 
break;
 
case CONTENT_MSG_STATUS:
break;
 
default:
assert(0);
}
 
return NSERROR_OK;
}
 
/**
* Callback for defer scripts
*/
static nserror
convert_script_defer_cb(hlcache_handle *script,
const hlcache_event *event,
void *pw)
{
html_content *parent = pw;
unsigned int i;
struct html_script *s;
 
/* Find script */
for (i = 0, s = parent->scripts; i != parent->scripts_count; i++, s++) {
if (s->type == HTML_SCRIPT_DEFER && s->data.handle == script)
break;
}
 
assert(i != parent->scripts_count);
 
switch (event->type) {
case CONTENT_MSG_LOADING:
break;
 
case CONTENT_MSG_READY:
break;
 
case CONTENT_MSG_DONE:
LOG(("script %d done '%s'", i,
nsurl_access(hlcache_handle_get_url(script))));
parent->base.active--;
LOG(("%d fetches active", parent->base.active));
 
break;
 
case CONTENT_MSG_ERROR:
LOG(("script %s failed: %s",
nsurl_access(hlcache_handle_get_url(script)),
event->data.error));
hlcache_handle_release(script);
s->data.handle = NULL;
parent->base.active--;
LOG(("%d fetches active", parent->base.active));
content_add_error(&parent->base, "?", 0);
 
break;
 
case CONTENT_MSG_STATUS:
break;
 
default:
assert(0);
}
 
/* if there are no active fetches remaining begin post parse
* conversion
*/
if (parent->base.active == 0) {
html_begin_conversion(parent);
}
 
return NSERROR_OK;
}
 
/**
* Callback for syncronous scripts
*/
static nserror
convert_script_sync_cb(hlcache_handle *script,
const hlcache_event *event,
void *pw)
{
html_content *parent = pw;
unsigned int i;
struct html_script *s;
script_handler_t *script_handler;
dom_hubbub_error err;
 
/* Find script */
for (i = 0, s = parent->scripts; i != parent->scripts_count; i++, s++) {
if (s->type == HTML_SCRIPT_SYNC && s->data.handle == script)
break;
}
 
assert(i != parent->scripts_count);
 
switch (event->type) {
case CONTENT_MSG_LOADING:
break;
 
case CONTENT_MSG_READY:
break;
 
case CONTENT_MSG_DONE:
LOG(("script %d done '%s'", i,
nsurl_access(hlcache_handle_get_url(script))));
parent->base.active--;
LOG(("%d fetches active", parent->base.active));
 
s->already_started = true;
 
/* attempt to execute script */
script_handler = select_script_handler(content_get_type(s->data.handle));
if (script_handler != NULL) {
/* script has a handler */
const char *data;
unsigned long size;
data = content_get_source_data(s->data.handle, &size );
script_handler(parent->jscontext, data, size);
}
 
/* continue parse */
err = dom_hubbub_parser_pause(parent->parser, false);
if (err != DOM_HUBBUB_OK) {
LOG(("unpause returned 0x%x", err));
}
 
break;
 
case CONTENT_MSG_ERROR:
LOG(("script %s failed: %s",
nsurl_access(hlcache_handle_get_url(script)),
event->data.error));
 
hlcache_handle_release(script);
s->data.handle = NULL;
parent->base.active--;
 
LOG(("%d fetches active", parent->base.active));
content_add_error(&parent->base, "?", 0);
 
s->already_started = true;
 
/* continue parse */
err = dom_hubbub_parser_pause(parent->parser, false);
if (err != DOM_HUBBUB_OK) {
LOG(("unpause returned 0x%x", err));
}
 
break;
 
case CONTENT_MSG_STATUS:
break;
 
default:
assert(0);
}
 
/* if there are no active fetches remaining begin post parse
* conversion
*/
if (parent->base.active == 0) {
html_begin_conversion(parent);
}
 
return NSERROR_OK;
}
 
/**
* process a script with a src tag
*/
static dom_hubbub_error
exec_src_script(html_content *c,
dom_node *node,
dom_string *mimetype,
dom_string *src)
{
nserror ns_error;
nsurl *joined;
hlcache_child_context child;
struct html_script *nscript;
union content_msg_data msg_data;
bool async;
bool defer;
enum html_script_type script_type;
hlcache_handle_callback script_cb;
dom_hubbub_error ret = DOM_HUBBUB_OK;
dom_exception exc; /* returned by libdom functions */
 
/* src url */
ns_error = nsurl_join(c->base_url, dom_string_data(src), &joined);
if (ns_error != NSERROR_OK) {
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return DOM_HUBBUB_NOMEM;
}
 
LOG(("script %i '%s'", c->scripts_count, nsurl_access(joined)));
 
/* there are three ways to process the script tag at this point:
*
* Syncronously pause the parent parse and continue after
* the script has downloaded and executed. (default)
* Async Start the script downloading and execute it when it
* becomes available.
* Defered Start the script downloading and execute it when
* the page has completed parsing, may be set along
* with async where it is ignored.
*/
 
/* we interpret the presence of the async and defer attribute
* as true and ignore its value, technically only the empty
* value or the attribute name itself are valid. However
* various browsers interpret this in various ways the most
* compatible approach is to be liberal and accept any
* value. Note setting the values to "false" still makes them true!
*/
exc = dom_element_has_attribute(node, corestring_dom_async, &async);
if (exc != DOM_NO_ERR) {
return DOM_HUBBUB_OK; /* dom error */
}
 
if (async) {
/* asyncronous script */
script_type = HTML_SCRIPT_ASYNC;
script_cb = convert_script_async_cb;
 
} else {
exc = dom_element_has_attribute(node,
corestring_dom_defer, &defer);
if (exc != DOM_NO_ERR) {
return DOM_HUBBUB_OK; /* dom error */
}
 
if (defer) {
/* defered script */
script_type = HTML_SCRIPT_DEFER;
script_cb = convert_script_defer_cb;
} else {
/* syncronous script */
script_type = HTML_SCRIPT_SYNC;
script_cb = convert_script_sync_cb;
}
}
 
nscript = html_process_new_script(c, mimetype, script_type);
if (nscript == NULL) {
nsurl_unref(joined);
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return DOM_HUBBUB_NOMEM;
}
 
/* set up child fetch encoding and quirks */
child.charset = c->encoding;
child.quirks = c->base.quirks;
 
ns_error = hlcache_handle_retrieve(joined,
0,
content_get_url(&c->base),
NULL,
script_cb,
c,
&child,
CONTENT_SCRIPT,
&nscript->data.handle);
 
 
nsurl_unref(joined);
 
if (ns_error != NSERROR_OK) {
/* @todo Deal with fetch error better. currently assume
* fetch never became active
*/
/* mark duff script fetch as already started */
nscript->already_started = true;
LOG(("Fetch failed with error %d",ns_error));
} else {
/* update base content active fetch count */
c->base.active++;
LOG(("%d fetches active", c->base.active));
 
switch (script_type) {
case HTML_SCRIPT_SYNC:
ret = DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED;
 
case HTML_SCRIPT_ASYNC:
break;
 
case HTML_SCRIPT_DEFER:
break;
 
default:
assert(0);
}
}
 
return ret;
}
 
static dom_hubbub_error
exec_inline_script(html_content *c, dom_node *node, dom_string *mimetype)
{
union content_msg_data msg_data;
dom_string *script;
dom_exception exc; /* returned by libdom functions */
struct lwc_string_s *lwcmimetype;
script_handler_t *script_handler;
struct html_script *nscript;
 
/* does not appear to be a src so script is inline content */
exc = dom_node_get_text_content(node, &script);
if ((exc != DOM_NO_ERR) || (script == NULL)) {
return DOM_HUBBUB_OK; /* no contents, skip */
}
 
nscript = html_process_new_script(c, mimetype, HTML_SCRIPT_INLINE);
if (nscript == NULL) {
dom_string_unref(script);
 
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return DOM_HUBBUB_NOMEM;
 
}
 
nscript->data.string = script;
nscript->already_started = true;
 
/* ensure script handler for content type */
dom_string_intern(mimetype, &lwcmimetype);
script_handler = select_script_handler(content_factory_type_from_mime_type(lwcmimetype));
lwc_string_unref(lwcmimetype);
 
if (script_handler != NULL) {
script_handler(c->jscontext,
dom_string_data(script),
dom_string_byte_length(script));
}
return DOM_HUBBUB_OK;
}
 
 
/**
* process script node parser callback
*
*
*/
dom_hubbub_error
html_process_script(void *ctx, dom_node *node)
{
html_content *c = (html_content *)ctx;
dom_exception exc; /* returned by libdom functions */
dom_string *src, *mimetype;
dom_hubbub_error err = DOM_HUBBUB_OK;
 
/* ensure javascript context is available */
if (c->jscontext == NULL) {
union content_msg_data msg_data;
 
msg_data.jscontext = &c->jscontext;
content_broadcast(&c->base, CONTENT_MSG_GETCTX, msg_data);
LOG(("javascript context %p ", c->jscontext));
if (c->jscontext == NULL) {
/* no context and it could not be created, abort */
return DOM_HUBBUB_OK;
}
}
 
LOG(("content %p parser %p node %p", c, c->parser, node));
 
exc = dom_element_get_attribute(node, corestring_dom_type, &mimetype);
if (exc != DOM_NO_ERR || mimetype == NULL) {
mimetype = dom_string_ref(corestring_dom_text_javascript);
}
 
exc = dom_element_get_attribute(node, corestring_dom_src, &src);
if (exc != DOM_NO_ERR || src == NULL) {
err = exec_inline_script(c, node, mimetype);
} else {
err = exec_src_script(c, node, mimetype, src);
dom_string_unref(src);
}
 
dom_string_unref(mimetype);
 
return err;
}
 
void html_free_scripts(html_content *html)
{
unsigned int i;
 
for (i = 0; i != html->scripts_count; i++) {
if (html->scripts[i].mimetype != NULL) {
dom_string_unref(html->scripts[i].mimetype);
}
 
if ((html->scripts[i].type == HTML_SCRIPT_INLINE) &&
(html->scripts[i].data.string != NULL)) {
 
dom_string_unref(html->scripts[i].data.string);
 
} else if ((html->scripts[i].type == HTML_SCRIPT_SYNC) &&
(html->scripts[i].data.handle != NULL)) {
 
hlcache_handle_release(html->scripts[i].data.handle);
 
}
}
free(html->scripts);
}
/programs/network/netsurf/netsurf/render/imagemap.c
0,0 → 1,804
/*
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/*
* Much of this shamelessly copied from utils/messages.c
*/
 
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
 
#include <dom/dom.h>
 
#include "content/content_protected.h"
#include "content/hlcache.h"
#include "render/box.h"
#include "render/html_internal.h"
#include "render/imagemap.h"
#include "utils/corestrings.h"
#include "utils/log.h"
#include "utils/utils.h"
 
#define HASH_SIZE 31 /* fixed size hash table */
 
typedef enum {
IMAGEMAP_DEFAULT,
IMAGEMAP_RECT,
IMAGEMAP_CIRCLE,
IMAGEMAP_POLY
} imagemap_entry_type;
 
struct mapentry {
imagemap_entry_type type; /**< type of shape */
nsurl *url; /**< absolute url to go to */
char *target; /**< target frame (if any) */
union {
struct {
int x; /**< x coordinate of centre */
int y; /**< y coordinate of center */
int r; /**< radius of circle */
} circle;
struct {
int x0; /**< left hand edge */
int y0; /**< top edge */
int x1; /**< right hand edge */
int y1; /**< bottom edge */
} rect;
struct {
int num; /**< number of points */
float *xcoords; /**< x coordinates */
float *ycoords; /**< y coordinates */
} poly;
} bounds;
struct mapentry *next; /**< next entry in list */
};
 
struct imagemap {
char *key; /**< key for this entry */
struct mapentry *list; /**< pointer to linked list of entries */
struct imagemap *next; /**< next entry in this hash chain */
};
 
static bool imagemap_add(html_content *c, dom_string *key,
struct mapentry *list);
static bool imagemap_create(html_content *c);
static bool imagemap_extract_map(dom_node *node, html_content *c,
struct mapentry **entry);
static bool imagemap_addtolist(dom_node *n, nsurl *base_url,
struct mapentry **entry, dom_string *tagtype);
static void imagemap_freelist(struct mapentry *list);
static unsigned int imagemap_hash(const char *key);
static int imagemap_point_in_poly(int num, float *xpt, float *ypt,
unsigned long x, unsigned long y, unsigned long click_x,
unsigned long click_y);
 
/**
* Add an imagemap to the hashtable, creating it if it doesn't exist
*
* \param c The containing content
* \param key The name of the imagemap
* \param list List of map regions
* \return true on succes, false otherwise
*/
bool imagemap_add(html_content *c, dom_string *key, struct mapentry *list)
{
struct imagemap *map;
unsigned int slot;
 
assert(c != NULL);
assert(key != NULL);
assert(list != NULL);
 
if (imagemap_create(c) == false)
return false;
 
map = calloc(1, sizeof(*map));
if (map == NULL)
return false;
/* \todo Stop relying on NULL termination of dom_string */
map->key = strdup(dom_string_data(key));
if (map->key == NULL) {
free(map);
return false;
}
 
map->list = list;
 
slot = imagemap_hash(map->key);
 
map->next = c->imagemaps[slot];
c->imagemaps[slot] = map;
 
return true;
}
 
/**
* Create hashtable of imagemaps
*
* \param c The containing content
* \return true on success, false otherwise
*/
bool imagemap_create(html_content *c)
{
assert(c != NULL);
 
if (c->imagemaps == NULL) {
c->imagemaps = calloc(HASH_SIZE, sizeof(struct imagemap));
if (c->imagemaps == NULL) {
return false;
}
}
 
return true;
}
 
/**
* Destroy hashtable of imagemaps
*
* \param c The containing content
*/
void imagemap_destroy(html_content *c)
{
unsigned int i;
 
assert(c != NULL);
 
/* no imagemaps -> return */
if (c->imagemaps == NULL)
return;
 
for (i = 0; i != HASH_SIZE; i++) {
struct imagemap *map, *next;
 
map = c->imagemaps[i];
while (map != NULL) {
next = map->next;
imagemap_freelist(map->list);
free(map->key);
free(map);
map = next;
}
}
 
free(c->imagemaps);
}
 
/**
* Dump imagemap data to the log
*
* \param c The containing content
*/
void imagemap_dump(html_content *c)
{
unsigned int i;
 
int j;
 
assert(c != NULL);
 
if (c->imagemaps == NULL)
return;
 
for (i = 0; i != HASH_SIZE; i++) {
struct imagemap *map;
struct mapentry *entry;
 
map = c->imagemaps[i];
while (map != NULL) {
LOG(("Imagemap: %s", map->key));
 
for (entry = map->list; entry; entry = entry->next) {
switch (entry->type) {
case IMAGEMAP_DEFAULT:
LOG(("\tDefault: %s", nsurl_access(
entry->url)));
break;
case IMAGEMAP_RECT:
LOG(("\tRectangle: %s: [(%d,%d),(%d,%d)]",
nsurl_access(entry->url),
entry->bounds.rect.x0,
entry->bounds.rect.y0,
entry->bounds.rect.x1,
entry->bounds.rect.y1));
break;
case IMAGEMAP_CIRCLE:
LOG(("\tCircle: %s: [(%d,%d),%d]",
nsurl_access(entry->url),
entry->bounds.circle.x,
entry->bounds.circle.y,
entry->bounds.circle.r));
break;
case IMAGEMAP_POLY:
LOG(("\tPolygon: %s:", nsurl_access(
entry->url)));
for (j = 0; j != entry->bounds.poly.num;
j++) {
fprintf(stderr, "(%d,%d) ",
(int)entry->bounds.poly.xcoords[j],
(int)entry->bounds.poly.ycoords[j]);
}
fprintf(stderr,"\n");
break;
}
}
map = map->next;
}
}
}
 
/**
* Extract all imagemaps from a document tree
*
* \param c The content
* \param map_str A dom_string which is "map"
* \return false on memory exhaustion, true otherwise
*/
nserror
imagemap_extract(html_content *c)
{
dom_nodelist *nlist;
dom_exception exc;
unsigned long mapnr;
uint32_t maybe_maps;
nserror ret = NSERROR_OK;
 
exc = dom_document_get_elements_by_tag_name(c->document,
corestring_dom_map,
&nlist);
if (exc != DOM_NO_ERR) {
return NSERROR_DOM;
}
exc = dom_nodelist_get_length(nlist, &maybe_maps);
if (exc != DOM_NO_ERR) {
ret = NSERROR_DOM;
goto out_nlist;
}
for (mapnr = 0; mapnr < maybe_maps; ++mapnr) {
dom_node *node;
dom_string *name;
exc = dom_nodelist_item(nlist, mapnr, &node);
if (exc != DOM_NO_ERR) {
ret = NSERROR_DOM;
goto out_nlist;
}
exc = dom_element_get_attribute(node, corestring_dom_id,
&name);
if (exc != DOM_NO_ERR) {
dom_node_unref(node);
ret = NSERROR_DOM;
goto out_nlist;
}
if (name == NULL) {
exc = dom_element_get_attribute(node,
corestring_dom_name,
&name);
if (exc != DOM_NO_ERR) {
dom_node_unref(node);
ret = NSERROR_DOM;
goto out_nlist;
}
}
if (name != NULL) {
struct mapentry *entry = NULL;
if (imagemap_extract_map(node, c, &entry) == false) {
dom_string_unref(name);
dom_node_unref(node);
ret = NSERROR_NOMEM; /** @todo check this */
goto out_nlist;
}
/* imagemap_extract_map may not extract anything,
* so entry can still be NULL here. This isn't an
* error as it just means that we've encountered
* an incorrectly defined <map>...</map> block
*/
if ((entry != NULL) &&
(imagemap_add(c, name, entry) == false)) {
dom_string_unref(name);
dom_node_unref(node);
ret = NSERROR_NOMEM; /** @todo check this */
goto out_nlist;
}
}
dom_string_unref(name);
dom_node_unref(node);
}
out_nlist:
dom_nodelist_unref(nlist);
 
return ret;
}
 
/**
* Extract an imagemap from html source
*
* \param node XML node containing map
* \param c Content containing document
* \param entry List of map entries
* \param tname The sub-tags to consider on this pass
* \return false on memory exhaustion, true otherwise
*/
static bool
imagemap_extract_map_entries(dom_node *node, html_content *c,
struct mapentry **entry, dom_string *tname)
{
dom_nodelist *nlist;
dom_exception exc;
unsigned long ent;
uint32_t tag_count;
exc = dom_element_get_elements_by_tag_name(node, tname, &nlist);
if (exc != DOM_NO_ERR) {
return false;
}
exc = dom_nodelist_get_length(nlist, &tag_count);
if (exc != DOM_NO_ERR) {
dom_nodelist_unref(nlist);
return false;
}
for (ent = 0; ent < tag_count; ++ent) {
dom_node *subnode;
exc = dom_nodelist_item(nlist, ent, &subnode);
if (exc != DOM_NO_ERR) {
dom_nodelist_unref(nlist);
return false;
}
if (imagemap_addtolist(subnode, c->base_url,
entry, tname) == false) {
dom_node_unref(subnode);
dom_nodelist_unref(nlist);
return false;
}
dom_node_unref(subnode);
}
dom_nodelist_unref(nlist);
return true;
}
 
/**
* Extract an imagemap from html source
*
* \param node XML node containing map
* \param c Content containing document
* \param entry List of map entries
* \return false on memory exhaustion, true otherwise
*/
bool imagemap_extract_map(dom_node *node, html_content *c,
struct mapentry **entry)
{
if (imagemap_extract_map_entries(node, c, entry,
corestring_dom_area) == false)
return false;
return imagemap_extract_map_entries(node, c, entry,
corestring_dom_a);
}
/**
* Adds an imagemap entry to the list
*
* \param n The xmlNode representing the entry to add
* \param base_url Base URL for resolving relative URLs
* \param entry Pointer to list of entries
* \return false on memory exhaustion, true otherwise
*/
bool
imagemap_addtolist(dom_node *n, nsurl *base_url,
struct mapentry **entry, dom_string *tagtype)
{
dom_exception exc;
dom_string *href = NULL, *target = NULL, *shape = NULL;
dom_string *coords = NULL;
struct mapentry *new_map, *temp;
bool ret = true;
if (dom_string_caseless_isequal(tagtype, corestring_dom_area)) {
bool nohref = false;
exc = dom_element_has_attribute(n,
corestring_dom_nohref, &nohref);
if ((exc != DOM_NO_ERR) || nohref)
/* Skip <area nohref="anything" /> */
goto ok_out;
}
exc = dom_element_get_attribute(n, corestring_dom_href, &href);
if (exc != DOM_NO_ERR || href == NULL) {
/* No href="" attribute, skip this element */
goto ok_out;
}
exc = dom_element_get_attribute(n, corestring_dom_target, &target);
if (exc != DOM_NO_ERR) {
goto ok_out;
}
exc = dom_element_get_attribute(n, corestring_dom_shape, &shape);
if (exc != DOM_NO_ERR) {
goto ok_out;
}
/* If there's no shape, we default to rectangles */
if (shape == NULL)
shape = dom_string_ref(corestring_dom_rect);
if (!dom_string_caseless_lwc_isequal(shape, corestring_lwc_default)) {
/* If not 'default' and there's no 'coords' give up */
exc = dom_element_get_attribute(n, corestring_dom_coords,
&coords);
if (exc != DOM_NO_ERR || coords == NULL) {
goto ok_out;
}
}
new_map = calloc(1, sizeof(*new_map));
if (new_map == NULL) {
goto bad_out;
}
if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_rect) ||
dom_string_caseless_lwc_isequal(shape, corestring_lwc_rectangle))
new_map->type = IMAGEMAP_RECT;
else if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_circle))
new_map->type = IMAGEMAP_CIRCLE;
else if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_poly) ||
dom_string_caseless_lwc_isequal(shape, corestring_lwc_polygon))
new_map->type = IMAGEMAP_POLY;
else if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_default))
new_map->type = IMAGEMAP_DEFAULT;
else
goto bad_out;
if (box_extract_link(dom_string_data(href),
base_url, &new_map->url) == false)
goto bad_out;
if (new_map->url == NULL) {
/* non-fatal error -> ignore this */
goto ok_free_map_out;
}
if (target != NULL) {
/* Copy target into the map */
new_map->target = malloc(dom_string_byte_length(target) + 1);
if (new_map->target == NULL)
goto bad_out;
/* Safe, but relies on dom_strings being NULL terminated */
/* \todo Do this better */
strcpy(new_map->target, dom_string_data(target));
}
if (new_map->type != IMAGEMAP_DEFAULT) {
int x, y;
float *xcoords, *ycoords;
/* coordinates are a comma-separated list of values */
char *val = strtok((char *)dom_string_data(coords), ",");
int num = 1;
 
switch (new_map->type) {
case IMAGEMAP_RECT:
/* (left, top, right, bottom) */
while (val != NULL && num <= 4) {
switch (num) {
case 1:
new_map->bounds.rect.x0 = atoi(val);
break;
case 2:
new_map->bounds.rect.y0 = atoi(val);
break;
case 3:
new_map->bounds.rect.x1 = atoi(val);
break;
case 4:
new_map->bounds.rect.y1 = atoi(val);
break;
}
 
num++;
val = strtok('\0', ",");
}
break;
case IMAGEMAP_CIRCLE:
/* (x, y, radius ) */
while (val != NULL && num <= 3) {
switch (num) {
case 1:
new_map->bounds.circle.x = atoi(val);
break;
case 2:
new_map->bounds.circle.y = atoi(val);
break;
case 3:
new_map->bounds.circle.r = atoi(val);
break;
}
 
num++;
val = strtok('\0', ",");
}
break;
case IMAGEMAP_POLY:
new_map->bounds.poly.xcoords = NULL;
new_map->bounds.poly.ycoords = NULL;
 
while (val != NULL) {
x = atoi(val);
 
val = strtok('\0', ",");
if (val == NULL)
break;
 
y = atoi(val);
 
xcoords = realloc(new_map->bounds.poly.xcoords,
num * sizeof(float));
if (xcoords == NULL) {
goto bad_out;
}
 
ycoords = realloc(new_map->bounds.poly.ycoords,
num * sizeof(float));
if (ycoords == NULL) {
goto bad_out;
}
 
new_map->bounds.poly.xcoords = xcoords;
new_map->bounds.poly.ycoords = ycoords;
 
new_map->bounds.poly.xcoords[num - 1] = x;
new_map->bounds.poly.ycoords[num - 1] = y;
 
num++;
val = strtok('\0', ",");
}
 
new_map->bounds.poly.num = num - 1;
 
break;
default:
break;
}
}
new_map->next = NULL;
 
if (entry && *entry) {
/* add to END of list */
for (temp = (*entry); temp->next != NULL; temp = temp->next)
;
temp->next = new_map;
}
else {
(*entry) = new_map;
}
/* All good, linked in, let's clean up */
goto ok_out;
bad_out:
ret = false;
ok_free_map_out:
if (new_map->url != NULL)
nsurl_unref(new_map->url);
if (new_map->type == IMAGEMAP_POLY &&
new_map->bounds.poly.ycoords != NULL)
free(new_map->bounds.poly.ycoords);
if (new_map->type == IMAGEMAP_POLY &&
new_map->bounds.poly.xcoords != NULL)
free(new_map->bounds.poly.xcoords);
if (new_map->target != NULL)
free(new_map->target);
if (new_map != NULL)
free(new_map);
ok_out:
if (href != NULL)
dom_string_unref(href);
if (target != NULL)
dom_string_unref(target);
if (shape != NULL)
dom_string_unref(shape);
if (coords != NULL)
dom_string_unref(coords);
return ret;
}
 
/**
* Free list of imagemap entries
*
* \param list Pointer to head of list
*/
void imagemap_freelist(struct mapentry *list)
{
struct mapentry *entry, *prev;
 
assert(list != NULL);
 
entry = list;
 
while (entry != NULL) {
prev = entry;
 
nsurl_unref(entry->url);
 
if (entry->target)
free(entry->target);
 
if (entry->type == IMAGEMAP_POLY) {
free(entry->bounds.poly.xcoords);
free(entry->bounds.poly.ycoords);
}
 
entry = entry->next;
free(prev);
}
}
 
/**
* Retrieve url associated with imagemap entry
*
* \param h The containing content
* \param key The map name to search for
* \param x The left edge of the containing box
* \param y The top edge of the containing box
* \param click_x The horizontal location of the click
* \param click_y The vertical location of the click
* \param target Pointer to location to receive target pointer (if any)
* \return The url associated with this area, or NULL if not found
*/
nsurl *imagemap_get(struct html_content *c, const char *key,
unsigned long x, unsigned long y,
unsigned long click_x, unsigned long click_y,
const char **target)
{
unsigned int slot = 0;
struct imagemap *map;
struct mapentry *entry;
unsigned long cx, cy;
 
assert(c != NULL);
 
if (key == NULL)
return NULL;
 
if (c->imagemaps == NULL)
return NULL;
 
slot = imagemap_hash(key);
 
for (map = c->imagemaps[slot]; map != NULL; map = map->next) {
if (map->key != NULL && strcasecmp(map->key, key) == 0)
break;
}
 
if (map == NULL || map->list == NULL)
return NULL;
 
for (entry = map->list; entry; entry = entry->next) {
switch (entry->type) {
case IMAGEMAP_DEFAULT:
/* just return the URL. no checks required */
if (target)
*target = entry->target;
return entry->url;
break;
case IMAGEMAP_RECT:
if (click_x >= x + entry->bounds.rect.x0 &&
click_x <= x + entry->bounds.rect.x1 &&
click_y >= y + entry->bounds.rect.y0 &&
click_y <= y + entry->bounds.rect.y1) {
if (target)
*target = entry->target;
return entry->url;
}
break;
case IMAGEMAP_CIRCLE:
cx = x + entry->bounds.circle.x - click_x;
cy = y + entry->bounds.circle.y - click_y;
if ((cx * cx + cy * cy) <=
(unsigned long) (entry->bounds.circle.r *
entry->bounds.circle.r)) {
if (target)
*target = entry->target;
return entry->url;
}
break;
case IMAGEMAP_POLY:
if (imagemap_point_in_poly(entry->bounds.poly.num,
entry->bounds.poly.xcoords,
entry->bounds.poly.ycoords, x, y,
click_x, click_y)) {
if (target)
*target = entry->target;
return entry->url;
}
break;
}
}
 
if (target)
*target = NULL;
 
return NULL;
}
 
/**
* Hash function
*
* \param key The key to hash
* \return The hashed value
*/
unsigned int imagemap_hash(const char *key)
{
unsigned int z = 0;
 
if (key == 0) return 0;
 
for (; *key != 0; key++) {
z += *key & 0x1f;
}
 
return (z % (HASH_SIZE - 1)) + 1;
}
 
/**
* Test if a point lies within an arbitrary polygon
* Modified from comp.graphics.algorithms FAQ 2.03
*
* \param num Number of vertices
* \param xpt Array of x coordinates
* \param ypt Array of y coordinates
* \param x Left hand edge of containing box
* \param y Top edge of containing box
* \param click_x X coordinate of click
* \param click_y Y coordinate of click
* \return 1 if point is in polygon, 0 if outside. 0 or 1 if on boundary
*/
int imagemap_point_in_poly(int num, float *xpt, float *ypt, unsigned long x,
unsigned long y, unsigned long click_x,
unsigned long click_y)
{
int i, j, c = 0;
 
assert(xpt != NULL);
assert(ypt != NULL);
 
for (i = 0, j = num - 1; i < num; j = i++) {
if ((((ypt[i] + y <= click_y) && (click_y < ypt[j] + y)) ||
((ypt[j] + y <= click_y) && (click_y < ypt[i] + y))) &&
(click_x < (xpt[j] - xpt[i]) *
(click_y - (ypt[i] + y)) / (ypt[j] - ypt[i]) + xpt[i] + x))
c = !c;
}
 
return c;
}
/programs/network/netsurf/netsurf/render/imagemap.h
0,0 → 1,38
/*
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef _NETSURF_RENDER_IMAGEMAP_H_
#define _NETSURF_RENDER_IMAGEMAP_H_
 
#include <dom/dom.h>
 
#include "utils/nsurl.h"
 
struct html_content;
struct hlcache_handle;
 
void imagemap_destroy(struct html_content *c);
void imagemap_dump(struct html_content *c);
nserror imagemap_extract(struct html_content *c);
 
nsurl *imagemap_get(struct html_content *c, const char *key,
unsigned long x, unsigned long y,
unsigned long click_x, unsigned long click_y,
const char **target);
 
#endif
/programs/network/netsurf/netsurf/render/layout.c
0,0 → 1,5077
/*
* Copyright 2005 Richard Wilson <info@tinct.net>
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
* Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* HTML layout (implementation).
*
* Layout is carried out in two stages:
*
* 1. + calculation of minimum / maximum box widths, and
* + determination of whether block level boxes will have >zero height
*
* 2. + layout (position and dimensions)
*
* In most cases the functions for the two stages are a corresponding pair
* layout_minmax_X() and layout_X().
*/
 
#include <assert.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <dom/dom.h>
#include "css/css.h"
#include "css/utils.h"
#include "content/content_protected.h"
#include "desktop/options.h"
#include "desktop/scrollbar.h"
#include "render/box.h"
#include "render/font.h"
#include "render/form.h"
#include "render/html_internal.h"
#include "render/layout.h"
#include "render/table.h"
#include "utils/log.h"
#include "utils/talloc.h"
#include "utils/utils.h"
 
 
/* Define to enable layout debugging */
#undef LAYOUT_DEBUG
 
#define AUTO INT_MIN
 
/* Fixed point value percentage of an integer, to an integer */
#define FPCT_OF_INT_TOINT(a, b) FIXTOINT(FMUL(FDIV(a, F_100), INTTOFIX(b)))
 
 
static bool layout_block_context(struct box *block, int viewport_height,
html_content *content);
static void layout_minmax_block(struct box *block,
const struct font_functions *font_func);
static struct box* layout_next_margin_block(struct box *box, struct box *block,
int viewport_height, int *max_pos_margin, int *max_neg_margin);
static bool layout_block_object(struct box *block);
static void layout_get_object_dimensions(struct box *box,
int *width, int *height, int min_width, int max_width);
static void layout_block_find_dimensions(int available_width,
int viewport_height, int lm, int rm,
struct box *box);
static bool layout_apply_minmax_height(struct box *box, struct box *container);
static void layout_block_add_scrollbar(struct box *box, int which);
static int layout_solve_width(struct box *box, int available_width, int width,
int lm, int rm, int max_width, int min_width);
static void layout_float_find_dimensions(int available_width,
const css_computed_style *style, struct box *box);
static void layout_find_dimensions(int available_width, int viewport_height,
struct box *box, const css_computed_style *style,
int *width, int *height, int *max_width, int *min_width,
int margin[4], int padding[4], struct box_border border[4]);
static void layout_tweak_form_dimensions(struct box *box, bool percentage,
int available_width, bool setwidth, int *dimension);
static int layout_clear(struct box *fl, enum css_clear_e clear);
static void find_sides(struct box *fl, int y0, int y1,
int *x0, int *x1, struct box **left, struct box **right);
static void layout_minmax_inline_container(struct box *inline_container,
bool *has_height, const struct font_functions *font_func);
static int line_height(const css_computed_style *style);
static bool layout_line(struct box *first, int *width, int *y,
int cx, int cy, struct box *cont, bool indent,
bool has_text_children,
html_content *content, struct box **next_box);
static struct box *layout_minmax_line(struct box *first, int *min, int *max,
bool first_line, bool *line_has_height,
const struct font_functions *font_func);
static int layout_text_indent(const css_computed_style *style, int width);
static bool layout_float(struct box *b, int width, html_content *content);
static void place_float_below(struct box *c, int width, int cx, int y,
struct box *cont);
static bool layout_table(struct box *box, int available_width,
html_content *content);
static void layout_move_children(struct box *box, int x, int y);
static void calculate_mbp_width(const css_computed_style *style,
unsigned int side, bool margin, bool border, bool padding,
int *fixed, float *frac);
static void layout_lists(struct box *box,
const struct font_functions *font_func);
static void layout_position_relative(struct box *root, struct box *fp,
int fx, int fy);
static void layout_compute_relative_offset(struct box *box, int *x, int *y);
static bool layout_position_absolute(struct box *box,
struct box *containing_block,
int cx, int cy,
html_content *content);
static bool layout_absolute(struct box *box, struct box *containing_block,
int cx, int cy,
html_content *content);
static void layout_compute_offsets(struct box *box,
struct box *containing_block,
int *top, int *right, int *bottom, int *left);
 
 
/**
* Calculate positions of boxes in a document.
*
* \param doc content of type CONTENT_HTML
* \param width available width
* \param height available height
* \return true on success, false on memory exhaustion
*/
 
bool layout_document(html_content *content, int width, int height)
{
bool ret;
struct box *doc = content->layout;
const struct font_functions *font_func = content->font_func;
 
layout_minmax_block(doc, font_func);
 
layout_block_find_dimensions(width, height, 0, 0, doc);
doc->x = doc->margin[LEFT] + doc->border[LEFT].width;
doc->y = doc->margin[TOP] + doc->border[TOP].width;
width -= doc->margin[LEFT] + doc->border[LEFT].width +
doc->padding[LEFT] + doc->padding[RIGHT] +
doc->border[RIGHT].width + doc->margin[RIGHT];
if (width < 0)
width = 0;
doc->width = width;
 
ret = layout_block_context(doc, height, content);
 
/* make <html> and <body> fill available height */
if (doc->y + doc->padding[TOP] + doc->height + doc->padding[BOTTOM] +
doc->border[BOTTOM].width + doc->margin[BOTTOM] <
height) {
doc->height = height - (doc->y + doc->padding[TOP] +
doc->padding[BOTTOM] +
doc->border[BOTTOM].width +
doc->margin[BOTTOM]);
if (doc->children)
doc->children->height = doc->height -
(doc->children->margin[TOP] +
doc->children->border[TOP].width +
doc->children->padding[TOP] +
doc->children->padding[BOTTOM] +
doc->children->border[BOTTOM].width +
doc->children->margin[BOTTOM]);
}
 
layout_lists(doc, font_func);
layout_position_absolute(doc, doc, 0, 0, content);
layout_position_relative(doc, doc, 0, 0);
 
layout_calculate_descendant_bboxes(doc);
 
return ret;
}
 
 
/**
* Layout a block formatting context.
*
* \param block BLOCK, INLINE_BLOCK, or TABLE_CELL to layout
* \param viewport_height Height of viewport in pixels or -ve if unknown
* \param content Memory pool for any new boxes
* \return true on success, false on memory exhaustion
*
* This function carries out layout of a block and its children, as described
* in CSS 2.1 9.4.1.
*/
 
bool layout_block_context(struct box *block, int viewport_height,
html_content *content)
{
struct box *box;
int cx, cy; /**< current coordinates */
int max_pos_margin = 0;
int max_neg_margin = 0;
int y = 0;
int lm, rm;
struct box *margin_collapse = NULL;
bool in_margin = false;
css_fixed gadget_size;
css_unit gadget_unit; /* Checkbox / radio buttons */
 
assert(block->type == BOX_BLOCK ||
block->type == BOX_INLINE_BLOCK ||
block->type == BOX_TABLE_CELL);
assert(block->width != UNKNOWN_WIDTH);
assert(block->width != AUTO);
 
block->float_children = NULL;
block->clear_level = 0;
 
/* special case if the block contains an object */
if (block->object) {
int temp_width = block->width;
if (!layout_block_object(block))
return false;
layout_get_object_dimensions(block, &temp_width,
&block->height, INT_MIN, INT_MAX);
return true;
} else if (block->flags & REPLACE_DIM) {
return true;
}
 
/* special case if the block contains an radio button or checkbox */
if (block->gadget && (block->gadget->type == GADGET_RADIO ||
block->gadget->type == GADGET_CHECKBOX)) {
/* form checkbox or radio button
* if width or height is AUTO, set it to 1em */
gadget_unit = CSS_UNIT_EM;
gadget_size = INTTOFIX(1);
if (block->height == AUTO)
block->height = FIXTOINT(nscss_len2px(gadget_size,
gadget_unit, block->style));
}
 
box = block->children;
/* set current coordinates to top-left of the block */
cx = 0;
y = cy = block->padding[TOP];
if (box)
box->y = block->padding[TOP];
 
/* Step through the descendants of the block in depth-first order, but
* not into the children of boxes which aren't blocks. For example, if
* the tree passed to this function looks like this (box->type shown):
*
* block -> BOX_BLOCK
* BOX_BLOCK * (1)
* BOX_INLINE_CONTAINER * (2)
* BOX_INLINE
* BOX_TEXT
* ...
* BOX_BLOCK * (3)
* BOX_TABLE * (4)
* BOX_TABLE_ROW
* BOX_TABLE_CELL
* ...
* BOX_TABLE_CELL
* ...
* BOX_BLOCK * (5)
* BOX_INLINE_CONTAINER * (6)
* BOX_TEXT
* ...
* then the while loop will visit each box marked with *, setting box
* to each in the order shown. */
while (box) {
assert(box->type == BOX_BLOCK || box->type == BOX_TABLE ||
box->type == BOX_INLINE_CONTAINER);
 
/* Tables are laid out before being positioned, because the
* position depends on the width which is calculated in
* table layout. Blocks and inline containers are positioned
* before being laid out, because width is not dependent on
* content, and the position is required during layout for
* correct handling of floats.
*/
 
if (box->style &&
(css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE ||
css_computed_position(box->style) ==
CSS_POSITION_FIXED)) {
box->x = box->parent->padding[LEFT];
/* absolute positioned; this element will establish
* its own block context when it gets laid out later,
* so no need to look at its children now. */
goto advance_to_next_box;
}
 
/* If we don't know which box the current margin collapses
* through to, find out. Update the pos/neg margin values. */
if (margin_collapse == NULL) {
margin_collapse = layout_next_margin_block(box, block,
viewport_height,
&max_pos_margin, &max_neg_margin);
/* We have a margin that has not yet been applied. */
in_margin = true;
}
 
/* Clearance. */
y = 0;
if (box->style && css_computed_clear(box->style) !=
CSS_CLEAR_NONE)
y = layout_clear(block->float_children,
css_computed_clear(box->style));
 
/* Blocks establishing a block formatting context get minimum
* left and right margins to avoid any floats. */
lm = rm = 0;
 
if (box->type == BOX_BLOCK || box->flags & IFRAME) {
if (!box->object && !(box->flags & IFRAME) &&
!(box->flags & REPLACE_DIM) &&
box->style &&
css_computed_overflow(box->style) !=
CSS_OVERFLOW_VISIBLE) {
/* box establishes new block formatting context
* so available width may be diminished due to
* floats. */
int x0, x1, top;
struct box *left, *right;
top = cy + max_pos_margin - max_neg_margin;
top = (top > y) ? top : y;
x0 = cx;
x1 = cx + box->parent->width -
box->parent->padding[LEFT] -
box->parent->padding[RIGHT];
find_sides(block->float_children, top, top,
&x0, &x1, &left, &right);
/* calculate min required left & right margins
* needed to avoid floats */
lm = x0 - cx;
rm = cx + box->parent->width -
box->parent->padding[LEFT] -
box->parent->padding[RIGHT] -
x1;
}
layout_block_find_dimensions(box->parent->width,
viewport_height, lm, rm, box);
if (box->type == BOX_BLOCK && !(box->flags & IFRAME)) {
layout_block_add_scrollbar(box, RIGHT);
layout_block_add_scrollbar(box, BOTTOM);
}
} else if (box->type == BOX_TABLE) {
if (box->style != NULL) {
enum css_width_e wtype;
css_fixed width = 0;
css_unit unit = CSS_UNIT_PX;
 
wtype = css_computed_width(box->style, &width,
&unit);
 
if (wtype == CSS_WIDTH_AUTO) {
/* max available width may be
* diminished due to floats. */
int x0, x1, top;
struct box *left, *right;
top = cy + max_pos_margin -
max_neg_margin;
top = (top > y) ? top : y;
x0 = cx;
x1 = cx + box->parent->width -
box->parent->padding[LEFT] -
box->parent->padding[RIGHT];
find_sides(block->float_children,
top, top, &x0, &x1,
&left, &right);
/* calculate min required left & right
* margins needed to avoid floats */
lm = x0 - cx;
rm = cx + box->parent->width -
box->parent->padding[LEFT] -
box->parent->padding[RIGHT] -
x1;
}
}
if (!layout_table(box, box->parent->width - lm - rm,
content))
return false;
layout_solve_width(box, box->parent->width, box->width,
lm, rm, -1, -1);
}
 
/* Position box: horizontal. */
box->x = box->parent->padding[LEFT] + box->margin[LEFT] +
box->border[LEFT].width;
cx += box->x;
 
/* Position box: vertical. */
if (box->border[TOP].width) {
box->y += box->border[TOP].width;
cy += box->border[TOP].width;
}
 
/* Vertical margin */
if (((box->type == BOX_BLOCK &&
(box->flags & HAS_HEIGHT)) ||
box->type == BOX_TABLE ||
(box->type == BOX_INLINE_CONTAINER &&
box != box->parent->children) ||
margin_collapse == box) &&
in_margin == true) {
/* Margin goes above this box. */
cy += max_pos_margin - max_neg_margin;
box->y += max_pos_margin - max_neg_margin;
 
/* Current margin has been applied. */
in_margin = false;
max_pos_margin = max_neg_margin = 0;
}
 
/* Handle clearance */
if (box->type != BOX_INLINE_CONTAINER &&
(y > 0) && (cy < y)) {
/* box clears something*/
box->y += y - cy;
cy = y;
}
 
/* Unless the box has an overflow style of visible, the box
* establishes a new block context. */
if (box->type == BOX_BLOCK && box->style &&
css_computed_overflow(box->style) !=
CSS_OVERFLOW_VISIBLE) {
 
layout_block_context(box, viewport_height, content);
 
cy += box->padding[TOP];
 
if (box->height == AUTO) {
box->height = 0;
layout_block_add_scrollbar(box, BOTTOM);
}
 
cx -= box->x;
cy += box->height + box->padding[BOTTOM] +
box->border[BOTTOM].width;
y = box->y + box->padding[TOP] + box->height +
box->padding[BOTTOM] +
box->border[BOTTOM].width;
 
/* Skip children, because they are done in the new
* block context */
goto advance_to_next_box;
}
 
#ifdef LAYOUT_DEBUG
LOG(("box %p, cx %i, cy %i", box, cx, cy));
#endif
 
/* Layout (except tables). */
if (box->object) {
if (!layout_block_object(box))
return false;
 
} else if (box->type == BOX_INLINE_CONTAINER) {
box->width = box->parent->width;
if (!layout_inline_container(box, box->width, block,
cx, cy, content))
return false;
 
} else if (box->type == BOX_TABLE) {
/* Move down to avoid floats if necessary. */
int x0, x1;
struct box *left, *right;
y = cy;
while (1) {
enum css_width_e wtype;
css_fixed width = 0;
css_unit unit = CSS_UNIT_PX;
 
wtype = css_computed_width(box->style,
&width, &unit);
 
x0 = cx;
x1 = cx + box->parent->width;
find_sides(block->float_children, y,
y + box->height,
&x0, &x1, &left, &right);
if (wtype == CSS_WIDTH_AUTO)
break;
if (box->width <= x1 - x0)
break;
if (!left && !right)
break;
else if (!left)
y = right->y + right->height + 1;
else if (!right)
y = left->y + left->height + 1;
else if (left->y + left->height <
right->y + right->height)
y = left->y + left->height + 1;
else
y = right->y + right->height + 1;
}
box->x += x0 - cx;
cx = x0;
box->y += y - cy;
cy = y;
}
 
/* Advance to next box. */
if (box->type == BOX_BLOCK && !box->object && !(box->iframe) &&
box->children) {
/* Down into children. */
 
if (box == margin_collapse) {
/* Current margin collapsed though to this box.
* Unset margin_collapse. */
margin_collapse = NULL;
}
 
y = box->padding[TOP];
box = box->children;
box->y = y;
cy += y;
continue;
} else if (box->type == BOX_BLOCK || box->object ||
box->flags & IFRAME)
cy += box->padding[TOP];
 
if (box->type == BOX_BLOCK && box->height == AUTO) {
box->height = 0;
layout_block_add_scrollbar(box, BOTTOM);
}
 
cy += box->height + box->padding[BOTTOM] +
box->border[BOTTOM].width;
cx -= box->x;
y = box->y + box->padding[TOP] + box->height +
box->padding[BOTTOM] +
box->border[BOTTOM].width;
 
advance_to_next_box:
if (!box->next) {
/* No more siblings:
* up to first ancestor with a sibling. */
 
do {
if (box == margin_collapse) {
/* Current margin collapsed though to
* this box. Unset margin_collapse. */
margin_collapse = NULL;
}
 
/* Apply bottom margin */
if (max_pos_margin < box->margin[BOTTOM])
max_pos_margin = box->margin[BOTTOM];
else if (max_neg_margin < -box->margin[BOTTOM])
max_neg_margin = -box->margin[BOTTOM];
 
box = box->parent;
if (box == block)
break;
 
/* Margin is invalidated if this is a box
* margins can't collapse through. */
if (box->type == BOX_BLOCK &&
box->flags & MAKE_HEIGHT) {
margin_collapse = NULL;
in_margin = false;
max_pos_margin = max_neg_margin = 0;
}
 
if (box->height == AUTO) {
box->height = y - box->padding[TOP];
 
if (box->type == BOX_BLOCK)
layout_block_add_scrollbar(box,
BOTTOM);
} else
cy += box->height -
(y - box->padding[TOP]);
 
/* Apply any min-height and max-height to
* boxes in normal flow */
if (box->style &&
css_computed_position(box->style) !=
CSS_POSITION_ABSOLUTE &&
layout_apply_minmax_height(box,
NULL)) {
/* Height altered */
/* Set current cy */
cy += box->height -
(y - box->padding[TOP]);
}
 
cy += box->padding[BOTTOM] +
box->border[BOTTOM].width;
cx -= box->x;
y = box->y + box->padding[TOP] + box->height +
box->padding[BOTTOM] +
box->border[BOTTOM].width;
 
} while (box->next == NULL);
if (box == block)
break;
}
 
/* To next sibling. */
 
if (box == margin_collapse) {
/* Current margin collapsed though to this box.
* Unset margin_collapse. */
margin_collapse = NULL;
}
 
if (max_pos_margin < box->margin[BOTTOM])
max_pos_margin = box->margin[BOTTOM];
else if (max_neg_margin < -box->margin[BOTTOM])
max_neg_margin = -box->margin[BOTTOM];
 
box = box->next;
box->y = y;
}
 
/* Account for bottom margin of last contained block */
cy += max_pos_margin - max_neg_margin;
 
/* Increase height to contain any floats inside (CSS 2.1 10.6.7). */
for (box = block->float_children; box; box = box->next_float) {
y = box->y + box->height + box->padding[BOTTOM] +
box->border[BOTTOM].width + box->margin[BOTTOM];
if (cy < y)
cy = y;
}
 
if (block->height == AUTO) {
block->height = cy - block->padding[TOP];
if (block->type == BOX_BLOCK)
layout_block_add_scrollbar(block, BOTTOM);
}
 
if (block->style && css_computed_position(block->style) !=
CSS_POSITION_ABSOLUTE) {
/* Block is in normal flow */
layout_apply_minmax_height(block, NULL);
}
 
return true;
}
 
 
/**
* Calculate minimum and maximum width of a block.
*
* \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
* \post block->min_width and block->max_width filled in,
* 0 <= block->min_width <= block->max_width
*/
 
void layout_minmax_block(struct box *block,
const struct font_functions *font_func)
{
struct box *child;
int min = 0, max = 0;
int extra_fixed = 0;
float extra_frac = 0;
enum css_width_e wtype = CSS_WIDTH_AUTO;
css_fixed width = 0;
css_unit wunit = CSS_UNIT_PX;
enum css_height_e htype = CSS_HEIGHT_AUTO;
css_fixed height = 0;
css_unit hunit = CSS_UNIT_PX;
bool child_has_height = false;
 
assert(block->type == BOX_BLOCK ||
block->type == BOX_INLINE_BLOCK ||
block->type == BOX_TABLE_CELL);
 
/* check if the widths have already been calculated */
if (block->max_width != UNKNOWN_MAX_WIDTH)
return;
 
if (block->style != NULL) {
wtype = css_computed_width(block->style, &width, &wunit);
htype = css_computed_height(block->style, &height, &hunit);
}
 
/* set whether the minimum width is of any interest for this box */
if (((block->parent && (block->parent->type == BOX_FLOAT_LEFT ||
block->parent->type == BOX_FLOAT_RIGHT)) ||
block->type == BOX_INLINE_BLOCK) &&
wtype != CSS_WIDTH_SET) {
/* box shrinks to fit; need minimum width */
block->flags |= NEED_MIN;
} else if (block->type == BOX_TABLE_CELL) {
/* box shrinks to fit; need minimum width */
block->flags |= NEED_MIN;
} else if (block->parent && (block->parent->flags & NEED_MIN) &&
wtype != CSS_WIDTH_SET) {
/* box inside shrink-to-fit context; need minimum width */
block->flags |= NEED_MIN;
}
 
if (block->gadget && (block->gadget->type == GADGET_TEXTBOX ||
block->gadget->type == GADGET_PASSWORD ||
block->gadget->type == GADGET_FILE ||
block->gadget->type == GADGET_TEXTAREA) &&
block->style && wtype == CSS_WIDTH_AUTO) {
css_fixed size = INTTOFIX(10);
css_unit unit = CSS_UNIT_EM;
 
min = max = FIXTOINT(nscss_len2px(size, unit, block->style));
 
block->flags |= HAS_HEIGHT;
}
 
if (block->gadget && (block->gadget->type == GADGET_RADIO ||
block->gadget->type == GADGET_CHECKBOX) &&
block->style && wtype == CSS_WIDTH_AUTO) {
css_fixed size = INTTOFIX(1);
css_unit unit = CSS_UNIT_EM;
 
/* form checkbox or radio button
* if width is AUTO, set it to 1em */
min = max = FIXTOINT(nscss_len2px(size, unit, block->style));
 
block->flags |= HAS_HEIGHT;
}
 
if (block->object) {
if (content_get_type(block->object) == CONTENT_HTML) {
layout_minmax_block(html_get_box_tree(block->object),
font_func);
min = html_get_box_tree(block->object)->min_width;
max = html_get_box_tree(block->object)->max_width;
} else {
min = max = content_get_width(block->object);
}
 
block->flags |= HAS_HEIGHT;
} else if (block->flags & IFRAME) {
/** TODO: do we need to know the min/max width of the iframe's
* content? */
block->flags |= HAS_HEIGHT;
} else {
/* recurse through children */
for (child = block->children; child; child = child->next) {
switch (child->type) {
case BOX_BLOCK:
layout_minmax_block(child, font_func);
if (child->flags & HAS_HEIGHT)
child_has_height = true;
break;
case BOX_INLINE_CONTAINER:
if (block->flags & NEED_MIN)
child->flags |= NEED_MIN;
 
layout_minmax_inline_container(child,
&child_has_height, font_func);
if (child_has_height &&
child ==
child->parent->children) {
block->flags |= MAKE_HEIGHT;
}
break;
case BOX_TABLE:
layout_minmax_table(child, font_func);
/* todo: fix for zero height tables */
child_has_height = true;
child->flags |= MAKE_HEIGHT;
break;
default:
assert(0);
}
assert(child->max_width != UNKNOWN_MAX_WIDTH);
 
if (child->style &&
(css_computed_position(child->style) ==
CSS_POSITION_ABSOLUTE ||
css_computed_position(child->style) ==
CSS_POSITION_FIXED)) {
/* This child is positioned out of normal flow,
* so it will have no affect on width */
continue;
}
 
if (min < child->min_width)
min = child->min_width;
if (max < child->max_width)
max = child->max_width;
 
if (child_has_height)
block->flags |= HAS_HEIGHT;
}
}
 
if (max < min) {
box_dump(stderr, block, 0);
assert(0);
}
 
/* fixed width takes priority */
if (block->type != BOX_TABLE_CELL && wtype == CSS_WIDTH_SET &&
wunit != CSS_UNIT_PCT) {
min = max = FIXTOINT(nscss_len2px(width, wunit, block->style));
}
 
if (htype == CSS_HEIGHT_SET && hunit != CSS_UNIT_PCT &&
height > INTTOFIX(0)) {
block->flags |= MAKE_HEIGHT;
block->flags |= HAS_HEIGHT;
}
 
/* add margins, border, padding to min, max widths */
/* Note: we don't know available width here so percentage margin
* and paddings are wrong. */
if (block->gadget && wtype == CSS_WIDTH_SET &&
(block->gadget->type == GADGET_SUBMIT ||
block->gadget->type == GADGET_RESET ||
block->gadget->type == GADGET_BUTTON)) {
/* some gadgets with specified width already include border and
* padding, so just get margin */
calculate_mbp_width(block->style, LEFT, true, false, false,
&extra_fixed, &extra_frac);
calculate_mbp_width(block->style, RIGHT, true, false, false,
&extra_fixed, &extra_frac);
} else {
calculate_mbp_width(block->style, LEFT, true, true, true,
&extra_fixed, &extra_frac);
calculate_mbp_width(block->style, RIGHT, true, true, true,
&extra_fixed, &extra_frac);
}
if (extra_fixed < 0)
extra_fixed = 0;
if (extra_frac < 0)
extra_frac = 0;
if (1.0 <= extra_frac)
extra_frac = 0.9;
if (block->style != NULL &&
(css_computed_float(block->style) == CSS_FLOAT_LEFT ||
css_computed_float(block->style) == CSS_FLOAT_RIGHT)) {
/* floated boxs */
block->min_width = min + extra_fixed;
block->max_width = max + extra_fixed;
} else {
/* not floated */
block->min_width = (min + extra_fixed) / (1.0 - extra_frac);
block->max_width = (max + extra_fixed) / (1.0 - extra_frac);
}
 
assert(0 <= block->min_width && block->min_width <= block->max_width);
}
 
 
/**
* Find next block that current margin collapses to.
*
* \param box box to start tree-order search from (top margin is included)
* \param block box responsible for current block fromatting context
* \param viewport_height height of viewport in px
* \param max_pos_margin updated to to maximum positive margin encountered
* \param max_neg_margin updated to to maximum negative margin encountered
* \return next box that current margin collapses to, or NULL if none.
*/
 
struct box* layout_next_margin_block(struct box *box, struct box *block,
int viewport_height, int *max_pos_margin, int *max_neg_margin)
{
assert(block != NULL);
 
while (box != NULL) {
 
if (box->type == BOX_INLINE_CONTAINER || (box->style &&
(css_computed_position(box->style) !=
CSS_POSITION_ABSOLUTE &&
css_computed_position(box->style) !=
CSS_POSITION_FIXED))) {
/* Not positioned */
 
/* Get margins */
if (box->style) {
layout_find_dimensions(box->parent->width,
viewport_height, box,
box->style,
NULL, NULL, NULL, NULL,
box->margin, box->padding,
box->border);
 
/* Apply top margin */
if (*max_pos_margin < box->margin[TOP])
*max_pos_margin = box->margin[TOP];
else if (*max_neg_margin < -box->margin[TOP])
*max_neg_margin = -box->margin[TOP];
}
 
/* Check whether box is the box current margin collapses
* to */
if (box->flags & MAKE_HEIGHT ||
box->border[TOP].width ||
box->padding[TOP] ||
(box->style &&
css_computed_overflow(box->style) !=
CSS_OVERFLOW_VISIBLE) ||
(box->type == BOX_INLINE_CONTAINER &&
box != box->parent->children)) {
/* Collapse to this box; return it */
return box;
}
}
 
 
/* Find next box */
if (box->type == BOX_BLOCK && !box->object && box->children &&
box->style &&
css_computed_overflow(box->style) ==
CSS_OVERFLOW_VISIBLE) {
/* Down into children. */
box = box->children;
} else {
if (!box->next) {
/* No more siblings:
* Go up to first ancestor with a sibling. */
do {
/* Apply bottom margin */
if (*max_pos_margin <
box->margin[BOTTOM])
*max_pos_margin =
box->margin[BOTTOM];
else if (*max_neg_margin <
-box->margin[BOTTOM])
*max_neg_margin =
-box->margin[BOTTOM];
 
box = box->parent;
} while (box != block && !box->next);
 
if (box == block) {
/* Margins don't collapse with stuff
* outside the block formatting context
*/
return block;
}
}
 
/* Apply bottom margin */
if (*max_pos_margin < box->margin[BOTTOM])
*max_pos_margin = box->margin[BOTTOM];
else if (*max_neg_margin < -box->margin[BOTTOM])
*max_neg_margin = -box->margin[BOTTOM];
 
/* To next sibling. */
box = box->next;
 
/* Get margins */
if (box->style) {
layout_find_dimensions(box->parent->width,
viewport_height, box,
box->style,
NULL, NULL, NULL, NULL,
box->margin, box->padding,
box->border);
}
}
}
 
return NULL;
}
 
 
/**
* Layout a block which contains an object.
*
* \param block box of type BLOCK, INLINE_BLOCK, TABLE, or TABLE_CELL
* \return true on success, false on memory exhaustion
*/
 
bool layout_block_object(struct box *block)
{
assert(block);
assert(block->type == BOX_BLOCK ||
block->type == BOX_INLINE_BLOCK ||
block->type == BOX_TABLE ||
block->type == BOX_TABLE_CELL);
assert(block->object);
 
#ifdef LAYOUT_DEBUG
LOG(("block %p, object %s, width %i", block,
hlcache_handle_get_url(block->object), block->width));
#endif
 
if (content_get_type(block->object) == CONTENT_HTML) {
content_reformat(block->object, false, block->width, 1);
} else {
/* Non-HTML objects */
/* this case handled already in
* layout_block_find_dimensions() */
}
 
return true;
}
 
 
/**
* Compute the size of replaced boxes with auto dimensions, according to
* content.
*
* \param box Box with object
* \param width Width value in px or AUTO. If AUTO, updated to value in px.
* \param height Height value in px or AUTO. If AUTO, updated to value in px.
* \param min_width Box's min width, as given by layout_find_dimensions.
* \param max_width Box's max width, as given by layout_find_dimensions.
*
* See CSS 2.1 sections 10.3 and 10.6.
*/
 
void layout_get_object_dimensions(struct box *box, int *width, int *height,
int min_width, int max_width)
{
assert(box->object != NULL);
assert(width != NULL && height != NULL);
 
if (*width == AUTO && *height == AUTO) {
/* No given dimensions */
 
bool scaled = false;
int intrinsic_width = content_get_width(box->object);
int intrinsic_height = content_get_height(box->object);
 
/* use intrinsic dimensions */
*width = intrinsic_width;
*height = intrinsic_height;
 
if (min_width > 0 && min_width > *width) {
*width = min_width;
scaled = true;
}
if (max_width >= 0 && max_width < *width) {
*width = max_width;
scaled = true;
}
 
if (scaled)
*height = (*width * intrinsic_height) /
intrinsic_width;
 
} else if (*width == AUTO) {
/* Have given height; width is calculated from the given height
* and ratio of intrinsic dimensions */
int intrinsic_width = content_get_width(box->object);
int intrinsic_height = content_get_height(box->object);
 
if (intrinsic_height != 0)
*width = (*height * intrinsic_width) /
intrinsic_height;
else
*width = intrinsic_width;
 
if (min_width > 0 && min_width > *width)
*width = min_width;
if (max_width >= 0 && max_width < *width)
*width = max_width;
 
} else if (*height == AUTO) {
/* Have given width; height is calculated from the given width
* and ratio of intrinsic dimensions */
int intrinsic_width = content_get_width(box->object);
int intrinsic_height = content_get_height(box->object);
 
if (intrinsic_width != 0)
*height = (*width * intrinsic_height) /
intrinsic_width;
else
*height = intrinsic_height;
}
}
 
 
/**
* Compute dimensions of box, margins, paddings, and borders for a block-level
* element.
*
* \param available_width Max width available in pixels
* \param viewport_height Height of viewport in pixels or -ve if unknown
* \param lm min left margin required to avoid floats in px.
* zero if not applicable
* \param rm min right margin required to avoid floats in px.
* zero if not applicable
* \param box box to find dimensions of. updated with new width,
* height, margins, borders and paddings
*
* See CSS 2.1 10.3.3, 10.3.4, 10.6.2, and 10.6.3.
*/
 
void layout_block_find_dimensions(int available_width, int viewport_height,
int lm, int rm, struct box *box)
{
int width, max_width, min_width;
int height;
int *margin = box->margin;
int *padding = box->padding;
struct box_border *border = box->border;
const css_computed_style *style = box->style;
 
layout_find_dimensions(available_width, viewport_height, box, style,
&width, &height, &max_width, &min_width,
margin, padding, border);
 
if (box->object && !(box->flags & REPLACE_DIM) &&
content_get_type(box->object) != CONTENT_HTML) {
/* block-level replaced element, see 10.3.4 and 10.6.2 */
layout_get_object_dimensions(box, &width, &height,
min_width, max_width);
}
 
box->width = layout_solve_width(box, available_width, width, lm, rm,
max_width, min_width);
box->height = height;
 
if (margin[TOP] == AUTO)
margin[TOP] = 0;
if (margin[BOTTOM] == AUTO)
margin[BOTTOM] = 0;
}
 
/**
* Manimpulate box height according to CSS min-height and max-height properties
*
* \param box block to modify with any min-height or max-height
* \param container containing block for absolutely positioned elements, or
* NULL for non absolutely positioned elements.
* \return whether the height has been changed
*/
 
bool layout_apply_minmax_height(struct box *box, struct box *container)
{
int h;
struct box *containing_block = NULL;
bool updated = false;
 
/* Find containing block for percentage heights */
if (box->style != NULL && css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE) {
/* Box is absolutely positioned */
assert(container);
containing_block = container;
} else if (box->float_container && box->style != NULL &&
(css_computed_float(box->style) == CSS_FLOAT_LEFT ||
css_computed_float(box->style) == CSS_FLOAT_RIGHT)) {
/* Box is a float */
assert(box->parent && box->parent->parent &&
box->parent->parent->parent);
containing_block = box->parent->parent->parent;
} else if (box->parent && box->parent->type != BOX_INLINE_CONTAINER) {
/* Box is a block level element */
containing_block = box->parent;
} else if (box->parent && box->parent->type == BOX_INLINE_CONTAINER) {
/* Box is an inline block */
assert(box->parent->parent);
containing_block = box->parent->parent;
}
 
if (box->style) {
enum css_height_e htype = CSS_HEIGHT_AUTO;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
if (containing_block) {
htype = css_computed_height(containing_block->style,
&value, &unit);
}
 
/* max-height */
if (css_computed_max_height(box->style, &value, &unit) ==
CSS_MAX_HEIGHT_SET) {
if (unit == CSS_UNIT_PCT) {
if (containing_block &&
containing_block->height != AUTO &&
(css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE ||
htype == CSS_HEIGHT_SET)) {
/* Box is absolutely positioned or its
* containing block has a valid
* specified height. (CSS 2.1
* Section 10.5) */
h = FPCT_OF_INT_TOINT(value,
containing_block->height);
if (h < box->height) {
box->height = h;
updated = true;
}
}
} else {
h = FIXTOINT(nscss_len2px(value, unit,
box->style));
if (h < box->height) {
box->height = h;
updated = true;
}
}
}
 
/* min-height */
if (css_computed_min_height(box->style, &value, &unit) ==
CSS_MIN_HEIGHT_SET) {
if (unit == CSS_UNIT_PCT) {
if (containing_block &&
containing_block->height != AUTO &&
(css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE ||
htype == CSS_HEIGHT_SET)) {
/* Box is absolutely positioned or its
* containing block has a valid
* specified height. (CSS 2.1
* Section 10.5) */
h = FPCT_OF_INT_TOINT(value,
containing_block->height);
if (h > box->height) {
box->height = h;
updated = true;
}
}
} else {
h = FIXTOINT(nscss_len2px(value, unit,
box->style));
if (h > box->height) {
box->height = h;
updated = true;
}
}
}
}
return updated;
}
 
/**
* Manipulate a block's [RB]padding/height/width to accommodate scrollbars
*
* \param box Box to apply scrollbar space too. Must be BOX_BLOCK.
* \param which Which scrollbar to make space for. Must be RIGHT or BOTTOM.
*/
 
void layout_block_add_scrollbar(struct box *box, int which)
{
enum css_overflow_e overflow;
 
assert(box->type == BOX_BLOCK && (which == RIGHT || which == BOTTOM));
 
if (box->style == NULL)
return;
 
overflow = css_computed_overflow(box->style);
 
if (overflow == CSS_OVERFLOW_SCROLL || overflow == CSS_OVERFLOW_AUTO ||
(box->object && content_get_type(box->object) ==
CONTENT_HTML)) {
/* make space for scrollbars, unless height/width are AUTO */
enum css_height_e htype;
css_fixed height = 0;
css_unit hunit = CSS_UNIT_PX;
htype = css_computed_height(box->style, &height, &hunit);
 
if (which == BOTTOM && box->height != AUTO &&
(overflow == CSS_OVERFLOW_SCROLL ||
box_hscrollbar_present(box))) {
box->padding[BOTTOM] += SCROLLBAR_WIDTH;
}
if (which == RIGHT && box->width != AUTO &&
htype == CSS_HEIGHT_SET &&
(overflow == CSS_OVERFLOW_SCROLL ||
box_vscrollbar_present(box))) {
box->width -= SCROLLBAR_WIDTH;
box->padding[RIGHT] += SCROLLBAR_WIDTH;
}
}
}
 
/**
* Solve the width constraint as given in CSS 2.1 section 10.3.3.
*
* \param box Box to solve constraint for
* \param available_width Max width available in pixels
* \param width Current box width
* \param lm Min left margin required to avoid floats in px.
* zero if not applicable
* \param rm Min right margin required to avoid floats in px.
* zero if not applicable
* \param max_width Box max-width ( -ve means no max-width to apply)
* \param min_width Box min-width ( <=0 means no min-width to apply)
* \return New box width
*
* \post \a box's left/right margins will be updated.
*/
 
int layout_solve_width(struct box *box, int available_width, int width,
int lm, int rm, int max_width, int min_width)
{
bool auto_width = false;
 
/* Increase specified left/right margins */
if (box->margin[LEFT] != AUTO && box->margin[LEFT] < lm &&
box->margin[LEFT] >= 0)
box->margin[LEFT] = lm;
if (box->margin[RIGHT] != AUTO && box->margin[RIGHT] < rm &&
box->margin[RIGHT] >= 0)
box->margin[RIGHT] = rm;
 
/* Find width */
if (width == AUTO) {
/* any other 'auto' become 0 or the minimum required values */
if (box->margin[LEFT] == AUTO)
box->margin[LEFT] = lm;
if (box->margin[RIGHT] == AUTO)
box->margin[RIGHT] = rm;
 
width = available_width -
(box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
box->border[RIGHT].width + box->margin[RIGHT]);
width = width < 0 ? 0 : width;
auto_width = true;
}
 
if (max_width >= 0 && width > max_width) {
/* max-width is admissable and width exceeds max-width */
width = max_width;
auto_width = false;
}
 
if (min_width > 0 && width < min_width) {
/* min-width is admissable and width is less than max-width */
width = min_width;
auto_width = false;
}
 
/* Width was auto, and unconstrained by min/max width, so we're done */
if (auto_width)
return width;
 
/* Width was not auto, or was constrained by min/max width
* Need to compute left/right margins */
 
/* HTML alignment (only applies to over-constrained boxes) */
if (box->margin[LEFT] != AUTO && box->margin[RIGHT] != AUTO &&
box->parent != NULL && box->parent->style != NULL) {
switch (css_computed_text_align(box->parent->style)) {
case CSS_TEXT_ALIGN_LIBCSS_RIGHT:
box->margin[LEFT] = AUTO;
box->margin[RIGHT] = 0;
break;
case CSS_TEXT_ALIGN_LIBCSS_CENTER:
box->margin[LEFT] = box->margin[RIGHT] = AUTO;
break;
case CSS_TEXT_ALIGN_LIBCSS_LEFT:
box->margin[LEFT] = 0;
box->margin[RIGHT] = AUTO;
break;
default:
/* Leave it alone; no HTML alignment */
break;
}
}
 
if (box->margin[LEFT] == AUTO && box->margin[RIGHT] == AUTO) {
/* make the margins equal, centering the element */
box->margin[LEFT] = box->margin[RIGHT] =
(available_width - lm - rm -
(box->border[LEFT].width + box->padding[LEFT] +
width + box->padding[RIGHT] +
box->border[RIGHT].width)) / 2;
 
if (box->margin[LEFT] < 0) {
box->margin[RIGHT] += box->margin[LEFT];
box->margin[LEFT] = 0;
}
 
box->margin[LEFT] += lm;
 
} else if (box->margin[LEFT] == AUTO) {
box->margin[LEFT] = available_width - lm -
(box->border[LEFT].width + box->padding[LEFT] +
width + box->padding[RIGHT] +
box->border[RIGHT].width + box->margin[RIGHT]);
box->margin[LEFT] = box->margin[LEFT] < lm
? lm : box->margin[LEFT];
} else {
/* margin-right auto or "over-constrained" */
box->margin[RIGHT] = available_width - rm -
(box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + width +
box->padding[RIGHT] +
box->border[RIGHT].width);
}
 
return width;
}
 
 
/**
* Compute dimensions of box, margins, paddings, and borders for a floating
* element using shrink-to-fit. Also used for inline-blocks.
*
* \param available_width Max width available in pixels
* \param style Box's style
* \param box Box for which to find dimensions
* Box margins, borders, paddings, width and
* height are updated.
*/
 
void layout_float_find_dimensions(int available_width,
const css_computed_style *style, struct box *box)
{
int width, height, max_width, min_width;
int *margin = box->margin;
int *padding = box->padding;
struct box_border *border = box->border;
int scrollbar_width =
(css_computed_overflow(style) == CSS_OVERFLOW_SCROLL ||
css_computed_overflow(style) == CSS_OVERFLOW_AUTO) ?
SCROLLBAR_WIDTH : 0;
 
layout_find_dimensions(available_width, -1, box, style, &width, &height,
&max_width, &min_width, margin, padding, border);
 
if (margin[LEFT] == AUTO)
margin[LEFT] = 0;
if (margin[RIGHT] == AUTO)
margin[RIGHT] = 0;
 
padding[RIGHT] += scrollbar_width;
padding[BOTTOM] += scrollbar_width;
 
if (box->object && !(box->flags & REPLACE_DIM) &&
content_get_type(box->object) != CONTENT_HTML) {
/* Floating replaced element, with intrinsic width or height.
* See 10.3.6 and 10.6.2 */
layout_get_object_dimensions(box, &width, &height,
min_width, max_width);
} else if (box->gadget && (box->gadget->type == GADGET_TEXTBOX ||
box->gadget->type == GADGET_PASSWORD ||
box->gadget->type == GADGET_FILE ||
box->gadget->type == GADGET_TEXTAREA)) {
css_fixed size = 0;
css_unit unit = CSS_UNIT_EM;
 
/* Give sensible dimensions to gadgets, with auto width/height,
* that don't shrink to fit contained text. */
assert(box->style);
 
if (box->gadget->type == GADGET_TEXTBOX ||
box->gadget->type == GADGET_PASSWORD ||
box->gadget->type == GADGET_FILE) {
if (width == AUTO) {
size = INTTOFIX(10);
width = FIXTOINT(nscss_len2px(size, unit,
box->style));
}
if (box->gadget->type == GADGET_FILE &&
height == AUTO) {
size = FLTTOFIX(1.5);
height = FIXTOINT(nscss_len2px(size, unit,
box->style));
}
}
if (box->gadget->type == GADGET_TEXTAREA) {
if (width == AUTO) {
size = INTTOFIX(10);
width = FIXTOINT(nscss_len2px(size, unit,
box->style));
} else {
width -= scrollbar_width;
}
if (height == AUTO) {
size = INTTOFIX(4);
height = FIXTOINT(nscss_len2px(size, unit,
box->style));
}
}
} else if (width == AUTO) {
/* CSS 2.1 section 10.3.5 */
width = min(max(box->min_width, available_width),
box->max_width);
 
/* width includes margin, borders and padding */
if (width == available_width) {
width -= box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] +
box->padding[RIGHT] +
box->border[RIGHT].width +
box->margin[RIGHT];
} else {
/* width was obtained from a min_width or max_width
* value, so need to use the same method for calculating
* mbp as was used in layout_minmax_block() */
int fixed = 0;
float frac = 0;
calculate_mbp_width(box->style, LEFT, true, true, true,
&fixed, &frac);
calculate_mbp_width(box->style, RIGHT, true, true, true,
&fixed, &frac);
if (fixed < 0)
fixed = 0;
 
width -= fixed;
}
 
if (max_width >= 0 && width > max_width) width = max_width;
if (min_width > 0 && width < min_width) width = min_width;
 
} else {
if (max_width >= 0 && width > max_width) width = max_width;
if (min_width > 0 && width < min_width) width = min_width;
width -= scrollbar_width;
}
 
box->width = width;
box->height = height;
 
if (margin[TOP] == AUTO)
margin[TOP] = 0;
if (margin[BOTTOM] == AUTO)
margin[BOTTOM] = 0;
}
 
 
/**
* Calculate width, height, and thickness of margins, paddings, and borders.
*
* \param available_width width of containing block
* \param viewport_height height of viewport in pixels or -ve if unknown
* \param box current box
* \param style style giving width, height, margins, paddings,
* and borders
* \param width updated to width, may be NULL
* \param height updated to height, may be NULL
* \param max_width updated to max-width, may be NULL
* \param min_width updated to min-width, may be NULL
* \param margin[4] filled with margins, may be NULL
* \param padding[4] filled with paddings, may be NULL
* \param border[4] filled with border widths, may be NULL
*/
 
void layout_find_dimensions(int available_width, int viewport_height,
struct box *box, const css_computed_style *style,
int *width, int *height, int *max_width, int *min_width,
int margin[4], int padding[4], struct box_border border[4])
{
struct box *containing_block = NULL;
unsigned int i;
bool percentage;
 
if (width) {
enum css_width_e wtype;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
wtype = css_computed_width(style, &value, &unit);
 
if (wtype == CSS_WIDTH_SET) {
if (unit == CSS_UNIT_PCT) {
*width = FPCT_OF_INT_TOINT(
value, available_width);
} else {
*width = FIXTOINT(nscss_len2px(value, unit,
style));
}
} else {
*width = AUTO;
}
 
/* specified gadget widths include borders and padding in some
* cases */
if (box->gadget && *width != AUTO) {
percentage = unit == CSS_UNIT_PCT;
 
layout_tweak_form_dimensions(box, percentage,
available_width, true, width);
}
}
 
if (height) {
enum css_height_e htype;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
htype = css_computed_height(style, &value, &unit);
 
if (htype == CSS_HEIGHT_SET) {
if (unit == CSS_UNIT_PCT) {
enum css_height_e cbhtype;
 
if (css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE &&
box->parent) {
/* Box is absolutely positioned */
assert(box->float_container);
containing_block = box->float_container;
} else if (box->float_container &&
css_computed_position(box->style) !=
CSS_POSITION_ABSOLUTE &&
(css_computed_float(box->style) ==
CSS_FLOAT_LEFT ||
css_computed_float(box->style) ==
CSS_FLOAT_RIGHT)) {
/* Box is a float */
assert(box->parent &&
box->parent->parent &&
box->parent->parent->parent);
 
containing_block =
box->parent->parent->parent;
} else if (box->parent && box->parent->type !=
BOX_INLINE_CONTAINER) {
/* Box is a block level element */
containing_block = box->parent;
} else if (box->parent && box->parent->type ==
BOX_INLINE_CONTAINER) {
/* Box is an inline block */
assert(box->parent->parent);
containing_block = box->parent->parent;
}
 
if (containing_block) {
css_fixed f = 0;
css_unit u = CSS_UNIT_PX;
 
cbhtype = css_computed_height(
containing_block->style,
&f, &u);
}
 
if (containing_block &&
containing_block->height != AUTO &&
(css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE ||
cbhtype == CSS_HEIGHT_SET)) {
/* Box is absolutely positioned or its
* containing block has a valid
* specified height.
* (CSS 2.1 Section 10.5) */
*height = FPCT_OF_INT_TOINT(value,
containing_block->height);
} else if ((!box->parent ||
!box->parent->parent) &&
viewport_height >= 0) {
/* If root element or it's child
* (HTML or BODY) */
*height = FPCT_OF_INT_TOINT(value,
viewport_height);
} else {
/* precentage height not permissible
* treat height as auto */
*height = AUTO;
}
} else {
*height = FIXTOINT(nscss_len2px(value, unit,
style));
}
} else {
*height = AUTO;
}
 
/* specified gadget heights include borders and padding in
* some cases */
if (box->gadget && *height != AUTO) {
percentage = unit == CSS_UNIT_PCT;
 
layout_tweak_form_dimensions(box, percentage,
available_width, false, height);
}
}
 
if (max_width) {
enum css_max_width_e type;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
type = css_computed_max_width(style, &value, &unit);
 
if (type == CSS_MAX_WIDTH_SET) {
if (unit == CSS_UNIT_PCT) {
*max_width = FPCT_OF_INT_TOINT(value,
available_width);
} else {
*max_width = FIXTOINT(nscss_len2px(value, unit,
style));
}
} else {
/* Inadmissible */
*max_width = -1;
}
 
/* specified gadget widths include borders and padding in some
* cases */
if (box->gadget && *max_width != -1) {
percentage = unit == CSS_UNIT_PCT;
 
layout_tweak_form_dimensions(box, percentage,
available_width, true, max_width);
}
}
 
if (min_width) {
enum css_min_width_e type;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
type = css_computed_min_width(style, &value, &unit);
 
if (type == CSS_MIN_WIDTH_SET) {
if (unit == CSS_UNIT_PCT) {
*min_width = FPCT_OF_INT_TOINT(value,
available_width);
} else {
*min_width = FIXTOINT(nscss_len2px(value, unit,
style));
}
} else {
/* Inadmissible */
*min_width = 0;
}
 
/* specified gadget widths include borders and padding in some
* cases */
if (box->gadget && *min_width != 0) {
percentage = unit == CSS_UNIT_PCT;
 
layout_tweak_form_dimensions(box, percentage,
available_width, true, min_width);
}
}
 
for (i = 0; i != 4; i++) {
if (margin) {
enum css_margin_e type = CSS_MARGIN_AUTO;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
switch (i) {
case TOP:
type = css_computed_margin_top(style,
&value, &unit);
break;
case RIGHT:
type = css_computed_margin_right(style,
&value, &unit);
break;
case BOTTOM:
type = css_computed_margin_bottom(style,
&value, &unit);
break;
case LEFT:
type = css_computed_margin_left(style,
&value, &unit);
break;
}
 
if (type == CSS_MARGIN_SET) {
if (unit == CSS_UNIT_PCT) {
margin[i] = FPCT_OF_INT_TOINT(value,
available_width);
} else {
margin[i] = FIXTOINT(nscss_len2px(value,
unit, style));
}
} else {
margin[i] = AUTO;
}
}
 
if (padding) {
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
switch (i) {
case TOP:
css_computed_padding_top(style, &value, &unit);
break;
case RIGHT:
css_computed_padding_right(style, &value,
&unit);
break;
case BOTTOM:
css_computed_padding_bottom(style, &value,
&unit);
break;
case LEFT:
css_computed_padding_left(style, &value, &unit);
break;
}
 
if (unit == CSS_UNIT_PCT) {
padding[i] = FPCT_OF_INT_TOINT(value,
available_width);
} else {
padding[i] = FIXTOINT(nscss_len2px(value, unit,
style));
}
}
 
/* Table cell borders are populated in table.c */
if (border && box->type != BOX_TABLE_CELL) {
enum css_border_style_e bstyle = CSS_BORDER_STYLE_NONE;
css_color color = 0;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
switch (i) {
case TOP:
css_computed_border_top_width(style, &value,
&unit);
bstyle = css_computed_border_top_style(style);
css_computed_border_top_color(style, &color);
break;
case RIGHT:
css_computed_border_right_width(style, &value,
&unit);
bstyle = css_computed_border_right_style(style);
css_computed_border_right_color(style, &color);
break;
case BOTTOM:
css_computed_border_bottom_width(style, &value,
&unit);
bstyle = css_computed_border_bottom_style(
style);
css_computed_border_bottom_color(style, &color);
break;
case LEFT:
css_computed_border_left_width(style, &value,
&unit);
bstyle = css_computed_border_left_style(style);
css_computed_border_left_color(style, &color);
break;
}
 
border[i].style = bstyle;
border[i].c = color;
 
if (bstyle == CSS_BORDER_STYLE_HIDDEN ||
bstyle == CSS_BORDER_STYLE_NONE)
/* spec unclear: following Mozilla */
border[i].width = 0;
else
border[i].width = FIXTOINT(nscss_len2px(value,
unit, style));
 
/* Special case for border-collapse: make all borders
* on table/table-row-group/table-row zero width. */
if (css_computed_border_collapse(style) ==
CSS_BORDER_COLLAPSE_COLLAPSE &&
(box->type == BOX_TABLE ||
box->type == BOX_TABLE_ROW_GROUP ||
box->type == BOX_TABLE_ROW))
border[i].width = 0;
}
}
}
 
 
/**
* Under some circumstances, specified dimensions for form elements include
* borders and padding.
*
* \param box gadget to adjust dimensions of
* \param percentage whether the gadget has its dimension specified as a
* percentage
* \param available_width width of containing block
* \param setwidth set true if the dimension to be tweaked is a width,
* else set false for a height
* \param dimension current value for given width/height dimension.
* updated to new value after consideration of
* gadget properties.
*/
 
void layout_tweak_form_dimensions(struct box *box, bool percentage,
int available_width, bool setwidth, int *dimension)
{
int fixed = 0;
float frac = 0;
 
assert(box && box->gadget);
 
/* specified gadget widths include borders and padding in some
* cases */
if (percentage || box->gadget->type == GADGET_SUBMIT ||
box->gadget->type == GADGET_RESET ||
box->gadget->type == GADGET_BUTTON) {
calculate_mbp_width(box->style, setwidth ? LEFT : TOP,
false, true, true, &fixed, &frac);
calculate_mbp_width(box->style, setwidth ? RIGHT : BOTTOM,
false, true, true, &fixed, &frac);
*dimension -= frac * available_width + fixed;
*dimension = *dimension > 0 ? *dimension : 0;
}
}
 
 
/**
* Find y coordinate which clears all floats on left and/or right.
*
* \param fl first float in float list
* \param clear type of clear
* \return y coordinate relative to ancestor box for floats
*/
 
int layout_clear(struct box *fl, enum css_clear_e clear)
{
int y = 0;
for (; fl; fl = fl->next_float) {
if ((clear == CSS_CLEAR_LEFT || clear == CSS_CLEAR_BOTH) &&
fl->type == BOX_FLOAT_LEFT)
if (y < fl->y + fl->height)
y = fl->y + fl->height;
if ((clear == CSS_CLEAR_RIGHT || clear == CSS_CLEAR_BOTH) &&
fl->type == BOX_FLOAT_RIGHT)
if (y < fl->y + fl->height)
y = fl->y + fl->height;
}
return y;
}
 
 
/**
* Find left and right edges in a vertical range.
*
* \param fl first float in float list
* \param y0 start of y range to search
* \param y1 end of y range to search
* \param x0 start left edge, updated to available left edge
* \param x1 start right edge, updated to available right edge
* \param left returns float on left if present
* \param right returns float on right if present
*/
 
void find_sides(struct box *fl, int y0, int y1,
int *x0, int *x1, struct box **left, struct box **right)
{
int fy0, fy1, fx0, fx1;
 
#ifdef LAYOUT_DEBUG
LOG(("y0 %i, y1 %i, x0 %i, x1 %i", y0, y1, *x0, *x1));
#endif
 
*left = *right = 0;
for (; fl; fl = fl->next_float) {
fy0 = fl->y;
fy1 = fl->y + fl->height;
if (y0 < fy1 && fy0 <= y1) {
if (fl->type == BOX_FLOAT_LEFT) {
fx1 = fl->x + fl->width;
if (*x0 < fx1) {
*x0 = fx1;
*left = fl;
}
} else if (fl->type == BOX_FLOAT_RIGHT) {
fx0 = fl->x;
if (fx0 < *x1) {
*x1 = fx0;
*right = fl;
}
}
}
}
 
#ifdef LAYOUT_DEBUG
LOG(("x0 %i, x1 %i, left %p, right %p", *x0, *x1, *left, *right));
#endif
}
 
 
/**
* Layout lines of text or inline boxes with floats.
*
* \param box inline container
* \param width horizontal space available
* \param cont ancestor box which defines horizontal space, for floats
* \param cx box position relative to cont
* \param cy box position relative to cont
* \param content memory pool for any new boxes
* \return true on success, false on memory exhaustion
*/
 
bool layout_inline_container(struct box *inline_container, int width,
struct box *cont, int cx, int cy, html_content *content)
{
bool first_line = true;
bool has_text_children;
struct box *c, *next;
int y = 0;
int curwidth,maxwidth = width;
 
assert(inline_container->type == BOX_INLINE_CONTAINER);
 
#ifdef LAYOUT_DEBUG
LOG(("inline_container %p, width %i, cont %p, cx %i, cy %i",
inline_container, width, cont, cx, cy));
#endif
 
has_text_children = false;
for (c = inline_container->children; c; c = c->next) {
bool is_pre = false;
 
if (c->style) {
enum css_white_space_e whitespace;
 
whitespace = css_computed_white_space(c->style);
 
is_pre = (whitespace == CSS_WHITE_SPACE_PRE ||
whitespace == CSS_WHITE_SPACE_PRE_LINE ||
whitespace == CSS_WHITE_SPACE_PRE_WRAP);
}
 
if ((!c->object && !(c->flags & REPLACE_DIM) &&
!(c->flags & IFRAME) &&
c->text && (c->length || is_pre)) ||
c->type == BOX_BR)
has_text_children = true;
}
 
/** \todo fix wrapping so that a box with horizontal scrollbar will
* shrink back to 'width' if no word is wider than 'width' (Or just set
* curwidth = width and have the multiword lines wrap to the min width)
*/
for (c = inline_container->children; c; ) {
#ifdef LAYOUT_DEBUG
LOG(("c %p", c));
#endif
curwidth = inline_container->width;
if (!layout_line(c, &curwidth, &y, cx, cy + y, cont, first_line,
has_text_children, content, &next))
return false;
maxwidth = max(maxwidth,curwidth);
c = next;
first_line = false;
}
 
inline_container->width = maxwidth;
inline_container->height = y;
 
return true;
}
 
 
/**
* Calculate minimum and maximum width of an inline container.
*
* \param inline_container box of type INLINE_CONTAINER
* \post inline_container->min_width and inline_container->max_width filled in,
* 0 <= inline_container->min_width <= inline_container->max_width
*/
 
void layout_minmax_inline_container(struct box *inline_container,
bool *has_height, const struct font_functions *font_func)
{
struct box *child;
int line_min = 0, line_max = 0;
int min = 0, max = 0;
bool first_line = true;
bool line_has_height;
 
assert(inline_container->type == BOX_INLINE_CONTAINER);
 
/* check if the widths have already been calculated */
if (inline_container->max_width != UNKNOWN_MAX_WIDTH)
return;
 
*has_height = false;
 
for (child = inline_container->children; child; ) {
child = layout_minmax_line(child, &line_min, &line_max,
first_line, &line_has_height, font_func);
if (min < line_min)
min = line_min;
if (max < line_max)
max = line_max;
first_line = false;
*has_height |= line_has_height;
}
 
inline_container->min_width = min;
inline_container->max_width = max;
 
assert(0 <= inline_container->min_width &&
inline_container->min_width <=
inline_container->max_width);
}
 
 
/**
* Calculate line height from a style.
*/
 
int line_height(const css_computed_style *style)
{
enum css_line_height_e lhtype;
css_fixed lhvalue = 0;
css_unit lhunit = CSS_UNIT_PX;
css_fixed line_height;
 
assert(style);
 
lhtype = css_computed_line_height(style, &lhvalue, &lhunit);
if (lhtype == CSS_LINE_HEIGHT_NORMAL) {
/* Normal => use a constant of 1.3 * font-size */
lhvalue = FLTTOFIX(1.3);
lhtype = CSS_LINE_HEIGHT_NUMBER;
}
 
if (lhtype == CSS_LINE_HEIGHT_NUMBER ||
lhunit == CSS_UNIT_PCT) {
line_height = nscss_len2px(lhvalue, CSS_UNIT_EM, style);
 
if (lhtype != CSS_LINE_HEIGHT_NUMBER)
line_height = FDIV(line_height, F_100);
} else {
assert(lhunit != CSS_UNIT_PCT);
 
line_height = nscss_len2px(lhvalue, lhunit, style);
}
 
return FIXTOINT(line_height);
}
 
 
/**
* Split a text box.
*
* \param content memory pool for any new boxes
* \param fstyle style for text in text box
* \param split_box box with text to split
* \param new_length new length for text in split_box, after splitting
* \param new_width new width for text in split_box, after splitting
* \return true on success, false on memory exhaustion
*
* A new box is created and inserted into the box tree after split_box,
* containing the text after new_length excluding the initial space character.
*/
 
static bool layout_text_box_split(html_content *content,
plot_font_style_t *fstyle, struct box *split_box,
size_t new_length, int new_width)
{
int space_width = split_box->space;
struct box *c2;
const struct font_functions *font_func = content->font_func;
 
if (space_width == 0) {
/* Currently split_box has no space. */
/* Get the space width because the split_box will need it */
/* Don't set it in split_box yet, or it will get cloned. */
font_func->font_width(fstyle, " ", 1, &space_width);
} else if (space_width == UNKNOWN_WIDTH) {
/* Split_box has a space but its width is unknown. */
/* Get the space width because the split_box will need it */
/* Set it in split_box, so it gets cloned. */
font_func->font_width(fstyle, " ", 1, &space_width);
split_box->space = space_width;
}
 
/* Create clone of split_box, c2 */
c2 = talloc_memdup(content->bctx, split_box, sizeof *c2);
if (!c2)
return false;
c2->flags |= CLONE;
 
/* Set remaining text in c2 */
if (split_box->parent->parent->gadget != NULL) {
/* Inside a form text input / textarea, special case */
/* TODO: Move text inputs to core textarea widget and remove
* this */
c2->text = talloc_strndup(content->bctx,
split_box->text + new_length + 1,
split_box->length - (new_length + 1));
if (!c2->text)
return false;
} else {
c2->text += new_length + 1;
}
 
/* Set c2 according to the remaining text */
c2->width -= new_width + space_width;
c2->flags &= ~MEASURED; /* width has been estimated */
c2->length = split_box->length - (new_length + 1);
 
/* Update split_box for its reduced text */
split_box->width = new_width;
split_box->flags |= MEASURED;
split_box->length = new_length;
split_box->space = space_width;
 
/* Insert c2 into box list */
c2->next = split_box->next;
split_box->next = c2;
c2->prev = split_box;
if (c2->next)
c2->next->prev = c2;
else
c2->parent->last = c2;
 
return true;
}
 
 
/**
* Position a line of boxes in inline formatting context.
*
* \param first box at start of line
* \param width available width on input, updated with actual width on output
* (may be incorrect if the line gets split?)
* \param y coordinate of top of line, updated on exit to bottom
* \param cx coordinate of left of line relative to cont
* \param cy coordinate of top of line relative to cont
* \param cont ancestor box which defines horizontal space, for floats
* \param indent apply any first-line indent
* \param has_text_children at least one TEXT in the inline_container
* \param next_box updated to first box for next line, or 0 at end
* \param content memory pool for any new boxes
* \return true on success, false on memory exhaustion
*/
 
bool layout_line(struct box *first, int *width, int *y,
int cx, int cy, struct box *cont, bool indent,
bool has_text_children,
html_content *content, struct box **next_box)
{
int height, used_height;
int x0 = 0;
int x1 = *width;
int x, h, x_previous;
int fy = cy;
struct box *left;
struct box *right;
struct box *b;
struct box *split_box = 0;
struct box *d;
struct box *br_box = 0;
bool move_y = false;
bool place_below = false;
int space_before = 0, space_after = 0;
unsigned int inline_count = 0;
unsigned int i;
const struct font_functions *font_func = content->font_func;
plot_font_style_t fstyle;
 
#ifdef LAYOUT_DEBUG
LOG(("first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i",
first, (int) first->length, first->text, *width,
*y, cx, cy));
#endif
 
/* find sides at top of line */
x0 += cx;
x1 += cx;
find_sides(cont->float_children, cy, cy, &x0, &x1, &left, &right);
x0 -= cx;
x1 -= cx;
 
if (indent)
x0 += layout_text_indent(first->parent->parent->style, *width);
 
if (x1 < x0)
x1 = x0;
 
/* get minimum line height from containing block.
* this is the line-height if there are text children and also in the
* case of an initially empty text input */
if (has_text_children || first->parent->parent->gadget)
used_height = height =
line_height(first->parent->parent->style);
else
/* inline containers with no text are usually for layout and
* look better with no minimum line-height */
used_height = height = 0;
 
/* pass 1: find height of line assuming sides at top of line: loop
* body executed at least once
* keep in sync with the loop in layout_minmax_line() */
#ifdef LAYOUT_DEBUG
LOG(("x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0));
#endif
 
for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) {
int min_width, max_width;
 
assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK ||
b->type == BOX_FLOAT_LEFT ||
b->type == BOX_FLOAT_RIGHT ||
b->type == BOX_BR || b->type == BOX_TEXT ||
b->type == BOX_INLINE_END);
 
#ifdef LAYOUT_DEBUG
LOG(("pass 1: b %p, x %i", b, x));
#endif
 
if (b->type == BOX_BR)
break;
 
if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT)
continue;
if (b->type == BOX_INLINE_BLOCK &&
(css_computed_position(b->style) ==
CSS_POSITION_ABSOLUTE ||
css_computed_position(b->style) ==
CSS_POSITION_FIXED))
continue;
 
assert(b->style != NULL);
font_plot_style_from_css(b->style, &fstyle);
 
x += space_after;
 
if (b->type == BOX_INLINE_BLOCK) {
if (b->max_width != UNKNOWN_WIDTH)
if (!layout_float(b, *width, content))
return false;
h = b->border[TOP].width + b->padding[TOP] + b->height +
b->padding[BOTTOM] +
b->border[BOTTOM].width;
if (height < h)
height = h;
x += b->margin[LEFT] + b->border[LEFT].width +
b->padding[LEFT] + b->width +
b->padding[RIGHT] +
b->border[RIGHT].width +
b->margin[RIGHT];
space_after = 0;
continue;
}
 
if (b->type == BOX_INLINE) {
/* calculate borders, margins, and padding */
layout_find_dimensions(*width, -1, b, b->style, 0, 0,
0, 0, b->margin, b->padding, b->border);
for (i = 0; i != 4; i++)
if (b->margin[i] == AUTO)
b->margin[i] = 0;
x += b->margin[LEFT] + b->border[LEFT].width +
b->padding[LEFT];
if (b->inline_end) {
b->inline_end->margin[RIGHT] = b->margin[RIGHT];
b->inline_end->padding[RIGHT] =
b->padding[RIGHT];
b->inline_end->border[RIGHT] =
b->border[RIGHT];
} else {
x += b->padding[RIGHT] +
b->border[RIGHT].width +
b->margin[RIGHT];
}
} else if (b->type == BOX_INLINE_END) {
b->width = 0;
if (b->space == UNKNOWN_WIDTH) {
font_func->font_width(&fstyle, " ", 1,
&b->space);
/** \todo handle errors */
}
space_after = b->space;
 
x += b->padding[RIGHT] + b->border[RIGHT].width +
b->margin[RIGHT];
continue;
}
 
if (!b->object && !(b->flags & IFRAME) && !b->gadget &&
!(b->flags & REPLACE_DIM)) {
/* inline non-replaced, 10.3.1 and 10.6.1 */
b->height = line_height(b->style ? b->style :
b->parent->parent->style);
if (height < b->height)
height = b->height;
 
if (!b->text) {
b->width = 0;
space_after = 0;
continue;
}
 
if (b->width == UNKNOWN_WIDTH) {
/** \todo handle errors */
 
/* If it's a select element, we must use the
* width of the widest option text */
if (b->parent->parent->gadget &&
b->parent->parent->gadget->type
== GADGET_SELECT) {
int opt_maxwidth = 0;
struct form_option *o;
 
for (o = b->parent->parent->gadget->
data.select.items; o;
o = o->next) {
int opt_width;
font_func->font_width(&fstyle,
o->text,
strlen(o->text),
&opt_width);
 
if (opt_maxwidth < opt_width)
opt_maxwidth =opt_width;
}
b->width = opt_maxwidth;
if (nsoption_bool(core_select_menu))
b->width += SCROLLBAR_WIDTH;
} else {
font_func->font_width(&fstyle, b->text,
b->length, &b->width);
b->flags |= MEASURED;
}
}
 
/* If the current text has not been measured (i.e. its
* width was estimated after splitting), and it fits on
* the line, measure it properly, so next box is placed
* correctly. */
if (b->text && (x + b->width < x1 - x0) &&
!(b->flags & MEASURED) &&
b->next) {
font_func->font_width(&fstyle, b->text,
b->length, &b->width);
b->flags |= MEASURED;
}
 
x += b->width;
if (b->space == UNKNOWN_WIDTH) {
font_func->font_width(&fstyle, " ", 1,
&b->space);
/** \todo handle errors */
}
space_after = b->space;
continue;
}
 
space_after = 0;
 
/* inline replaced, 10.3.2 and 10.6.2 */
assert(b->style);
 
layout_find_dimensions(*width, -1, b, b->style,
&b->width, &b->height, &max_width, &min_width,
NULL, NULL, NULL);
 
if (b->object && !(b->flags & REPLACE_DIM)) {
layout_get_object_dimensions(b, &b->width, &b->height,
min_width, max_width);
} else if (b->flags & IFRAME) {
/* TODO: should we look at the content dimensions? */
if (b->width == AUTO)
b->width = 400;
if (b->height == AUTO)
b->height = 300;
 
/* We reformat the iframe browser window to new
* dimensions in pass 2 */
} else {
/* form control with no object */
if (b->width == AUTO)
b->width = FIXTOINT(nscss_len2px(INTTOFIX(1),
CSS_UNIT_EM, b->style));
if (b->height == AUTO)
b->height = FIXTOINT(nscss_len2px(INTTOFIX(1),
CSS_UNIT_EM, b->style));
}
 
/* Reformat object to new box size */
if (b->object && content_get_type(b->object) == CONTENT_HTML &&
b->width !=
content_get_available_width(b->object)) {
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
enum css_height_e htype = css_computed_height(b->style,
&value, &unit);
 
content_reformat(b->object, false, b->width, b->height);
 
if (htype == CSS_HEIGHT_AUTO)
b->height = content_get_height(b->object);
}
 
if (height < b->height)
height = b->height;
 
x += b->width;
}
 
/* find new sides using this height */
x0 = cx;
x1 = cx + *width;
find_sides(cont->float_children, cy, cy + height, &x0, &x1,
&left, &right);
x0 -= cx;
x1 -= cx;
 
if (indent)
x0 += layout_text_indent(first->parent->parent->style, *width);
 
if (x1 < x0)
x1 = x0;
 
space_after = space_before = 0;
 
/* pass 2: place boxes in line: loop body executed at least once */
#ifdef LAYOUT_DEBUG
LOG(("x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0));
#endif
 
for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) {
#ifdef LAYOUT_DEBUG
LOG(("pass 2: b %p, x %i", b, x));
#endif
 
if (b->type == BOX_INLINE_BLOCK &&
(css_computed_position(b->style) ==
CSS_POSITION_ABSOLUTE ||
css_computed_position(b->style) ==
CSS_POSITION_FIXED)) {
b->x = x + space_after;
 
} else if (b->type == BOX_INLINE ||
b->type == BOX_INLINE_BLOCK ||
b->type == BOX_TEXT ||
b->type == BOX_INLINE_END) {
assert(b->width != UNKNOWN_WIDTH);
 
x_previous = x;
x += space_after;
b->x = x;
 
if ((b->type == BOX_INLINE && !b->inline_end) ||
b->type == BOX_INLINE_BLOCK) {
b->x += b->margin[LEFT] + b->border[LEFT].width;
x = b->x + b->padding[LEFT] + b->width +
b->padding[RIGHT] +
b->border[RIGHT].width +
b->margin[RIGHT];
} else if (b->type == BOX_INLINE) {
b->x += b->margin[LEFT] + b->border[LEFT].width;
x = b->x + b->padding[LEFT] + b->width;
} else if (b->type == BOX_INLINE_END) {
b->height = b->inline_end->height;
x += b->padding[RIGHT] +
b->border[RIGHT].width +
b->margin[RIGHT];
} else {
x += b->width;
}
 
space_before = space_after;
if (b->object || b->flags & REPLACE_DIM ||
b->flags & IFRAME)
space_after = 0;
else if (b->text || b->type == BOX_INLINE_END) {
if (b->space == UNKNOWN_WIDTH) {
font_plot_style_from_css(b->style,
&fstyle);
/** \todo handle errors */
font_func->font_width(&fstyle, " ", 1,
&b->space);
}
space_after = b->space;
} else {
space_after = 0;
}
split_box = b;
move_y = true;
inline_count++;
} else if (b->type == BOX_BR) {
b->x = x;
b->width = 0;
br_box = b;
b = b->next;
split_box = 0;
move_y = true;
break;
 
} else {
/* float */
#ifdef LAYOUT_DEBUG
LOG(("float %p", b));
#endif
 
d = b->children;
d->float_children = 0;
b->float_container = d->float_container = cont;
 
if (!layout_float(d, *width, content))
return false;
 
#ifdef LAYOUT_DEBUG
LOG(("%p : %d %d", d, d->margin[TOP],
d->border[TOP].width));
#endif
 
d->x = d->margin[LEFT] + d->border[LEFT].width;
d->y = d->margin[TOP] + d->border[TOP].width;
b->width = d->margin[LEFT] + d->border[LEFT].width +
d->padding[LEFT] + d->width +
d->padding[RIGHT] +
d->border[RIGHT].width +
d->margin[RIGHT];
b->height = d->margin[TOP] + d->border[TOP].width +
d->padding[TOP] + d->height +
d->padding[BOTTOM] +
d->border[BOTTOM].width +
d->margin[BOTTOM];
 
if (b->width > (x1 - x0) - x)
place_below = true;
if (d->style && (css_computed_clear(d->style) ==
CSS_CLEAR_NONE ||
(css_computed_clear(d->style) ==
CSS_CLEAR_LEFT && left == 0) ||
(css_computed_clear(d->style) ==
CSS_CLEAR_RIGHT &&
right == 0) ||
(css_computed_clear(d->style) ==
CSS_CLEAR_BOTH &&
left == 0 && right == 0)) &&
(!place_below ||
(left == 0 && right == 0 && x == 0)) &&
cy >= cont->clear_level) {
/* + not cleared or,
* cleared and there are no floats to clear
* + fits without needing to be placed below or,
* this line is empty with no floats
* + current y, cy, is below the clear level
*
* Float affects current line */
if (b->type == BOX_FLOAT_LEFT) {
b->x = cx + x0;
if (b->width > 0)
x0 += b->width;
left = b;
} else {
b->x = cx + x1 - b->width;
if (b->width > 0)
x1 -= b->width;
right = b;
}
b->y = cy;
} else {
/* cleared or doesn't fit on line */
/* place below into next available space */
int fcy = (cy > cont->clear_level) ? cy :
cont->clear_level;
fy = (fy > fcy) ? fy : fcy;
fy = (fy == cy) ? fy + height : fy;
 
place_float_below(b, *width, cx, fy, cont);
fy = b->y;
if (d->style && (
(css_computed_clear(d->style) ==
CSS_CLEAR_LEFT && left != 0) ||
(css_computed_clear(d->style) ==
CSS_CLEAR_RIGHT &&
right != 0) ||
(css_computed_clear(d->style) ==
CSS_CLEAR_BOTH &&
(left != 0 || right != 0)))) {
/* to be cleared below existing
* floats */
if (b->type == BOX_FLOAT_LEFT)
b->x = cx;
else
b->x = cx + *width - b->width;
 
fcy = layout_clear(cont->float_children,
css_computed_clear(d->style));
if (fcy > cont->clear_level)
cont->clear_level = fcy;
if (b->y < fcy)
b->y = fcy;
}
if (b->type == BOX_FLOAT_LEFT)
left = b;
else
right = b;
}
if (cont->float_children == b) {
#ifdef LAYOUT_DEBUG
LOG(("float %p already placed", b));
#endif
 
box_dump(stderr, cont, 0);
assert(0);
}
b->next_float = cont->float_children;
cont->float_children = b;
 
split_box = 0;
}
}
 
if (x1 - x0 < x && split_box) {
/* the last box went over the end */
unsigned int i;
size_t space = 0;
int w;
bool no_wrap = css_computed_white_space(
split_box->style) == CSS_WHITE_SPACE_NOWRAP ||
css_computed_white_space(
split_box->style) == CSS_WHITE_SPACE_PRE;
 
x = x_previous;
 
if ((split_box->type == BOX_INLINE ||
split_box->type == BOX_TEXT) &&
!split_box->object &&
!(split_box->flags & REPLACE_DIM) &&
!(split_box->flags & IFRAME) &&
!split_box->gadget && split_box->text) {
/* skip leading spaces, otherwise code gets fooled into
* thinking it's all one long word */
for (i = 0; i != split_box->length &&
split_box->text[i] == ' '; i++)
;
/* find end of word */
for (; i != split_box->length &&
split_box->text[i] != ' '; i++)
;
if (i != split_box->length)
space = i;
}
 
/* space != 0 implies split_box->text != 0 */
 
if (space == 0 || no_wrap)
w = split_box->width;
else {
font_plot_style_from_css(split_box->style, &fstyle);
/** \todo handle errors */
font_func->font_width(&fstyle, split_box->text,
space, &w);
}
 
#ifdef LAYOUT_DEBUG
LOG(("splitting: split_box %p \"%.*s\", space %zu, w %i, "
"left %p, right %p, inline_count %u",
split_box, (int) split_box->length,
split_box->text, space, w,
left, right, inline_count));
#endif
 
if ((space == 0 || x1 - x0 <= x + space_before + w) &&
!left && !right && inline_count == 1) {
/* first word of box doesn't fit, but no floats and
* first box on line so force in */
if (space == 0 || no_wrap) {
/* only one word in this box, or not text
* or white-space:nowrap */
b = split_box->next;
} else {
/* cut off first word for this line */
if (!layout_text_box_split(content, &fstyle,
split_box, space, w))
return false;
b = split_box->next;
}
x += space_before + w;
#ifdef LAYOUT_DEBUG
LOG(("forcing"));
#endif
} else if ((space == 0 || x1 - x0 <= x + space_before + w) &&
inline_count == 1) {
/* first word of first box doesn't fit, but a float is
* taking some of the width so move below it */
assert(left || right);
used_height = 0;
if (left) {
#ifdef LAYOUT_DEBUG
LOG(("cy %i, left->y %i, left->height %i",
cy, left->y, left->height));
#endif
used_height = left->y + left->height - cy + 1;
#ifdef LAYOUT_DEBUG
LOG(("used_height %i", used_height));
#endif
}
if (right && used_height <
right->y + right->height - cy + 1)
used_height = right->y + right->height - cy + 1;
 
if (used_height < 0)
used_height = 0;
 
b = split_box;
#ifdef LAYOUT_DEBUG
LOG(("moving below float"));
#endif
} else if (space == 0 || x1 - x0 <= x + space_before + w) {
/* first word of box doesn't fit so leave box for next
* line */
b = split_box;
#ifdef LAYOUT_DEBUG
LOG(("leaving for next line"));
#endif
} else {
/* fit as many words as possible */
assert(space != 0);
font_plot_style_from_css(split_box->style, &fstyle);
/** \todo handle errors */
font_func->font_split(&fstyle,
split_box->text, split_box->length,
x1 - x0 - x - space_before, &space, &w);
#ifdef LAYOUT_DEBUG
LOG(("'%.*s' %i %zu %i", (int) split_box->length,
split_box->text, x1 - x0, space, w));
#endif
if (space == 0)
space = 1;
if (space != split_box->length) {
if (!layout_text_box_split(content, &fstyle,
split_box, space, w))
return false;
b = split_box->next;
}
x += space_before + w;
#ifdef LAYOUT_DEBUG
LOG(("fitting words"));
#endif
}
move_y = true;
}
 
/* set positions */
switch (css_computed_text_align(first->parent->parent->style)) {
case CSS_TEXT_ALIGN_RIGHT:
case CSS_TEXT_ALIGN_LIBCSS_RIGHT:
x0 = x1 - x;
break;
case CSS_TEXT_ALIGN_CENTER:
case CSS_TEXT_ALIGN_LIBCSS_CENTER:
x0 = (x0 + (x1 - x)) / 2;
break;
case CSS_TEXT_ALIGN_LEFT:
case CSS_TEXT_ALIGN_LIBCSS_LEFT:
case CSS_TEXT_ALIGN_JUSTIFY:
/* leave on left */
break;
case CSS_TEXT_ALIGN_DEFAULT:
/* None; consider text direction */
switch (css_computed_direction(first->parent->parent->style)) {
case CSS_DIRECTION_LTR:
/* leave on left */
break;
case CSS_DIRECTION_RTL:
x0 = x1 - x;
break;
}
break;
}
 
for (d = first; d != b; d = d->next) {
d->flags &= ~NEW_LINE;
 
if (d->type == BOX_INLINE_BLOCK &&
(css_computed_position(d->style) ==
CSS_POSITION_ABSOLUTE ||
css_computed_position(d->style) ==
CSS_POSITION_FIXED)) {
/* positioned inline-blocks:
* set static position (x,y) only, rest of positioning
* is handled later */
d->x += x0;
d->y = *y;
continue;
} else if ((d->type == BOX_INLINE &&
((d->object || d->gadget) == false) &&
!(d->flags & IFRAME) &&
!(d->flags & REPLACE_DIM)) ||
d->type == BOX_BR ||
d->type == BOX_TEXT ||
d->type == BOX_INLINE_END) {
/* regular (non-replaced) inlines */
d->x += x0;
d->y = *y - d->padding[TOP];
 
if (d->type == BOX_TEXT && d->height > used_height) {
/* text */
used_height = d->height;
}
} else if ((d->type == BOX_INLINE) ||
d->type == BOX_INLINE_BLOCK) {
/* replaced inlines and inline-blocks */
d->x += x0;
d->y = *y + d->border[TOP].width + d->margin[TOP];
h = d->margin[TOP] + d->border[TOP].width +
d->padding[TOP] + d->height +
d->padding[BOTTOM] +
d->border[BOTTOM].width +
d->margin[BOTTOM];
if (used_height < h)
used_height = h;
}
}
 
first->flags |= NEW_LINE;
 
assert(b != first || (move_y && 0 < used_height && (left || right)));
 
/* handle vertical-align by adjusting box y values */
/** \todo proper vertical alignment handling */
for (d = first; d != b; d = d->next) {
if ((d->type == BOX_INLINE && d->inline_end) ||
d->type == BOX_BR ||
d->type == BOX_TEXT ||
d->type == BOX_INLINE_END) {
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
switch (css_computed_vertical_align(d->style, &value,
&unit)) {
case CSS_VERTICAL_ALIGN_SUPER:
case CSS_VERTICAL_ALIGN_TOP:
case CSS_VERTICAL_ALIGN_TEXT_TOP:
/* already at top */
break;
case CSS_VERTICAL_ALIGN_SUB:
case CSS_VERTICAL_ALIGN_BOTTOM:
case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
d->y += used_height - d->height;
break;
default:
case CSS_VERTICAL_ALIGN_BASELINE:
d->y += 0.75 * (used_height - d->height);
break;
}
}
}
 
/* handle clearance for br */
if (br_box && css_computed_clear(br_box->style) != CSS_CLEAR_NONE) {
int clear_y = layout_clear(cont->float_children,
css_computed_clear(br_box->style));
if (used_height < clear_y - cy)
used_height = clear_y - cy;
}
 
if (move_y)
*y += used_height;
*next_box = b;
*width = x; /* return actual width */
return true;
}
 
 
/**
* Calculate minimum and maximum width of a line.
*
* \param first a box in an inline container
* \param line_min updated to minimum width of line starting at first
* \param line_max updated to maximum width of line starting at first
* \param first_line true iff this is the first line in the inline container
* \param line_has_height updated to true or false, depending on line
* \return first box in next line, or 0 if no more lines
* \post 0 <= *line_min <= *line_max
*/
 
struct box *layout_minmax_line(struct box *first,
int *line_min, int *line_max, bool first_line,
bool *line_has_height, const struct font_functions *font_func)
{
int min = 0, max = 0, width, height, fixed;
float frac;
size_t i, j;
struct box *b;
plot_font_style_t fstyle;
 
assert(first->parent);
assert(first->parent->parent);
assert(first->parent->parent->style);
 
*line_has_height = false;
 
/* corresponds to the pass 1 loop in layout_line() */
for (b = first; b; b = b->next) {
enum css_width_e wtype;
enum css_height_e htype;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK ||
b->type == BOX_FLOAT_LEFT ||
b->type == BOX_FLOAT_RIGHT ||
b->type == BOX_BR || b->type == BOX_TEXT ||
b->type == BOX_INLINE_END);
 
#ifdef LAYOUT_DEBUG
LOG(("%p: min %i, max %i", b, min, max));
#endif
 
if (b->type == BOX_BR) {
b = b->next;
break;
}
 
if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT) {
assert(b->children);
if (b->children->type == BOX_BLOCK)
layout_minmax_block(b->children, font_func);
else
layout_minmax_table(b->children, font_func);
b->min_width = b->children->min_width;
b->max_width = b->children->max_width;
if (min < b->min_width)
min = b->min_width;
max += b->max_width;
continue;
}
 
if (b->type == BOX_INLINE_BLOCK) {
layout_minmax_block(b, font_func);
if (min < b->min_width)
min = b->min_width;
max += b->max_width;
 
if (b->flags & HAS_HEIGHT)
*line_has_height = true;
continue;
}
 
assert(b->style);
font_plot_style_from_css(b->style, &fstyle);
 
if (b->type == BOX_INLINE && !b->object &&
!(b->flags & REPLACE_DIM) &&
!(b->flags & IFRAME)) {
fixed = frac = 0;
calculate_mbp_width(b->style, LEFT, true, true, true,
&fixed, &frac);
if (!b->inline_end)
calculate_mbp_width(b->style, RIGHT,
true, true, true,
&fixed, &frac);
if (0 < fixed)
max += fixed;
*line_has_height = true;
/* \todo update min width, consider fractional extra */
} else if (b->type == BOX_INLINE_END) {
fixed = frac = 0;
calculate_mbp_width(b->inline_end->style, RIGHT,
true, true, true,
&fixed, &frac);
if (0 < fixed)
max += fixed;
 
if (b->next) {
if (b->space == UNKNOWN_WIDTH) {
font_func->font_width(&fstyle, " ", 1,
&b->space);
}
max += b->space;
}
 
*line_has_height = true;
continue;
}
 
if (!b->object && !(b->flags & IFRAME) && !b->gadget &&
!(b->flags & REPLACE_DIM)) {
/* inline non-replaced, 10.3.1 and 10.6.1 */
if (!b->text)
continue;
 
if (b->width == UNKNOWN_WIDTH) {
/** \todo handle errors */
 
/* If it's a select element, we must use the
* width of the widest option text */
if (b->parent->parent->gadget &&
b->parent->parent->gadget->type
== GADGET_SELECT) {
int opt_maxwidth = 0;
struct form_option *o;
 
for (o = b->parent->parent->gadget->
data.select.items; o;
o = o->next) {
int opt_width;
font_func->font_width(&fstyle,
o->text,
strlen(o->text),
&opt_width);
 
if (opt_maxwidth < opt_width)
opt_maxwidth =opt_width;
}
 
b->width = opt_maxwidth;
if (nsoption_bool(core_select_menu))
b->width += SCROLLBAR_WIDTH;
 
} else {
font_func->font_width(&fstyle, b->text,
b->length, &b->width);
b->flags |= MEASURED;
}
}
max += b->width;
if (b->next) {
if (b->space == UNKNOWN_WIDTH) {
font_func->font_width(&fstyle, " ", 1,
&b->space);
}
max += b->space;
}
 
/* min = widest word */
if (b->parent->flags & NEED_MIN) {
/* If we care what the minimum width is,
* calculate it. (It's only needed if we're
* shrinking-to-fit.) */
i = 0;
do {
for (j = i; j != b->length &&
b->text[j] != ' '; j++)
;
font_func->font_width(&fstyle,
b->text + i,
j - i, &width);
if (min < width)
min = width;
i = j + 1;
} while (j != b->length);
}
 
*line_has_height = true;
 
continue;
}
 
/* inline replaced, 10.3.2 and 10.6.2 */
assert(b->style);
 
/* calculate box width */
wtype = css_computed_width(b->style, &value, &unit);
if (wtype == CSS_WIDTH_SET) {
if (unit == CSS_UNIT_PCT) {
/*
b->width = FPCT_OF_INT_TOINT(value, width);
*/
 
width = AUTO;
} else {
width = FIXTOINT(nscss_len2px(value, unit,
b->style));
if (width < 0)
width = 0;
}
} else {
width = AUTO;
}
 
/* height */
htype = css_computed_height(b->style, &value, &unit);
if (htype == CSS_HEIGHT_SET) {
height = FIXTOINT(nscss_len2px(value, unit, b->style));
} else {
height = AUTO;
}
 
if (b->object || (b->flags & REPLACE_DIM)) {
if (b->object) {
int temp_height = height;
layout_get_object_dimensions(b,
&width, &temp_height,
INT_MIN, INT_MAX);
}
 
fixed = frac = 0;
calculate_mbp_width(b->style, LEFT, true, true, true,
&fixed, &frac);
calculate_mbp_width(b->style, RIGHT, true, true, true,
&fixed, &frac);
 
if (0 < width + fixed)
width += fixed;
} else if (b->flags & IFRAME) {
/* TODO: handle percentage widths properly */
if (width == AUTO)
width = 400;
 
fixed = frac = 0;
calculate_mbp_width(b->style, LEFT, true, true, true,
&fixed, &frac);
calculate_mbp_width(b->style, RIGHT, true, true, true,
&fixed, &frac);
 
if (0 < width + fixed)
width += fixed;
} else {
/* form control with no object */
if (width == AUTO)
width = FIXTOINT(nscss_len2px(INTTOFIX(1),
CSS_UNIT_EM, b->style));
}
 
if (min < width)
min = width;
max += width;
 
*line_has_height = true;
}
 
if (first_line) {
/* todo: handle percentage values properly */
/* todo: handle text-indent interaction with floats */
int text_indent = layout_text_indent(
first->parent->parent->style, 100);
min = (min + text_indent < 0) ? 0 : min + text_indent;
max = (max + text_indent < 0) ? 0 : max + text_indent;
}
 
*line_min = min;
*line_max = max;
 
#ifdef LAYOUT_DEBUG
LOG(("line_min %i, line_max %i", min, max));
#endif
 
assert(b != first);
assert(0 <= *line_min);
assert(*line_min <= *line_max);
return b;
}
 
 
/**
* Calculate the text-indent length.
*
* \param style style of block
* \param width width of containing block
* \return length of indent
*/
 
int layout_text_indent(const css_computed_style *style, int width)
{
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
css_computed_text_indent(style, &value, &unit);
 
if (unit == CSS_UNIT_PCT) {
return FPCT_OF_INT_TOINT(value, width);
} else {
return FIXTOINT(nscss_len2px(value, unit, style));
}
}
 
 
/**
* Layout the contents of a float or inline block.
*
* \param b float or inline block box
* \param width available width
* \param content memory pool for any new boxes
* \return true on success, false on memory exhaustion
*/
 
bool layout_float(struct box *b, int width, html_content *content)
{
assert(b->type == BOX_TABLE || b->type == BOX_BLOCK ||
b->type == BOX_INLINE_BLOCK);
layout_float_find_dimensions(width, b->style, b);
if (b->type == BOX_TABLE) {
if (!layout_table(b, width, content))
return false;
if (b->margin[LEFT] == AUTO)
b->margin[LEFT] = 0;
if (b->margin[RIGHT] == AUTO)
b->margin[RIGHT] = 0;
if (b->margin[TOP] == AUTO)
b->margin[TOP] = 0;
if (b->margin[BOTTOM] == AUTO)
b->margin[BOTTOM] = 0;
} else
return layout_block_context(b, -1, content);
return true;
}
 
 
/**
* Position a float in the first available space.
*
* \param c float box to position
* \param width available width
* \param cx x coordinate relative to cont to place float right of
* \param y y coordinate relative to cont to place float below
* \param cont ancestor box which defines horizontal space, for floats
*/
 
void place_float_below(struct box *c, int width, int cx, int y,
struct box *cont)
{
int x0, x1, yy = y;
struct box *left;
struct box *right;
 
#ifdef LAYOUT_DEBUG
LOG(("c %p, width %i, cx %i, y %i, cont %p", c, width, cx, y, cont));
#endif
 
do {
y = yy;
x0 = cx;
x1 = cx + width;
find_sides(cont->float_children, y, y + c->height, &x0, &x1,
&left, &right);
if (left != 0 && right != 0) {
yy = (left->y + left->height <
right->y + right->height ?
left->y + left->height :
right->y + right->height);
} else if (left == 0 && right != 0) {
yy = right->y + right->height;
} else if (left != 0 && right == 0) {
yy = left->y + left->height;
}
} while (!((left == 0 && right == 0) || (c->width <= x1 - x0)));
 
if (c->type == BOX_FLOAT_LEFT) {
c->x = x0;
} else {
c->x = x1 - c->width;
}
c->y = y;
}
 
 
/**
* Layout a table.
*
* \param table table to layout
* \param available_width width of containing block
* \param content memory pool for any new boxes
* \return true on success, false on memory exhaustion
*/
 
bool layout_table(struct box *table, int available_width,
html_content *content)
{
unsigned int columns = table->columns; /* total columns */
unsigned int i;
unsigned int *row_span;
int *excess_y;
int table_width, min_width = 0, max_width = 0;
int required_width = 0;
int x, remainder = 0, count = 0;
int table_height = 0;
int min_height = 0;
int *xs; /* array of column x positions */
int auto_width;
int spare_width;
int relative_sum = 0;
int border_spacing_h = 0, border_spacing_v = 0;
int spare_height;
int positioned_columns = 0;
struct box *containing_block = NULL;
struct box *c;
struct box *row;
struct box *row_group;
struct box **row_span_cell;
struct column *col;
const css_computed_style *style = table->style;
enum css_width_e wtype;
enum css_height_e htype;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
assert(table->type == BOX_TABLE);
assert(style);
assert(table->children && table->children->children);
assert(columns);
 
/* allocate working buffers */
col = malloc(columns * sizeof col[0]);
excess_y = malloc(columns * sizeof excess_y[0]);
row_span = malloc(columns * sizeof row_span[0]);
row_span_cell = malloc(columns * sizeof row_span_cell[0]);
xs = malloc((columns + 1) * sizeof xs[0]);
if (!col || !xs || !row_span || !excess_y || !row_span_cell) {
free(col);
free(excess_y);
free(row_span);
free(row_span_cell);
free(xs);
return false;
}
 
memcpy(col, table->col, sizeof(col[0]) * columns);
 
/* find margins, paddings, and borders for table and cells */
layout_find_dimensions(available_width, -1, table, style, 0, 0, 0, 0,
table->margin, table->padding, table->border);
for (row_group = table->children; row_group;
row_group = row_group->next) {
for (row = row_group->children; row; row = row->next) {
for (c = row->children; c; c = c->next) {
assert(c->style);
table_used_border_for_cell(c);
layout_find_dimensions(available_width, -1,
c, c->style, 0, 0, 0, 0, 0,
c->padding, c->border);
if (css_computed_overflow(c->style) ==
CSS_OVERFLOW_SCROLL ||
css_computed_overflow(c->style) ==
CSS_OVERFLOW_AUTO) {
c->padding[RIGHT] += SCROLLBAR_WIDTH;
c->padding[BOTTOM] += SCROLLBAR_WIDTH;
}
}
}
}
 
/* border-spacing is used in the separated borders model */
if (css_computed_border_collapse(style) ==
CSS_BORDER_COLLAPSE_SEPARATE) {
css_fixed h = 0, v = 0;
css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
 
css_computed_border_spacing(style, &h, &hu, &v, &vu);
 
border_spacing_h = FIXTOINT(nscss_len2px(h, hu, style));
border_spacing_v = FIXTOINT(nscss_len2px(v, vu, style));
}
 
/* find specified table width, or available width if auto-width */
wtype = css_computed_width(style, &value, &unit);
if (wtype == CSS_WIDTH_SET) {
if (unit == CSS_UNIT_PCT) {
table_width = FPCT_OF_INT_TOINT(value, available_width);
} else {
table_width =
FIXTOINT(nscss_len2px(value, unit, style));
}
 
/* specified width includes border */
table_width -= table->border[LEFT].width +
table->border[RIGHT].width;
table_width = table_width < 0 ? 0 : table_width;
 
auto_width = table_width;
} else {
table_width = AUTO;
auto_width = available_width -
((table->margin[LEFT] == AUTO ? 0 :
table->margin[LEFT]) +
table->border[LEFT].width +
table->padding[LEFT] +
table->padding[RIGHT] +
table->border[RIGHT].width +
(table->margin[RIGHT] == AUTO ? 0 :
table->margin[RIGHT]));
}
 
/* Find any table height specified within CSS/HTML */
htype = css_computed_height(style, &value, &unit);
if (htype == CSS_HEIGHT_SET) {
if (unit == CSS_UNIT_PCT) {
/* This is the minimum height for the table
* (see 17.5.3) */
if (css_computed_position(table->style) ==
CSS_POSITION_ABSOLUTE) {
/* Table is absolutely positioned */
assert(table->float_container);
containing_block = table->float_container;
} else if (table->float_container &&
css_computed_position(table->style) !=
CSS_POSITION_ABSOLUTE &&
(css_computed_float(table->style) ==
CSS_FLOAT_LEFT ||
css_computed_float(table->style) ==
CSS_FLOAT_RIGHT)) {
/* Table is a float */
assert(table->parent && table->parent->parent &&
table->parent->parent->parent);
containing_block =
table->parent->parent->parent;
} else if (table->parent && table->parent->type !=
BOX_INLINE_CONTAINER) {
/* Table is a block level element */
containing_block = table->parent;
} else if (table->parent && table->parent->type ==
BOX_INLINE_CONTAINER) {
/* Table is an inline block */
assert(table->parent->parent);
containing_block = table->parent->parent;
}
 
if (containing_block) {
css_fixed ignored = 0;
 
htype = css_computed_height(
containing_block->style,
&ignored, &unit);
}
 
if (containing_block &&
containing_block->height != AUTO &&
(css_computed_position(table->style) ==
CSS_POSITION_ABSOLUTE ||
htype == CSS_HEIGHT_SET)) {
/* Table is absolutely positioned or its
* containing block has a valid specified
* height. (CSS 2.1 Section 10.5) */
min_height = FPCT_OF_INT_TOINT(value,
containing_block->height);
}
} else {
/* This is the minimum height for the table
* (see 17.5.3) */
min_height = FIXTOINT(nscss_len2px(value, unit, style));
}
}
 
/* calculate width required by cells */
for (i = 0; i != columns; i++) {
#ifdef LAYOUT_DEBUG
LOG(("table %p, column %u: type %s, width %i, min %i, max %i",
table, i,
((const char *[]) {"UNKNOWN", "FIXED", "AUTO",
"PERCENT", "RELATIVE"})[col[i].type],
col[i].width, col[i].min, col[i].max));
#endif
 
if (col[i].positioned) {
positioned_columns++;
continue;
} else if (col[i].type == COLUMN_WIDTH_FIXED) {
if (col[i].width < col[i].min)
col[i].width = col[i].max = col[i].min;
else
col[i].min = col[i].max = col[i].width;
required_width += col[i].width;
} else if (col[i].type == COLUMN_WIDTH_PERCENT) {
int width = col[i].width * auto_width / 100;
required_width += col[i].min < width ? width :
col[i].min;
} else
required_width += col[i].min;
 
#ifdef LAYOUT_DEBUG
LOG(("required_width %i", required_width));
#endif
}
required_width += (columns + 1 - positioned_columns) *
border_spacing_h;
 
#ifdef LAYOUT_DEBUG
LOG(("width %i, min %i, max %i, auto %i, required %i",
table_width, table->min_width, table->max_width,
auto_width, required_width));
#endif
 
if (auto_width < required_width) {
/* table narrower than required width for columns:
* treat percentage widths as maximums */
for (i = 0; i != columns; i++) {
if (col[i].type == COLUMN_WIDTH_RELATIVE)
continue;
if (col[i].type == COLUMN_WIDTH_PERCENT) {
col[i].max = auto_width * col[i].width / 100;
if (col[i].max < col[i].min)
col[i].max = col[i].min;
}
min_width += col[i].min;
max_width += col[i].max;
}
} else {
/* take percentages exactly */
for (i = 0; i != columns; i++) {
if (col[i].type == COLUMN_WIDTH_RELATIVE)
continue;
if (col[i].type == COLUMN_WIDTH_PERCENT) {
int width = auto_width * col[i].width / 100;
if (width < col[i].min)
width = col[i].min;
col[i].min = col[i].width = col[i].max = width;
col[i].type = COLUMN_WIDTH_FIXED;
}
min_width += col[i].min;
max_width += col[i].max;
}
}
 
/* allocate relative widths */
spare_width = auto_width;
for (i = 0; i != columns; i++) {
if (col[i].type == COLUMN_WIDTH_RELATIVE)
relative_sum += col[i].width;
else if (col[i].type == COLUMN_WIDTH_FIXED)
spare_width -= col[i].width;
else
spare_width -= col[i].min;
}
spare_width -= (columns + 1) * border_spacing_h;
if (relative_sum != 0) {
if (spare_width < 0)
spare_width = 0;
for (i = 0; i != columns; i++) {
if (col[i].type == COLUMN_WIDTH_RELATIVE) {
col[i].min = ceil(col[i].max =
(float) spare_width
* (float) col[i].width
/ relative_sum);
min_width += col[i].min;
max_width += col[i].max;
}
}
}
min_width += (columns + 1) * border_spacing_h;
max_width += (columns + 1) * border_spacing_h;
 
if (auto_width <= min_width) {
/* not enough space: minimise column widths */
for (i = 0; i < columns; i++) {
col[i].width = col[i].min;
}
table_width = min_width;
} else if (max_width <= auto_width) {
/* more space than maximum width */
if (table_width == AUTO) {
/* for auto-width tables, make columns max width */
for (i = 0; i < columns; i++) {
col[i].width = col[i].max;
}
table_width = max_width;
} else {
/* for fixed-width tables, distribute the extra space
* too */
unsigned int flexible_columns = 0;
for (i = 0; i != columns; i++)
if (col[i].type != COLUMN_WIDTH_FIXED)
flexible_columns++;
if (flexible_columns == 0) {
int extra = (table_width - max_width) / columns;
remainder = (table_width - max_width) -
(extra * columns);
for (i = 0; i != columns; i++) {
col[i].width = col[i].max + extra;
count -= remainder;
if (count < 0) {
col[i].width++;
count += columns;
}
}
 
} else {
int extra = (table_width - max_width) /
flexible_columns;
remainder = (table_width - max_width) -
(extra * flexible_columns);
for (i = 0; i != columns; i++)
if (col[i].type != COLUMN_WIDTH_FIXED) {
col[i].width = col[i].max +
extra;
count -= remainder;
if (count < 0) {
col[i].width++;
count += flexible_columns;
}
}
}
}
} else {
/* space between min and max: fill it exactly */
float scale = (float) (auto_width - min_width) /
(float) (max_width - min_width);
/* fprintf(stderr, "filling, scale %f\n", scale); */
for (i = 0; i < columns; i++) {
col[i].width = col[i].min + (int) (0.5 +
(col[i].max - col[i].min) * scale);
}
table_width = auto_width;
}
 
xs[0] = x = border_spacing_h;
for (i = 0; i != columns; i++) {
if (!col[i].positioned)
x += col[i].width + border_spacing_h;
xs[i + 1] = x;
row_span[i] = 0;
excess_y[i] = 0;
row_span_cell[i] = 0;
}
 
/* position cells */
table_height = border_spacing_v;
for (row_group = table->children; row_group;
row_group = row_group->next) {
int row_group_height = 0;
for (row = row_group->children; row; row = row->next) {
int row_height = 0;
 
htype = css_computed_height(row->style, &value, &unit);
if (htype == CSS_HEIGHT_SET && unit != CSS_UNIT_PCT) {
row_height = FIXTOINT(nscss_len2px(value, unit,
row->style));
}
for (c = row->children; c; c = c->next) {
assert(c->style);
c->width = xs[c->start_column + c->columns] -
xs[c->start_column] -
border_spacing_h -
c->border[LEFT].width -
c->padding[LEFT] -
c->padding[RIGHT] -
c->border[RIGHT].width;
c->float_children = 0;
 
c->height = AUTO;
if (!layout_block_context(c, -1, content)) {
free(col);
free(excess_y);
free(row_span);
free(row_span_cell);
free(xs);
return false;
}
/* warning: c->descendant_y0 and
* c->descendant_y1 used as temporary storage
* until after vertical alignment is complete */
c->descendant_y0 = c->height;
c->descendant_y1 = c->padding[BOTTOM];
 
htype = css_computed_height(c->style,
&value, &unit);
 
if (htype == CSS_HEIGHT_SET &&
unit != CSS_UNIT_PCT) {
/* some sites use height="1" or similar
* to attempt to make cells as small as
* possible, so treat it as a minimum */
int h = FIXTOINT(nscss_len2px(value,
unit, c->style));
if (c->height < h)
c->height = h;
}
/* specified row height is treated as a minimum
*/
if (c->height < row_height)
c->height = row_height;
c->x = xs[c->start_column] +
c->border[LEFT].width;
c->y = c->border[TOP].width;
for (i = 0; i != c->columns; i++) {
row_span[c->start_column + i] = c->rows;
excess_y[c->start_column + i] =
c->border[TOP].width +
c->padding[TOP] +
c->height +
c->padding[BOTTOM] +
c->border[BOTTOM].width;
row_span_cell[c->start_column + i] = 0;
}
row_span_cell[c->start_column] = c;
c->padding[BOTTOM] = -border_spacing_v -
c->border[TOP].width -
c->padding[TOP] -
c->height -
c->border[BOTTOM].width;
}
for (i = 0; i != columns; i++)
if (row_span[i] != 0)
row_span[i]--;
else
row_span_cell[i] = 0;
if (row->next || row_group->next) {
/* row height is greatest excess of a cell
* which ends in this row */
for (i = 0; i != columns; i++)
if (row_span[i] == 0 && row_height <
excess_y[i])
row_height = excess_y[i];
} else {
/* except in the last row */
for (i = 0; i != columns; i++)
if (row_height < excess_y[i])
row_height = excess_y[i];
}
for (i = 0; i != columns; i++) {
if (row_height < excess_y[i])
excess_y[i] -= row_height;
else
excess_y[i] = 0;
if (row_span_cell[i] != 0)
row_span_cell[i]->padding[BOTTOM] +=
row_height +
border_spacing_v;
}
 
row->x = 0;
row->y = row_group_height;
row->width = table_width;
row->height = row_height;
row_group_height += row_height + border_spacing_v;
}
row_group->x = 0;
row_group->y = table_height;
row_group->width = table_width;
row_group->height = row_group_height;
table_height += row_group_height;
}
/* Table height is either the height of the contents, or specified
* height if greater */
table_height = max(table_height, min_height);
/** \TODO distribute spare height over the row groups / rows / cells */
 
/* perform vertical alignment */
for (row_group = table->children; row_group;
row_group = row_group->next) {
for (row = row_group->children; row; row = row->next) {
for (c = row->children; c; c = c->next) {
enum css_vertical_align_e vertical_align;
 
/* unextended bottom padding is in
* c->descendant_y1, and unextended
* cell height is in c->descendant_y0 */
spare_height = (c->padding[BOTTOM] -
c->descendant_y1) +
(c->height - c->descendant_y0);
 
vertical_align = css_computed_vertical_align(
c->style, &value, &unit);
 
switch (vertical_align) {
case CSS_VERTICAL_ALIGN_SUB:
case CSS_VERTICAL_ALIGN_SUPER:
case CSS_VERTICAL_ALIGN_TEXT_TOP:
case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
case CSS_VERTICAL_ALIGN_SET:
case CSS_VERTICAL_ALIGN_BASELINE:
/* todo: baseline alignment, for now
* just use ALIGN_TOP */
case CSS_VERTICAL_ALIGN_TOP:
break;
case CSS_VERTICAL_ALIGN_MIDDLE:
c->padding[TOP] += spare_height / 2;
c->padding[BOTTOM] -= spare_height / 2;
layout_move_children(c, 0,
spare_height / 2);
break;
case CSS_VERTICAL_ALIGN_BOTTOM:
c->padding[TOP] += spare_height;
c->padding[BOTTOM] -= spare_height;
layout_move_children(c, 0,
spare_height);
break;
case CSS_VERTICAL_ALIGN_INHERIT:
assert(0);
break;
}
}
}
}
 
/* Top and bottom margins of 'auto' are set to 0. CSS2.1 10.6.3 */
if (table->margin[TOP] == AUTO)
table->margin[TOP] = 0;
if (table->margin[BOTTOM] == AUTO)
table->margin[BOTTOM] = 0;
 
free(col);
free(excess_y);
free(row_span);
free(row_span_cell);
free(xs);
 
table->width = table_width;
table->height = table_height;
 
return true;
}
 
 
/**
* Calculate minimum and maximum width of a table.
*
* \param table box of type TABLE
* \post table->min_width and table->max_width filled in,
* 0 <= table->min_width <= table->max_width
*/
 
void layout_minmax_table(struct box *table,
const struct font_functions *font_func)
{
unsigned int i, j;
int border_spacing_h = 0;
int table_min = 0, table_max = 0;
int extra_fixed = 0;
float extra_frac = 0;
struct column *col = table->col;
struct box *row_group, *row, *cell;
enum css_width_e wtype;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
/* check if the widths have already been calculated */
if (table->max_width != UNKNOWN_MAX_WIDTH)
return;
 
/* start with 0 except for fixed-width columns */
for (i = 0; i != table->columns; i++) {
if (col[i].type == COLUMN_WIDTH_FIXED)
col[i].min = col[i].max = col[i].width;
else
col[i].min = col[i].max = 0;
}
 
/* border-spacing is used in the separated borders model */
if (css_computed_border_collapse(table->style) ==
CSS_BORDER_COLLAPSE_SEPARATE) {
css_fixed h = 0, v = 0;
css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
 
css_computed_border_spacing(table->style, &h, &hu, &v, &vu);
 
border_spacing_h = FIXTOINT(nscss_len2px(h, hu, table->style));
}
 
/* 1st pass: consider cells with colspan 1 only */
for (row_group = table->children; row_group; row_group =row_group->next)
for (row = row_group->children; row; row = row->next)
for (cell = row->children; cell; cell = cell->next) {
assert(cell->type == BOX_TABLE_CELL);
assert(cell->style);
/** TODO: Handle colspan="0" correctly.
* It's currently converted to 1 in box normaisation */
assert(cell->columns != 0);
 
if (cell->columns != 1)
continue;
 
layout_minmax_block(cell, font_func);
i = cell->start_column;
 
if (col[i].positioned)
continue;
 
/* update column min, max widths using cell widths */
if (col[i].min < cell->min_width)
col[i].min = cell->min_width;
if (col[i].max < cell->max_width)
col[i].max = cell->max_width;
}
 
/* 2nd pass: cells which span multiple columns */
for (row_group = table->children; row_group; row_group =row_group->next)
for (row = row_group->children; row; row = row->next)
for (cell = row->children; cell; cell = cell->next) {
unsigned int flexible_columns = 0;
int min = 0, max = 0, fixed_width = 0, extra;
 
if (cell->columns == 1)
continue;
 
layout_minmax_block(cell, font_func);
i = cell->start_column;
 
/* find min width so far of spanned columns, and count
* number of non-fixed spanned columns and total fixed width */
for (j = 0; j != cell->columns; j++) {
min += col[i + j].min;
if (col[i + j].type == COLUMN_WIDTH_FIXED)
fixed_width += col[i + j].width;
else
flexible_columns++;
}
min += (cell->columns - 1) * border_spacing_h;
 
/* distribute extra min to spanned columns */
if (min < cell->min_width) {
if (flexible_columns == 0) {
extra = 1 + (cell->min_width - min) /
cell->columns;
for (j = 0; j != cell->columns; j++) {
col[i + j].min += extra;
if (col[i + j].max < col[i + j].min)
col[i + j].max = col[i + j].min;
}
} else {
extra = 1 + (cell->min_width - min) /
flexible_columns;
for (j = 0; j != cell->columns; j++) {
if (col[i + j].type !=
COLUMN_WIDTH_FIXED) {
col[i + j].min += extra;
if (col[i + j].max <
col[i + j].min)
col[i + j].max =
col[i + j].min;
}
}
}
}
 
/* find max width so far of spanned columns */
for (j = 0; j != cell->columns; j++)
max += col[i + j].max;
max += (cell->columns - 1) * border_spacing_h;
 
/* distribute extra max to spanned columns */
if (max < cell->max_width && flexible_columns) {
extra = 1 + (cell->max_width - max) / flexible_columns;
for (j = 0; j != cell->columns; j++)
if (col[i + j].type != COLUMN_WIDTH_FIXED)
col[i + j].max += extra;
}
}
 
for (i = 0; i != table->columns; i++) {
if (col[i].max < col[i].min) {
box_dump(stderr, table, 0);
assert(0);
}
table_min += col[i].min;
table_max += col[i].max;
}
 
/* fixed width takes priority, unless it is too narrow */
wtype = css_computed_width(table->style, &value, &unit);
if (wtype == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
int width = FIXTOINT(nscss_len2px(value, unit, table->style));
if (table_min < width)
table_min = width;
if (table_max < width)
table_max = width;
}
 
/* add margins, border, padding to min, max widths */
calculate_mbp_width(table->style, LEFT, true, true, true,
&extra_fixed, &extra_frac);
calculate_mbp_width(table->style, RIGHT, true, true, true,
&extra_fixed, &extra_frac);
if (extra_fixed < 0)
extra_fixed = 0;
if (extra_frac < 0)
extra_frac = 0;
if (1.0 <= extra_frac)
extra_frac = 0.9;
table->min_width = (table_min + extra_fixed) / (1.0 - extra_frac);
table->max_width = (table_max + extra_fixed) / (1.0 - extra_frac);
table->min_width += (table->columns + 1) * border_spacing_h;
table->max_width += (table->columns + 1) * border_spacing_h;
 
assert(0 <= table->min_width && table->min_width <= table->max_width);
}
 
 
/**
* Moves the children of a box by a specified amount
*
* \param box top of tree of boxes
* \param x the amount to move children by horizontally
* \param y the amount to move children by vertically
*/
 
void layout_move_children(struct box *box, int x, int y)
{
assert(box);
 
for (box = box->children; box; box = box->next) {
box->x += x;
box->y += y;
}
}
 
 
/**
* Determine width of margin, borders, and padding on one side of a box.
*
* \param style style to measure
* \param size side of box to measure
* \param margin whether margin width is required
* \param border whether border width is required
* \param padding whether padding width is required
* \param fixed increased by sum of fixed margin, border, and padding
* \param frac increased by sum of fractional margin and padding
*/
 
void calculate_mbp_width(const css_computed_style *style, unsigned int side,
bool margin, bool border, bool padding,
int *fixed, float *frac)
{
typedef uint8_t (*len_func)(const css_computed_style *style,
css_fixed *length, css_unit *unit);
 
static len_func margin_funcs[4] = {
css_computed_margin_top,
css_computed_margin_right,
css_computed_margin_bottom,
css_computed_margin_left
};
static len_func padding_funcs[4] = {
css_computed_padding_top,
css_computed_padding_right,
css_computed_padding_bottom,
css_computed_padding_left
};
static struct {
len_func width;
uint8_t (*style)(const css_computed_style *style);
} border_funcs[4] = {
{ css_computed_border_top_width,
css_computed_border_top_style },
{ css_computed_border_right_width,
css_computed_border_right_style },
{ css_computed_border_bottom_width,
css_computed_border_bottom_style },
{ css_computed_border_left_width,
css_computed_border_left_style }
};
 
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
assert(style);
 
/* margin */
if (margin) {
enum css_margin_e type;
 
type = margin_funcs[side](style, &value, &unit);
if (type == CSS_MARGIN_SET) {
if (unit == CSS_UNIT_PCT) {
*frac += FIXTOINT(FDIV(value, F_100));
} else {
*fixed += FIXTOINT(nscss_len2px(value, unit,
style));
}
}
}
 
/* border */
if (border) {
if (border_funcs[side].style(style) !=
CSS_BORDER_STYLE_NONE) {
border_funcs[side].width(style, &value, &unit);
 
*fixed += FIXTOINT(nscss_len2px(value, unit, style));
}
}
 
/* padding */
if (padding) {
padding_funcs[side](style, &value, &unit);
if (unit == CSS_UNIT_PCT) {
*frac += FIXTOINT(FDIV(value, F_100));
} else {
*fixed += FIXTOINT(nscss_len2px(value, unit, style));
}
}
}
 
 
/**
* Layout list markers.
*/
 
void layout_lists(struct box *box,
const struct font_functions *font_func)
{
struct box *child;
struct box *marker;
plot_font_style_t fstyle;
 
for (child = box->children; child; child = child->next) {
if (child->list_marker) {
marker = child->list_marker;
if (marker->object) {
marker->width =
content_get_width(marker->object);
marker->x = -marker->width;
marker->height =
content_get_height(marker->object);
marker->y = (line_height(marker->style) -
marker->height) / 2;
} else if (marker->text) {
if (marker->width == UNKNOWN_WIDTH) {
font_plot_style_from_css(marker->style,
&fstyle);
font_func->font_width(&fstyle,
marker->text,
marker->length,
&marker->width);
marker->flags |= MEASURED;
}
marker->x = -marker->width;
marker->y = 0;
marker->height = line_height(marker->style);
} else {
marker->x = 0;
marker->y = 0;
marker->width = 0;
marker->height = 0;
}
/* Gap between marker and content */
marker->x -= 4;
}
layout_lists(child, font_func);
}
}
 
 
/**
* Adjust positions of relatively positioned boxes.
*
* \param root box to adjust the position of
* \param fp box which forms the block formatting context for children of
* "root" which are floats
* \param fx x offset due to intervening relatively positioned boxes
* between current box, "root", and the block formatting context
* box, "fp", for float children of "root"
* \param fy y offset due to intervening relatively positioned boxes
* between current box, "root", and the block formatting context
* box, "fp", for float children of "root"
*/
 
void layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
{
struct box *box; /* for children of "root" */
struct box *fn; /* for block formatting context box for children of
* "box" */
struct box *fc; /* for float children of the block formatting context,
* "fp" */
int x, y; /* for the offsets resulting from any relative
* positioning on the current block */
int fnx, fny; /* for affsets which apply to flat children of "box" */
 
/**\todo ensure containing box is large enough after moving boxes */
 
assert(root);
 
/* Normal children */
for (box = root->children; box; box = box->next) {
 
if (box->type == BOX_TEXT)
continue;
 
/* If relatively positioned, get offsets */
if (box->style && css_computed_position(box->style) ==
CSS_POSITION_RELATIVE)
layout_compute_relative_offset(box, &x, &y);
else
x = y = 0;
 
/* Adjust float coordinates.
* (note float x and y are relative to their block formatting
* context box and not their parent) */
if (box->style && (css_computed_float(box->style) ==
CSS_FLOAT_LEFT ||
css_computed_float(box->style) ==
CSS_FLOAT_RIGHT) &&
(fx != 0 || fy != 0)) {
/* box is a float and there is a float offset to
* apply */
for (fc = fp->float_children; fc; fc = fc->next_float) {
if (box == fc->children) {
/* Box is floated in the block
* formatting context block, fp.
* Apply float offsets. */
box->x += fx;
box->y += fy;
fx = fy = 0;
}
}
}
 
if (box->float_children) {
fn = box;
fnx = fny = 0;
} else {
fn = fp;
fnx = fx + x;
fny = fy + y;
}
 
/* recurse first */
layout_position_relative(box, fn, fnx, fny);
 
/* Ignore things we're not interested in. */
if (!box->style || (box->style &&
css_computed_position(box->style) !=
CSS_POSITION_RELATIVE))
continue;
 
box->x += x;
box->y += y;
 
/* Handle INLINEs - their "children" are in fact
* the sibling boxes between the INLINE and
* INLINE_END boxes */
if (box->type == BOX_INLINE && box->inline_end) {
struct box *b;
for (b = box->next; b && b != box->inline_end;
b = b->next) {
b->x += x;
b->y += y;
}
}
}
}
 
 
/**
* Compute a box's relative offset as per CSS 2.1 9.4.3
*
* \param box Box to compute relative offsets for.
* \param x Receives relative offset in x.
* \param y Receives relative offset in y.
*/
 
void layout_compute_relative_offset(struct box *box, int *x, int *y)
{
int left, right, top, bottom;
struct box *containing_block;
 
assert(box && box->parent && box->style &&
css_computed_position(box->style) ==
CSS_POSITION_RELATIVE);
 
if (box->float_container &&
(css_computed_float(box->style) == CSS_FLOAT_LEFT ||
css_computed_float(box->style) == CSS_FLOAT_RIGHT)) {
containing_block = box->float_container;
} else {
containing_block = box->parent;
}
 
layout_compute_offsets(box, containing_block,
&top, &right, &bottom, &left);
 
if (left == AUTO && right == AUTO)
left = right = 0;
else if (left == AUTO)
/* left is auto => computed = -right */
left = -right;
else if (right == AUTO)
/* right is auto => computed = -left */
right = -left;
else {
/* over constrained => examine direction property
* of containing block */
if (containing_block->style &&
css_computed_direction(
containing_block->style) ==
CSS_DIRECTION_RTL) {
/* right wins */
left = -right;
} else {
/* assume LTR in all other cases */
right = -left;
}
}
 
assert(left == -right);
 
if (top == AUTO && bottom == AUTO)
top = bottom = 0;
else if (top == AUTO)
top = -bottom;
else if (bottom == AUTO)
bottom = -top;
else
bottom = -top;
 
#ifdef LAYOUT_DEBUG
LOG(("left %i, right %i, top %i, bottom %i", left, right, top, bottom));
#endif
 
*x = left;
*y = top;
}
 
 
/**
* Recursively layout and position absolutely positioned boxes.
*
* \param box tree of boxes to layout
* \param containing_block current containing block
* \param cx position of box relative to containing_block
* \param cy position of box relative to containing_block
* \param content memory pool for any new boxes
* \return true on success, false on memory exhaustion
*/
 
bool layout_position_absolute(struct box *box,
struct box *containing_block,
int cx, int cy,
html_content *content)
{
struct box *c;
 
for (c = box->children; c; c = c->next) {
if ((c->type == BOX_BLOCK || c->type == BOX_TABLE ||
c->type == BOX_INLINE_BLOCK) &&
(css_computed_position(c->style) ==
CSS_POSITION_ABSOLUTE ||
css_computed_position(c->style) ==
CSS_POSITION_FIXED)) {
if (!layout_absolute(c, containing_block,
cx, cy, content))
return false;
if (!layout_position_absolute(c, c, 0, 0, content))
return false;
} else if (c->style && css_computed_position(c->style) ==
CSS_POSITION_RELATIVE) {
if (!layout_position_absolute(c, c, 0, 0, content))
return false;
} else {
int px, py;
if (c->style && (css_computed_float(c->style) ==
CSS_FLOAT_LEFT ||
css_computed_float(c->style) ==
CSS_FLOAT_RIGHT)) {
/* Float x/y coords are relative to nearest
* ansestor with float_children, rather than
* relative to parent. Need to get x/y relative
* to parent */
struct box *p;
px = c->x;
py = c->y;
for (p = box->parent; p && !p->float_children;
p = p->parent) {
px -= p->x;
py -= p->y;
}
} else {
/* Not a float, so box x/y coords are relative
* to parent */
px = c->x;
py = c->y;
}
if (!layout_position_absolute(c, containing_block,
cx + px, cy + py, content))
return false;
}
}
 
return true;
}
 
 
/**
* Layout and position an absolutely positioned box.
*
* \param box absolute box to layout and position
* \param containing_block containing block
* \param cx position of box relative to containing_block
* \param cy position of box relative to containing_block
* \param content memory pool for any new boxes
* \return true on success, false on memory exhaustion
*/
 
bool layout_absolute(struct box *box, struct box *containing_block,
int cx, int cy,
html_content *content)
{
int static_left, static_top; /* static position */
int top, right, bottom, left;
int width, height, max_width, min_width;
int *margin = box->margin;
int *padding = box->padding;
struct box_border *border = box->border;
int available_width = containing_block->width;
int space;
 
assert(box->type == BOX_BLOCK || box->type == BOX_TABLE ||
box->type == BOX_INLINE_BLOCK);
 
/* The static position is where the box would be if it was not
* absolutely positioned. The x and y are filled in by
* layout_block_context(). */
static_left = cx + box->x;
static_top = cy + box->y;
 
if (containing_block->type == BOX_BLOCK ||
containing_block->type == BOX_INLINE_BLOCK ||
containing_block->type == BOX_TABLE_CELL) {
/* Block level container => temporarily increase containing
* block dimensions to include padding (we restore this
* again at the end) */
containing_block->width += containing_block->padding[LEFT] +
containing_block->padding[RIGHT];
containing_block->height += containing_block->padding[TOP] +
containing_block->padding[BOTTOM];
} else {
/** \todo inline containers */
}
 
layout_compute_offsets(box, containing_block,
&top, &right, &bottom, &left);
 
/* Pass containing block into layout_find_dimensions via the float
* containing block box member. This is unused for absolutely positioned
* boxes because a box can't be floated and absolutely positioned. */
box->float_container = containing_block;
layout_find_dimensions(available_width, -1, box, box->style,
&width, &height, &max_width, &min_width,
margin, padding, border);
box->float_container = NULL;
 
/* 10.3.7 */
#ifdef LAYOUT_DEBUG
LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
left, margin[LEFT], border[LEFT].width,
padding[LEFT], width, padding[RIGHT],
border[RIGHT].width, margin[RIGHT], right,
containing_block->width));
#endif
 
if (left == AUTO && width == AUTO && right == AUTO) {
if (margin[LEFT] == AUTO)
margin[LEFT] = 0;
if (margin[RIGHT] == AUTO)
margin[RIGHT] = 0;
left = static_left;
 
width = min(max(box->min_width, available_width),
box->max_width);
width -= box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
box->border[RIGHT].width + box->margin[RIGHT];
 
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width) width = max_width;
if (min_width > 0 && width < min_width) width = min_width;
 
right = containing_block->width -
left -
margin[LEFT] - border[LEFT].width - padding[LEFT] -
width -
padding[RIGHT] - border[RIGHT].width - margin[RIGHT];
} else if (left != AUTO && width != AUTO && right != AUTO) {
 
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width) width = max_width;
if (min_width > 0 && width < min_width) width = min_width;
 
if (margin[LEFT] == AUTO && margin[RIGHT] == AUTO) {
space = containing_block->width -
left - border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
border[RIGHT].width - right;
if (space < 0) {
margin[LEFT] = 0;
margin[RIGHT] = space;
} else {
margin[LEFT] = margin[RIGHT] = space / 2;
}
} else if (margin[LEFT] == AUTO) {
margin[LEFT] = containing_block->width -
left - border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
border[RIGHT].width - margin[RIGHT] -
right;
} else if (margin[RIGHT] == AUTO) {
margin[RIGHT] = containing_block->width -
left - margin[LEFT] -
border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
border[RIGHT].width - right;
} else {
right = containing_block->width -
left - margin[LEFT] -
border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
border[RIGHT].width - margin[RIGHT];
}
} else {
if (margin[LEFT] == AUTO)
margin[LEFT] = 0;
if (margin[RIGHT] == AUTO)
margin[RIGHT] = 0;
 
if (left == AUTO && width == AUTO && right != AUTO) {
available_width -= right;
 
width = min(max(box->min_width, available_width),
box->max_width);
width -= box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
box->border[RIGHT].width + box->margin[RIGHT];
 
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
width = max_width;
if (min_width > 0 && width < min_width)
width = min_width;
 
left = containing_block->width -
margin[LEFT] - border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
border[RIGHT].width - margin[RIGHT] -
right;
} else if (left == AUTO && width != AUTO && right == AUTO) {
 
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
width = max_width;
if (min_width > 0 && width < min_width)
width = min_width;
 
left = static_left;
right = containing_block->width -
left - margin[LEFT] -
border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
border[RIGHT].width - margin[RIGHT];
} else if (left != AUTO && width == AUTO && right == AUTO) {
available_width -= left;
 
width = min(max(box->min_width, available_width),
box->max_width);
width -= box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
box->border[RIGHT].width + box->margin[RIGHT];
 
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
width = max_width;
if (min_width > 0 && width < min_width)
width = min_width;
 
right = containing_block->width -
left - margin[LEFT] -
border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
border[RIGHT].width - margin[RIGHT];
} else if (left == AUTO && width != AUTO && right != AUTO) {
 
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
width = max_width;
if (min_width > 0 && width < min_width)
width = min_width;
 
left = containing_block->width -
margin[LEFT] - border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
border[RIGHT].width - margin[RIGHT] -
right;
} else if (left != AUTO && width == AUTO && right != AUTO) {
width = containing_block->width -
left - margin[LEFT] -
border[LEFT].width -
padding[LEFT] - padding[RIGHT] -
border[RIGHT].width - margin[RIGHT] -
right;
 
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
width = max_width;
if (min_width > 0 && width < min_width)
width = min_width;
 
} else if (left != AUTO && width != AUTO && right == AUTO) {
 
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
width = max_width;
if (min_width > 0 && width < min_width)
width = min_width;
 
right = containing_block->width -
left - margin[LEFT] -
border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
border[RIGHT].width - margin[RIGHT];
}
}
 
#ifdef LAYOUT_DEBUG
LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
left, margin[LEFT], border[LEFT].width, padding[LEFT],
width, padding[RIGHT], border[RIGHT].width,
margin[RIGHT], right,
containing_block->width));
#endif
 
box->x = left + margin[LEFT] + border[LEFT].width - cx;
if (containing_block->type == BOX_BLOCK ||
containing_block->type == BOX_INLINE_BLOCK ||
containing_block->type == BOX_TABLE_CELL) {
/* Block-level ancestor => reset container's width */
containing_block->width -= containing_block->padding[LEFT] +
containing_block->padding[RIGHT];
} else {
/** \todo inline ancestors */
}
box->width = width;
box->height = height;
 
if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
box->object || box->flags & IFRAME) {
if (!layout_block_context(box, -1, content))
return false;
} else if (box->type == BOX_TABLE) {
/* layout_table also expects the containing block to be
* stored in the float_container field */
box->float_container = containing_block;
/* \todo layout_table considers margins etc. again */
if (!layout_table(box, width, content))
return false;
box->float_container = NULL;
layout_solve_width(box, box->parent->width, box->width, 0, 0,
-1, -1);
}
 
/* 10.6.4 */
#ifdef LAYOUT_DEBUG
LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
top, margin[TOP], border[TOP].width, padding[TOP],
height, padding[BOTTOM], border[BOTTOM].width,
margin[BOTTOM], bottom,
containing_block->height));
#endif
 
if (top == AUTO && height == AUTO && bottom == AUTO) {
top = static_top;
height = box->height;
if (margin[TOP] == AUTO)
margin[TOP] = 0;
if (margin[BOTTOM] == AUTO)
margin[BOTTOM] = 0;
bottom = containing_block->height -
top - margin[TOP] - border[TOP].width -
padding[TOP] - height - padding[BOTTOM] -
border[BOTTOM].width - margin[BOTTOM];
} else if (top != AUTO && height != AUTO && bottom != AUTO) {
if (margin[TOP] == AUTO && margin[BOTTOM] == AUTO) {
space = containing_block->height -
top - border[TOP].width - padding[TOP] -
height - padding[BOTTOM] -
border[BOTTOM].width - bottom;
margin[TOP] = margin[BOTTOM] = space / 2;
} else if (margin[TOP] == AUTO) {
margin[TOP] = containing_block->height -
top - border[TOP].width - padding[TOP] -
height - padding[BOTTOM] -
border[BOTTOM].width - margin[BOTTOM] -
bottom;
} else if (margin[BOTTOM] == AUTO) {
margin[BOTTOM] = containing_block->height -
top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
padding[BOTTOM] - border[BOTTOM].width -
bottom;
} else {
bottom = containing_block->height -
top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM];
}
} else {
if (margin[TOP] == AUTO)
margin[TOP] = 0;
if (margin[BOTTOM] == AUTO)
margin[BOTTOM] = 0;
if (top == AUTO && height == AUTO && bottom != AUTO) {
height = box->height;
top = containing_block->height -
margin[TOP] - border[TOP].width -
padding[TOP] - height -
padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM] - bottom;
} else if (top == AUTO && height != AUTO && bottom == AUTO) {
top = static_top;
bottom = containing_block->height -
top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM];
} else if (top != AUTO && height == AUTO && bottom == AUTO) {
height = box->height;
bottom = containing_block->height -
top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM];
} else if (top == AUTO && height != AUTO && bottom != AUTO) {
top = containing_block->height -
margin[TOP] - border[TOP].width -
padding[TOP] - height -
padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM] - bottom;
} else if (top != AUTO && height == AUTO && bottom != AUTO) {
height = containing_block->height -
top - margin[TOP] - border[TOP].width -
padding[TOP] - padding[BOTTOM] -
border[BOTTOM].width - margin[BOTTOM] -
bottom;
} else if (top != AUTO && height != AUTO && bottom == AUTO) {
bottom = containing_block->height -
top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM];
}
}
 
#ifdef LAYOUT_DEBUG
LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
top, margin[TOP], border[TOP].width, padding[TOP],
height, padding[BOTTOM], border[BOTTOM].width,
margin[BOTTOM], bottom,
containing_block->height));
#endif
 
box->y = top + margin[TOP] + border[TOP].width - cy;
if (containing_block->type == BOX_BLOCK ||
containing_block->type == BOX_INLINE_BLOCK ||
containing_block->type == BOX_TABLE_CELL) {
/* Block-level ancestor => reset container's height */
containing_block->height -= containing_block->padding[TOP] +
containing_block->padding[BOTTOM];
} else {
/** \todo Inline ancestors */
}
box->height = height;
layout_apply_minmax_height(box, containing_block);
 
return true;
}
 
 
/**
* Compute box offsets for a relatively or absolutely positioned box with
* respect to a box.
*
* \param box box to compute offsets for
* \param containing_block box to compute percentages with respect to
* \param top updated to top offset, or AUTO
* \param right updated to right offset, or AUTO
* \param bottom updated to bottom offset, or AUTO
* \param left updated to left offset, or AUTO
*
* See CSS 2.1 9.3.2. containing_block must have width and height.
*/
 
void layout_compute_offsets(struct box *box,
struct box *containing_block,
int *top, int *right, int *bottom, int *left)
{
uint32_t type;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
assert(containing_block->width != UNKNOWN_WIDTH &&
containing_block->width != AUTO &&
containing_block->height != AUTO);
 
/* left */
type = css_computed_left(box->style, &value, &unit);
if (type == CSS_LEFT_SET) {
if (unit == CSS_UNIT_PCT) {
*left = FPCT_OF_INT_TOINT(value,
containing_block->width);
} else {
*left = FIXTOINT(nscss_len2px(value, unit, box->style));
}
} else {
*left = AUTO;
}
 
/* right */
type = css_computed_right(box->style, &value, &unit);
if (type == CSS_RIGHT_SET) {
if (unit == CSS_UNIT_PCT) {
*right = FPCT_OF_INT_TOINT(value,
containing_block->width);
} else {
*right = FIXTOINT(nscss_len2px(value, unit,
box->style));
}
} else {
*right = AUTO;
}
 
/* top */
type = css_computed_top(box->style, &value, &unit);
if (type == CSS_TOP_SET) {
if (unit == CSS_UNIT_PCT) {
*top = FPCT_OF_INT_TOINT(value,
containing_block->height);
} else {
*top = FIXTOINT(nscss_len2px(value, unit, box->style));
}
} else {
*top = AUTO;
}
 
/* bottom */
type = css_computed_bottom(box->style, &value, &unit);
if (type == CSS_BOTTOM_SET) {
if (unit == CSS_UNIT_PCT) {
*bottom = FPCT_OF_INT_TOINT(value,
containing_block->height);
} else {
*bottom = FIXTOINT(nscss_len2px(value, unit,
box->style));
}
} else {
*bottom = AUTO;
}
}
 
 
/**
* Find a box's bounding box relative to itself, i.e. the box's border edge box
*
* \param box box find bounding box of
* \param desc_x0 updated to left of box's bbox
* \param desc_y0 updated to top of box's bbox
* \param desc_x1 updated to right of box's bbox
* \param desc_y1 updated to bottom of box's bbox
*/
 
static void layout_get_box_bbox(struct box *box, int *desc_x0, int *desc_y0,
int *desc_x1, int *desc_y1)
{
*desc_x0 = -box->border[LEFT].width;
*desc_y0 = -box->border[TOP].width;
*desc_x1 = box->padding[LEFT] + box->width + box->padding[RIGHT] +
box->border[RIGHT].width;
*desc_y1 = box->padding[TOP] + box->height + box->padding[BOTTOM] +
box->border[BOTTOM].width;
}
 
 
/**
* Apply changes to box descendant_[xy][01] values due to given child.
*
* \param box box to update
* \param child a box, which may affect box's descendant bbox
* \param off_x offset to apply to child->x coord to treat as child of box
* \param off_y offset to apply to child->y coord to treat as child of box
*/
 
static void layout_update_descendant_bbox(struct box *box, struct box *child,
int off_x, int off_y)
{
int child_desc_x0, child_desc_y0, child_desc_x1, child_desc_y1;
 
/* get coordinates of child relative to box */
int child_x = child->x - off_x;
int child_y = child->y - off_y;
 
bool html_object = (child->object &&
content_get_type(child->object) == CONTENT_HTML);
 
if (child->style == NULL ||
(child->style && css_computed_overflow(child->style) ==
CSS_OVERFLOW_VISIBLE && html_object == false)) {
/* get child's descendant bbox relative to box */
child_desc_x0 = child_x + child->descendant_x0;
child_desc_y0 = child_y + child->descendant_y0;
child_desc_x1 = child_x + child->descendant_x1;
child_desc_y1 = child_y + child->descendant_y1;
} else {
/* child's descendants don't matter; use child's border edge */
layout_get_box_bbox(child, &child_desc_x0, &child_desc_y0,
&child_desc_x1, &child_desc_y1);
/* get the bbox relative to box */
child_desc_x0 += child_x;
child_desc_y0 += child_y;
child_desc_x1 += child_x;
child_desc_y1 += child_y;
}
 
/* increase box's descendant bbox to contain descendants */
if (child_desc_x0 < box->descendant_x0)
box->descendant_x0 = child_desc_x0;
if (child_desc_y0 < box->descendant_y0)
box->descendant_y0 = child_desc_y0;
if (box->descendant_x1 < child_desc_x1)
box->descendant_x1 = child_desc_x1;
if (box->descendant_y1 < child_desc_y1)
box->descendant_y1 = child_desc_y1;
}
 
 
/**
* Recursively calculate the descendant_[xy][01] values for a laid-out box tree
* and inform iframe browser windows of their size and position.
*
* \param box tree of boxes to update
*/
 
void layout_calculate_descendant_bboxes(struct box *box)
{
struct box *child;
 
assert((box->width != UNKNOWN_WIDTH) && (box->height != AUTO));
/* assert((box->width >= 0) && (box->height >= 0)); */
 
/* Initialise box's descendant box to border edge box */
layout_get_box_bbox(box, &box->descendant_x0, &box->descendant_y0,
&box->descendant_x1, &box->descendant_y1);
 
/* Extend it to contain HTML contents if box is replaced */
if (box->object && content_get_type(box->object) == CONTENT_HTML) {
if (box->descendant_x1 < content_get_width(box->object))
box->descendant_x1 = content_get_width(box->object);
if (box->descendant_y1 < content_get_height(box->object))
box->descendant_y1 = content_get_height(box->object);
}
 
if (box->iframe != NULL) {
int x, y;
box_coords(box, &x, &y);
 
browser_window_set_position(box->iframe, x, y);
browser_window_set_dimensions(box->iframe,
box->width, box->height);
browser_window_reformat(box->iframe, true,
box->width, box->height);
}
 
if (box->type == BOX_INLINE || box->type == BOX_TEXT)
return;
 
if (box->type == BOX_INLINE_END) {
box = box->inline_end;
for (child = box->next; child;
child = child->next) {
if (child->type == BOX_FLOAT_LEFT ||
child->type == BOX_FLOAT_RIGHT)
continue;
 
layout_update_descendant_bbox(box, child,
box->x, box->y);
 
if (child == box->inline_end)
break;
}
return;
}
 
if (box->flags & REPLACE_DIM)
/* Box's children aren't displayed if the box is replaced */
return;
 
for (child = box->children; child; child = child->next) {
if (child->type == BOX_FLOAT_LEFT ||
child->type == BOX_FLOAT_RIGHT)
continue;
 
layout_calculate_descendant_bboxes(child);
 
if (box->style && css_computed_overflow(box->style) ==
CSS_OVERFLOW_HIDDEN)
continue;
 
layout_update_descendant_bbox(box, child, 0, 0);
}
 
for (child = box->float_children; child; child = child->next_float) {
assert(child->type == BOX_FLOAT_LEFT ||
child->type == BOX_FLOAT_RIGHT);
 
layout_calculate_descendant_bboxes(child);
 
layout_update_descendant_bbox(box, child, 0, 0);
}
 
if (box->list_marker) {
child = box->list_marker;
layout_calculate_descendant_bboxes(child);
 
layout_update_descendant_bbox(box, child, 0, 0);
}
}
 
/programs/network/netsurf/netsurf/render/layout.h
0,0 → 1,39
/*
* Copyright 2003 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* HTML layout (interface).
*
* The main interface to the layout code is layout_document(), which takes a
* normalized box tree and assigns coordinates and dimensions to the boxes, and
* also adds boxes to the tree (eg. when formatting lines of text).
*/
 
#ifndef _NETSURF_RENDER_LAYOUT_H_
#define _NETSURF_RENDER_LAYOUT_H_
 
struct box;
struct html_content;
 
bool layout_document(struct html_content *content, int width, int height);
bool layout_inline_container(struct box *box, int width,
struct box *cont, int cx, int cy, struct html_content *content);
void layout_calculate_descendant_bboxes(struct box *box);
void layout_minmax_table(struct box *table,
const struct font_functions *font_func);
#endif
/programs/network/netsurf/netsurf/render/list.c
0,0 → 1,483
/*
* Copyright 2005 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* HTML lists (implementation).
*/
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "css/css.h"
#include "render/list.h"
#include "utils/log.h"
 
 
struct list_counter {
char *name; /** Counter name */
struct list_counter_state *first; /** First counter state */
struct list_counter_state *state; /** Current counter state */
struct list_counter *next; /** Next counter */
};
 
struct list_counter_state {
int count; /** Current count */
struct list_counter_state *parent; /** Parent counter, or NULL */
struct list_counter_state *next; /** Next counter, or NULL */
};
 
static struct list_counter *list_counter_pool = NULL;
static char list_counter_workspace[16];
 
static const char *list_counter_roman[] = { "I", "IV", "V", "IX",
"X", "XL", "L", "XC",
"C", "CD", "D", "CM",
"M"};
static const int list_counter_decimal[] = { 1, 4, 5, 9,
10, 40, 50, 90,
100, 400, 500, 900,
1000};
#define ROMAN_DECIMAL_CONVERSIONS (sizeof(list_counter_decimal) \
/ sizeof(list_counter_decimal[0]))
 
 
static struct list_counter *render_list_find_counter(const char *name);
static char *render_list_encode_counter(struct list_counter_state *state,
enum css_list_style_type_e style);
static char *render_list_encode_roman(int value);
 
/*
static void render_list_counter_output(char *name);
*/
 
/**
* Finds a counter from the current pool, or adds a new one.
*
* \param name the name of the counter to find
* \return the counter, or NULL if it couldn't be found/created.
*/
static struct list_counter *render_list_find_counter(const char *name) {
struct list_counter *counter;
 
assert(name);
/* find a current counter */
for (counter = list_counter_pool; counter; counter = counter->next)
if (!strcasecmp(name, counter->name))
return counter;
 
/* create a new counter */
counter = calloc(1, sizeof(struct list_counter));
if (!counter) {
LOG(("No memory for calloc()"));
return NULL;
}
counter->name = malloc(strlen(name) + 1);
if (!counter->name) {
LOG(("No memory for malloc()"));
free(counter);
return NULL;
}
strcpy(counter->name, name);
counter->next = list_counter_pool;
list_counter_pool = counter;
return counter;
}
 
 
/**
* Removes all counters from the current pool.
*/
void render_list_destroy_counters(void) {
struct list_counter *counter = list_counter_pool;
struct list_counter *next_counter;
struct list_counter_state *state;
struct list_counter_state *next_state;
 
while (counter) {
next_counter = counter->next;
free(counter->name);
state = counter->first;
free(counter);
counter = next_counter;
while (state) {
next_state = state->next;
free(state);
state = next_state;
}
}
list_counter_pool = NULL;
}
 
 
/**
* Resets a counter in accordance with counter-reset (CSS 2.1/12.4).
*
* \param name the name of the counter to reset
* \param value the value to reset the counter to
* \return true on success, false on failure.
*/
bool render_list_counter_reset(const char *name, int value) {
struct list_counter *counter;
struct list_counter_state *state;
struct list_counter_state *link;
 
assert(name);
counter = render_list_find_counter(name);
if (!counter)
return false;
state = calloc(1, sizeof(struct list_counter_state));
if (!state) {
LOG(("No memory for calloc()"));
return false;
}
state->count = value;
state->parent = counter->state;
counter->state = state;
if (!counter->first) {
counter->first = state;
} else {
for (link = counter->first; link->next; link = link->next);
link->next = state;
}
/* render_list_counter_output(name);
*/ return true;
}
 
 
/**
* Increments a counter in accordance with counter-increment (CSS 2.1/12.4).
*
* \param name the name of the counter to reset
* \param value the value to increment the counter by
* \return true on success, false on failure.
*/
bool render_list_counter_increment(const char *name, int value) {
struct list_counter *counter;
 
assert(name);
counter = render_list_find_counter(name);
if (!counter)
return false;
/* if no counter-reset used, it is assumed the counter has been reset
* to 0 by the root element. */
if (!counter->state) {
if (counter->first) {
counter->state = counter->first;
counter->state->count = 0;
} else {
render_list_counter_reset(name, 0);
}
}
if (counter->state)
counter->state->count += value;
/* render_list_counter_output(name);
*/ return counter->state != NULL;
}
 
 
/**
* Ends the scope of a counter.
*
* \param name the name of the counter to end the scope for
* \return true on success, false on failure.
*/
bool render_list_counter_end_scope(const char *name) {
struct list_counter *counter;
 
assert(name);
counter = render_list_find_counter(name);
if ((!counter) || (!counter->state))
return false;
counter->state = counter->state->parent;
/* render_list_counter_output(name);
*/ return true;
}
 
 
/**
* Returns a textual representation of a counter for counter() or counters()
* (CSS 2.1/12.2).
*
* \param css_counter the counter to convert
* \return a textual representation of the counter, or NULL on failure
*/
char *render_list_counter(const css_computed_content_item *css_counter) {
struct list_counter *counter;
struct list_counter_state *state;
char *compound = NULL;
char *merge, *extend;
lwc_string *name = NULL, *sep = NULL;
uint8_t style;
 
assert(css_counter);
 
if (css_counter->type == CSS_COMPUTED_CONTENT_COUNTER) {
name = css_counter->data.counter.name;
style = css_counter->data.counter.style;
} else {
assert(css_counter->type == CSS_COMPUTED_CONTENT_COUNTERS);
 
name = css_counter->data.counters.name;
sep = css_counter->data.counters.sep;
style = css_counter->data.counters.style;
}
 
counter = render_list_find_counter(lwc_string_data(name));
if (!counter) {
LOG(("Failed to find/create counter for conversion"));
return NULL;
}
 
/* handle counter() first */
if (sep == NULL)
return render_list_encode_counter(counter->state, style);
 
/* loop through all states for counters() */
for (state = counter->first; state; state = state->next) {
merge = render_list_encode_counter(state, style);
if (!merge) {
free(compound);
return NULL;
}
if (!compound) {
compound = merge;
} else {
extend = realloc(compound, strlen(compound) +
strlen(merge) + 1);
if (!extend) {
LOG(("No memory for realloc()"));
free(compound);
free(merge);
return NULL;
}
compound = extend;
strcat(compound, merge);
}
if (state->next) {
merge = realloc(compound, strlen(compound) +
lwc_string_length(sep) + 1);
if (!merge) {
LOG(("No memory for realloc()"));
free(compound);
return NULL;
}
compound = merge;
strcat(compound, lwc_string_data(sep));
}
}
return compound;
}
 
 
/**
* Returns a textual representation of a counter state in a specified style.
*
* \param state the counter state to represent
* \param style the counter style to use
* \return a textual representation of the counter state, or NULL on failure
*/
static char *render_list_encode_counter(struct list_counter_state *state,
enum css_list_style_type_e style) {
char *result = NULL;
int i;
 
/* no counter state means that the counter is currently out of scope */
if (!state) {
result = malloc(1);
if (!result)
return NULL;
result[0] = '\0';
return result;
}
 
/* perform the relevant encoding to upper case where applicable */
switch (style) {
case CSS_LIST_STYLE_TYPE_LOWER_ALPHA:
case CSS_LIST_STYLE_TYPE_UPPER_ALPHA:
if (state->count <= 0)
result = calloc(1, 1);
else
result = malloc(2);
if (!result)
return NULL;
if (state->count > 0) {
result[0] = 'A' + (state->count - 1) % 26;
result[1] = '\0';
}
break;
case CSS_LIST_STYLE_TYPE_DISC:
case CSS_LIST_STYLE_TYPE_CIRCLE:
case CSS_LIST_STYLE_TYPE_SQUARE:
result = malloc(2);
if (!result)
return NULL;
result[0] = '?';
result[1] = '\0';
break;
case CSS_LIST_STYLE_TYPE_LOWER_ROMAN:
case CSS_LIST_STYLE_TYPE_UPPER_ROMAN:
result = render_list_encode_roman(state->count);
if (!result)
return NULL;
break;
case CSS_LIST_STYLE_TYPE_DECIMAL:
snprintf(list_counter_workspace,
sizeof list_counter_workspace,
"%i", state->count);
result = malloc(strlen(list_counter_workspace) + 1);
if (!result)
return NULL;
strcpy(result, list_counter_workspace);
break;
case CSS_LIST_STYLE_TYPE_NONE:
result = malloc(1);
if (!result)
return NULL;
result[0] = '\0';
break;
default:
break;
}
 
/* perform case conversion */
if ((style == CSS_LIST_STYLE_TYPE_LOWER_ALPHA) ||
(style == CSS_LIST_STYLE_TYPE_LOWER_ROMAN))
for (i = 0; result[i]; i++)
result[i] = tolower(result[i]);
 
return result;
}
 
 
/**
* Encodes a value in roman numerals.
* For values that cannot be represented (ie <=0) an empty string is returned.
*
* \param value the value to represent
* \return a string containing the representation, or NULL on failure
*/
static char *render_list_encode_roman(int value) {
int i, overflow, p = 0;
char temp[10];
char *result;
 
/* zero and below is returned as an empty string and not erred as
* if it is counters() will fail to complete other scopes. */
if (value <= 0) {
result = malloc(1);
if (!result)
return NULL;
result[0] = '\0';
return result;
}
 
/* we only calculate 1->999 and then add a M for each thousand */
overflow = value / 1000;
value = value % 1000;
 
/* work backwards through the array */
for (i = ROMAN_DECIMAL_CONVERSIONS - 1; i >= 0; i--) {
while (value >= list_counter_decimal[0]) {
if (value - list_counter_decimal[i] <
list_counter_decimal[0] - 1)
break;
value -= list_counter_decimal[i];
temp[p++] = list_counter_roman[i][0];
if (i & 0x1)
temp[p++] = list_counter_roman[i][1];
}
}
temp[p] = '\0';
 
/* create a copy for the caller including thousands */
result = malloc(p + overflow + 1);
if (!result)
return NULL;
for (i = 0; i < overflow; i++)
result[i] = 'M';
strcpy(&result[overflow], temp);
return result;
}
 
 
 
 
 
 
 
 
void render_list_test(void) {
/* example given in CSS2.1/12.4.1 */
/* render_list_counter_reset("item", 0);
render_list_counter_increment("item", 1);
render_list_counter_increment("item", 1);
render_list_counter_reset("item", 0);
render_list_counter_increment("item", 1);
render_list_counter_increment("item", 1);
render_list_counter_increment("item", 1);
render_list_counter_reset("item", 0);
render_list_counter_increment("item", 1);
render_list_counter_end_scope("item");
render_list_counter_reset("item", 0);
render_list_counter_increment("item", 1);
render_list_counter_end_scope("item");
render_list_counter_increment("item", 1);
render_list_counter_end_scope("item");
render_list_counter_increment("item", 1);
render_list_counter_increment("item", 1);
render_list_counter_end_scope("item");
render_list_counter_reset("item", 0);
render_list_counter_increment("item", 1);
render_list_counter_increment("item", 1);
render_list_counter_end_scope("item");
*/
}
/*
static void render_list_counter_output(char *name) {
struct list_counter *counter;
char *result;
struct css_counter css_counter;
 
assert(name);
counter = render_list_find_counter(name);
if (!counter) {
fprintf(stderr, "Unable to create counter '%s'\n", name);
return;
}
 
css_counter.name = name;
css_counter.style = CSS_LIST_STYLE_TYPE_LOWER_ALPHA;
css_counter.separator = NULL;
result = render_list_counter(&css_counter);
if (!result) {
fprintf(stderr, "Failed to output counter('%s')\n", name);
} else {
fprintf(stderr, "counter('%s') is '%s'\n", name, result);
free(result);
}
css_counter.separator = ".";
result = render_list_counter(&css_counter);
if (!result) {
fprintf(stderr, "Failed to output counters('%s', '.')\n", name);
} else {
fprintf(stderr, "counters('%s', '.') is '%s'\n", name, result);
free(result);
}
}
*/
/programs/network/netsurf/netsurf/render/list.h
0,0 → 1,38
/*
* Copyright 2005 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* HTML lists (interface).
*/
 
#ifndef _NETSURF_RENDER_LIST_H_
#define _NETSURF_RENDER_LIST_H_
 
#include <stdbool.h>
 
#include "css/css.h"
 
void render_list_destroy_counters(void);
bool render_list_counter_reset(const char *name, int value);
bool render_list_counter_increment(const char *name, int value);
bool render_list_counter_end_scope(const char *name);
char *render_list_counter(const css_computed_content_item *css_counter);
 
void render_list_test(void);
 
#endif
/programs/network/netsurf/netsurf/render/make.render
0,0 → 1,25
CFLAGS += -O2
NETSURF_FB_FRONTEND := sdl
NETSURF_FB_FONTLIB := internal
 
NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
 
# Default resource install path
NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
 
# Default framebuffer search path
NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
 
# freetype compiled in font serch path
NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
OBJS := box.o box_construct.o box_normalise.o \
font.o form.o \
html.o html_script.o html_interaction.o html_redraw.o \
html_forms.o imagemap.o layout.o list.o search.o table.o \
textinput.o textplain.o
 
 
OUTFILE = TEST.o
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include
include $(MENUETDEV)/makefiles/Makefile_for_o_lib
/programs/network/netsurf/netsurf/render/search.c
0,0 → 1,723
/*
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
* Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file
* Free text search (core)
*/
#include "utils/config.h"
 
#include <ctype.h>
#include <string.h>
 
#include <dom/dom.h>
 
#include "content/content.h"
#include "content/hlcache.h"
#include "desktop/gui.h"
#include "desktop/selection.h"
#include "render/box.h"
#include "render/html.h"
#include "render/html_internal.h"
#include "render/search.h"
#include "render/textplain.h"
#include "utils/config.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/utils.h"
 
 
#ifndef NOF_ELEMENTS
#define NOF_ELEMENTS(array) (sizeof(array)/sizeof(*(array)))
#endif
 
 
struct list_entry {
unsigned start_idx; /* start position of match */
unsigned end_idx; /* end of match */
 
struct box *start_box; /* used only for html contents */
struct box *end_box;
 
struct selection *sel;
 
struct list_entry *prev;
struct list_entry *next;
};
 
struct search_context {
struct search_callbacks callbacks;
struct content *c;
struct list_entry *found;
struct list_entry *current; /* first for select all */
char *string;
bool prev_case_sens;
bool newsearch;
bool is_html;
};
 
 
/**
* create a search_context
* \param h the hlcache_handle the search_context is connected to
* \param callbacks the callbacks to modify appearance according to results
* \param p the pointer to send to the callbacks
* \return true for success
*/
struct search_context * search_create_context(hlcache_handle *h,
struct search_callbacks callbacks)
{
struct search_context *context;
struct list_entry *search_head;
struct content *c = hlcache_handle_get_content(h);
 
if (h == NULL)
return NULL;
 
if (content_get_type(h) != CONTENT_HTML &&
content_get_type(h) != CONTENT_TEXTPLAIN) {
return NULL;
}
 
context = malloc(sizeof(struct search_context));
if (context == NULL) {
warn_user("NoMemory", 0);
return NULL;
}
 
search_head = malloc(sizeof(struct list_entry));
if (search_head == NULL) {
warn_user("NoMemory", 0);
free(context);
return NULL;
}
 
search_head->start_idx = 0;
search_head->end_idx = 0;
search_head->start_box = NULL;
search_head->end_box = NULL;
search_head->sel = NULL;
search_head->prev = NULL;
search_head->next = NULL;
 
context->found = search_head;
context->current = NULL;
context->string = NULL;
context->prev_case_sens = false;
context->newsearch = true;
context->c = c;
context->is_html = (content_get_type(h) == CONTENT_HTML) ? true : false;
context->callbacks = callbacks;
 
if (context->is_html) {
html_set_search(context->c, context);
} else {
textplain_set_search(context->c, context);
}
 
return context;
}
 
 
/**
* Release the memory used by the list of matches,
* deleting selection objects too
*/
 
static void free_matches(struct search_context *context)
{
struct list_entry *a;
struct list_entry *b;
a = context->found->next;
 
/* empty the list before clearing and deleting the
selections because the the clearing updates the
screen immediately, causing nested accesses to the list */
 
context->found->prev = NULL;
context->found->next = NULL;
 
for (; a; a = b) {
b = a->next;
if (a->sel) {
selection_clear(a->sel, true);
selection_destroy(a->sel);
}
free(a);
}
}
 
 
/**
* Find the first occurrence of 'match' in 'string' and return its index
*
* \param string the string to be searched (unterminated)
* \param s_len length of the string to be searched
* \param pattern the pattern for which we are searching (unterminated)
* \param p_len length of pattern
* \param case_sens true iff case sensitive match required
* \param m_len accepts length of match in bytes
* \return pointer to first match, NULL if none
*/
 
static const char *find_pattern(const char *string, int s_len,
const char *pattern, int p_len, bool case_sens,
unsigned int *m_len)
{
struct { const char *ss, *s, *p; bool first; } context[16];
const char *ep = pattern + p_len;
const char *es = string + s_len;
const char *p = pattern - 1; /* a virtual '*' before the pattern */
const char *ss = string;
const char *s = string;
bool first = true;
int top = 0;
 
while (p < ep) {
bool matches;
if (p < pattern || *p == '*') {
char ch;
 
/* skip any further asterisks; one is the same as many
*/
do p++; while (p < ep && *p == '*');
 
/* if we're at the end of the pattern, yes, it matches
*/
if (p >= ep) break;
 
/* anything matches a # so continue matching from
here, and stack a context that will try to match
the wildcard against the next character */
 
ch = *p;
if (ch != '#') {
/* scan forwards until we find a match for
this char */
if (!case_sens) ch = toupper(ch);
while (s < es) {
if (case_sens) {
if (*s == ch) break;
} else if (toupper(*s) == ch)
break;
s++;
}
}
 
if (s < es) {
/* remember where we are in case the match
fails; we may then resume */
if (top < (int)NOF_ELEMENTS(context)) {
context[top].ss = ss;
context[top].s = s + 1;
context[top].p = p - 1;
/* ptr to last asterisk */
context[top].first = first;
top++;
}
 
if (first) {
ss = s;
/* remember first non-'*' char */
first = false;
}
 
matches = true;
}
else
matches = false;
}
else if (s < es) {
char ch = *p;
if (ch == '#')
matches = true;
else {
if (case_sens)
matches = (*s == ch);
else
matches = (toupper(*s) == toupper(ch));
}
if (matches && first) {
ss = s; /* remember first non-'*' char */
first = false;
}
}
else
matches = false;
 
if (matches) {
p++; s++;
}
else {
/* doesn't match, resume with stacked context if we have one */
if (--top < 0) return NULL; /* no match, give up */
 
ss = context[top].ss;
s = context[top].s;
p = context[top].p;
first = context[top].first;
}
}
 
/* end of pattern reached */
*m_len = max(s - ss, 1);
return ss;
}
 
 
/**
* Add a new entry to the list of matches
*
* \param start_idx offset of match start within textual representation
* \param end_idx offset of match end
* \return pointer to added entry, NULL iff failed
*/
 
static struct list_entry *add_entry(unsigned start_idx, unsigned end_idx,
struct search_context *context)
{
struct list_entry *entry;
 
/* found string in box => add to list */
entry = calloc(1, sizeof(*entry));
if (!entry) {
warn_user("NoMemory", 0);
return NULL;
}
 
entry->start_idx = start_idx;
entry->end_idx = end_idx;
entry->sel = NULL;
 
entry->next = 0;
entry->prev = context->found->prev;
if (context->found->prev == NULL)
context->found->next = entry;
else
context->found->prev->next = entry;
context->found->prev = entry;
 
return entry;
}
 
 
/**
* Finds all occurrences of a given string in the html box tree
*
* \param pattern the string pattern to search for
* \param p_len pattern length
* \param cur pointer to the current box
* \param case_sens whether to perform a case sensitive search
* \return true on success, false on memory allocation failure
*/
static bool find_occurrences_html(const char *pattern, int p_len,
struct box *cur, bool case_sens,
struct search_context *context)
{
struct box *a;
 
/* ignore this box, if there's no visible text */
if (!cur->object && cur->text) {
const char *text = cur->text;
unsigned length = cur->length;
 
while (length > 0) {
struct list_entry *entry;
unsigned match_length;
unsigned match_offset;
const char *new_text;
const char *pos = find_pattern(text, length,
pattern, p_len, case_sens,
&match_length);
if (!pos) break;
 
/* found string in box => add to list */
match_offset = pos - cur->text;
 
entry = add_entry(cur->byte_offset + match_offset,
cur->byte_offset +
match_offset +
match_length, context);
if (!entry)
return false;
 
entry->start_box = cur;
entry->end_box = cur;
 
new_text = pos + match_length;
length -= (new_text - text);
text = new_text;
}
}
 
/* and recurse */
for (a = cur->children; a; a = a->next) {
if (!find_occurrences_html(pattern, p_len, a, case_sens,
context))
return false;
}
 
return true;
}
 
 
/**
* Finds all occurrences of a given string in a textplain content
*
* \param pattern the string pattern to search for
* \param p_len pattern length
* \param c the content to be searched
* \param case_sens wheteher to perform a case sensitive search
* \return true on success, false on memory allocation failure
*/
 
static bool find_occurrences_text(const char *pattern, int p_len,
struct content *c, bool case_sens,
struct search_context *context)
{
int nlines = textplain_line_count(c);
int line;
 
for(line = 0; line < nlines; line++) {
size_t offset, length;
const char *text = textplain_get_line(c, line,
&offset, &length);
if (text) {
while (length > 0) {
struct list_entry *entry;
unsigned match_length;
size_t start_idx;
const char *new_text;
const char *pos = find_pattern(text, length,
pattern, p_len, case_sens,
&match_length);
if (!pos) break;
 
/* found string in line => add to list */
start_idx = offset + (pos - text);
entry = add_entry(start_idx, start_idx +
match_length, context);
if (!entry)
return false;
 
new_text = pos + match_length;
offset += (new_text - text);
length -= (new_text - text);
text = new_text;
}
}
}
 
return true;
}
 
 
/**
* Search for a string in the box tree
*
* \param string the string to search for
* \param string_len length of search string
*/
static void search_text(const char *string, int string_len,
struct search_context *context, search_flags_t flags)
{
struct rect bounds;
struct box *box = NULL;
union content_msg_data msg_data;
bool case_sensitive, forwards, showall;
 
case_sensitive = ((flags & SEARCH_FLAG_CASE_SENSITIVE) != 0) ?
true : false;
forwards = ((flags & SEARCH_FLAG_FORWARDS) != 0) ? true : false;
showall = ((flags & SEARCH_FLAG_SHOWALL) != 0) ? true : false;
 
if (context->c == NULL)
return;
 
if (context->is_html == true) {
html_content *html = (html_content *)context->c;
 
box = html->layout;
 
if (!box)
return;
}
 
/* LOG(("do_search '%s' - '%s' (%p, %p) %p (%d, %d) %d",
search_data.string, string, search_data.content, c, search_data.found->next,
search_data.prev_case_sens, case_sens, forwards)); */
 
/* check if we need to start a new search or continue an old one */
if (context->newsearch) {
bool res;
 
if (context->string != NULL)
free(context->string);
context->current = NULL;
free_matches(context);
 
context->string = malloc(string_len + 1);
if (context->string != NULL) {
memcpy(context->string, string, string_len);
context->string[string_len] = '\0';
}
 
if ((context->callbacks.gui != NULL) &&
(context->callbacks.gui->hourglass != NULL))
context->callbacks.gui->hourglass(true,
context->callbacks.gui_p);
 
if (context->is_html == true) {
res = find_occurrences_html(string, string_len,
box, case_sensitive, context);
} else {
res = find_occurrences_text(string, string_len,
context->c, case_sensitive, context);
}
 
if (!res) {
free_matches(context);
if ((context->callbacks.gui != NULL) &&
(context->callbacks.gui->hourglass !=
NULL))
context->callbacks.gui->hourglass(false,
context->callbacks.gui_p);
return;
}
if ((context->callbacks.gui != NULL) &&
(context->callbacks.gui->hourglass != NULL))
context->callbacks.gui->hourglass(false,
context->callbacks.gui_p);
 
context->prev_case_sens = case_sensitive;
/* LOG(("%d %p %p (%p, %p)", new, search_data.found->next, search_data.current,
search_data.current->prev, search_data.current->next)); */
/* new search, beginning at the top of the page */
context->current = context->found->next;
context->newsearch = false;
}
else if (context->current != NULL) {
/* continued search in the direction specified */
if (forwards) {
if (context->current->next)
context->current = context->current->next;
}
else {
if (context->current->prev)
context->current = context->current->prev;
}
}
 
if (context->callbacks.gui == NULL)
return;
if (context->callbacks.gui->status != NULL)
context->callbacks.gui->status((context->current != NULL),
context->callbacks.gui_p);
search_show_all(showall, context);
 
if (context->callbacks.gui->back_state != NULL)
context->callbacks.gui->back_state((context->current != NULL) &&
(context->current->prev != NULL),
context->callbacks.gui_p);
if (context->callbacks.gui->forward_state != NULL)
context->callbacks.gui->forward_state(
(context->current != NULL) &&
(context->current->next != NULL),
context->callbacks.gui_p);
 
if (context->current == NULL)
return;
 
if (context->is_html == true) {
/* get box position and jump to it */
box_coords(context->current->start_box, &bounds.x0, &bounds.y0);
/* \todo: move x0 in by correct idx */
box_coords(context->current->end_box, &bounds.x1, &bounds.y1);
/* \todo: move x1 in by correct idx */
bounds.x1 += context->current->end_box->width;
bounds.y1 += context->current->end_box->height;
} else {
textplain_coords_from_range(context->c,
context->current->start_idx,
context->current->end_idx, &bounds);
}
 
msg_data.scroll.area = true;
msg_data.scroll.x0 = bounds.x0;
msg_data.scroll.y0 = bounds.y0;
msg_data.scroll.x1 = bounds.x1;
msg_data.scroll.y1 = bounds.y1;
content_broadcast(context->c, CONTENT_MSG_SCROLL, msg_data);
}
 
 
/**
* Begins/continues the search process
* Note that this may be called many times for a single search.
*
* \param bw the browser_window to search in
* \param flags the flags forward/back etc
* \param string the string to match
*/
 
void search_step(struct search_context *context, search_flags_t flags,
const char *string)
{
int string_len;
int i = 0;
 
if ((context == NULL) || (context->callbacks.gui == NULL)) {
warn_user("SearchError", 0);
return;
}
 
if (context->callbacks.gui->add_recent != NULL)
context->callbacks.gui->add_recent(string,
context->callbacks.gui_p);
 
string_len = strlen(string);
for(i = 0; i < string_len; i++)
if (string[i] != '#' && string[i] != '*') break;
if (i >= string_len) {
union content_msg_data msg_data;
free_matches(context);
if (context->callbacks.gui->status != NULL)
context->callbacks.gui->status(true,
context->callbacks.gui_p);
if (context->callbacks.gui->back_state != NULL)
context->callbacks.gui->back_state(false,
context->callbacks.gui_p);
if (context->callbacks.gui->forward_state != NULL)
context->callbacks.gui->forward_state(false,
context->callbacks.gui_p);
 
msg_data.scroll.area = false;
msg_data.scroll.x0 = 0;
msg_data.scroll.y0 = 0;
content_broadcast(context->c, CONTENT_MSG_SCROLL, msg_data);
return;
}
search_text(string, string_len, context, flags);
}
 
 
/**
* Determines whether any portion of the given text box should be
* selected because it matches the current search string.
*
* \param bw browser window
* \param start_offset byte offset within text of string to be checked
* \param end_offset byte offset within text
* \param start_idx byte offset within string of highlight start
* \param end_idx byte offset of highlight end
* \return true iff part of the box should be highlighted
*/
 
bool search_term_highlighted(struct content *c,
unsigned start_offset, unsigned end_offset,
unsigned *start_idx, unsigned *end_idx,
struct search_context *context)
{
if (c == context->c) {
struct list_entry *a;
for(a = context->found->next; a; a = a->next)
if (a->sel && selection_defined(a->sel) &&
selection_highlighted(a->sel,
start_offset, end_offset,
start_idx, end_idx))
return true;
}
 
return false;
}
 
 
/**
* Specifies whether all matches or just the current match should
* be highlighted in the search text.
*/
 
void search_show_all(bool all, struct search_context *context)
{
struct list_entry *a;
 
for (a = context->found->next; a; a = a->next) {
bool add = true;
if (!all && a != context->current) {
add = false;
if (a->sel) {
selection_clear(a->sel, true);
selection_destroy(a->sel);
a->sel = NULL;
}
}
if (add && !a->sel) {
 
if (context->is_html == true) {
html_content *html = (html_content *)context->c;
a->sel = selection_create(context->c, true);
if (!a->sel)
continue;
 
selection_init(a->sel, html->layout);
} else {
a->sel = selection_create(context->c, false);
if (!a->sel)
continue;
 
selection_init(a->sel, NULL);
}
 
selection_set_start(a->sel, a->start_idx);
selection_set_end(a->sel, a->end_idx);
}
}
}
 
 
/**
* Ends the search process, invalidating all state
* freeing the list of found boxes
*/
void search_destroy_context(struct search_context *context)
{
assert(context != NULL);
 
if (context->callbacks.invalidate != NULL) {
context->callbacks.invalidate(context, context->callbacks.p);
}
 
if (context->c != NULL) {
 
if (context->is_html)
html_set_search(context->c, NULL);
else
textplain_set_search(context->c, NULL);
}
if ((context->string != NULL) && (context->callbacks.gui != NULL) &&
(context->callbacks.gui->add_recent != NULL)) {
context->callbacks.gui->add_recent(context->string,
context->callbacks.gui_p);
free(context->string);
}
free_matches(context);
free(context);
}
/programs/network/netsurf/netsurf/render/search.h
0,0 → 1,58
/*
* Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef _NETSURF_RENDER_SEARCH_H_
#define _NETSURF_RENDER_SEARCH_H_
 
#include <ctype.h>
#include <string.h>
 
#include "desktop/search.h"
 
struct search_context;
 
/**
* Called when a search context is destroyed
* \param context search context being invalidated
* \param p pointer for client data
*/
typedef void (*search_invalidate_callback)(struct search_context *context,
void *p);
 
struct search_callbacks {
struct gui_search_callbacks *gui;
void *gui_p; /* private gui owned data */
search_invalidate_callback invalidate;
void *p; /* private client data */
};
 
 
struct search_context * search_create_context(struct hlcache_handle *h,
struct search_callbacks callbacks);
void search_destroy_context(struct search_context *context);
void search_step(struct search_context *context, search_flags_t flags,
const char * string);
void search_show_all(bool all, struct search_context *context);
 
 
bool search_term_highlighted(struct content *c,
unsigned start_offset, unsigned end_offset,
unsigned *start_idx, unsigned *end_idx,
struct search_context *context);
 
#endif
/programs/network/netsurf/netsurf/render/table.c
0,0 → 1,999
/*
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
* Copyright 2005 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Table processing and layout (implementation).
*/
 
#include <assert.h>
 
#include <dom/dom.h>
 
#include "css/css.h"
#include "css/utils.h"
#include "render/box.h"
#include "render/table.h"
#include "utils/log.h"
#include "utils/talloc.h"
 
/* Define to enable verbose table debug */
#undef TABLE_DEBUG
 
/**
* Container for border values during table border calculations
*/
struct border {
enum css_border_style_e style; /**< border-style */
enum css_border_color_e color; /**< border-color type */
css_color c; /**< border-color value */
css_fixed width; /**< border-width length */
css_unit unit; /**< border-width units */
};
 
static void table_used_left_border_for_cell(struct box *cell);
static void table_used_top_border_for_cell(struct box *cell);
static void table_used_right_border_for_cell(struct box *cell);
static void table_used_bottom_border_for_cell(struct box *cell);
static bool table_border_is_more_eyecatching(const struct border *a,
box_type a_src, const struct border *b, box_type b_src);
static void table_cell_top_process_table(struct box *table, struct border *a,
box_type *a_src);
static bool table_cell_top_process_group(struct box *cell, struct box *group,
struct border *a, box_type *a_src);
static bool table_cell_top_process_row(struct box *cell, struct box *row,
struct border *a, box_type *a_src);
 
 
/**
* Determine the column width types for a table.
*
* \param table box of type BOX_TABLE
* \return true on success, false on memory exhaustion
*
* The table->col array is allocated and type and width are filled in for each
* column.
*/
 
bool table_calculate_column_types(struct box *table)
{
unsigned int i, j;
struct column *col;
struct box *row_group, *row, *cell;
 
if (table->col)
/* table->col already constructed, for example frameset table */
return true;
 
table->col = col = talloc_array(table, struct column, table->columns);
if (!col)
return false;
 
for (i = 0; i != table->columns; i++) {
col[i].type = COLUMN_WIDTH_UNKNOWN;
col[i].width = 0;
col[i].positioned = true;
}
 
/* 1st pass: cells with colspan 1 only */
for (row_group = table->children; row_group; row_group =row_group->next)
for (row = row_group->children; row; row = row->next)
for (cell = row->children; cell; cell = cell->next) {
enum css_width_e type;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
assert(cell->type == BOX_TABLE_CELL);
assert(cell->style);
 
if (cell->columns != 1)
continue;
i = cell->start_column;
 
if (css_computed_position(cell->style) !=
CSS_POSITION_ABSOLUTE &&
css_computed_position(cell->style) !=
CSS_POSITION_FIXED) {
col[i].positioned = false;
}
 
type = css_computed_width(cell->style, &value, &unit);
 
/* fixed width takes priority over any other width type */
if (col[i].type != COLUMN_WIDTH_FIXED &&
type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
col[i].type = COLUMN_WIDTH_FIXED;
col[i].width = FIXTOINT(nscss_len2px(value, unit,
cell->style));
if (col[i].width < 0)
col[i].width = 0;
continue;
}
 
if (col[i].type != COLUMN_WIDTH_UNKNOWN)
continue;
 
if (type == CSS_WIDTH_SET && unit == CSS_UNIT_PCT) {
col[i].type = COLUMN_WIDTH_PERCENT;
col[i].width = FIXTOINT(value);
if (col[i].width < 0)
col[i].width = 0;
} else if (type == CSS_WIDTH_AUTO) {
col[i].type = COLUMN_WIDTH_AUTO;
}
}
 
/* 2nd pass: cells which span multiple columns */
for (row_group = table->children; row_group; row_group =row_group->next)
for (row = row_group->children; row; row = row->next)
for (cell = row->children; cell; cell = cell->next) {
unsigned int fixed_columns = 0, percent_columns = 0,
auto_columns = 0, unknown_columns = 0;
int fixed_width = 0, percent_width = 0;
enum css_width_e type;
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
 
if (cell->columns == 1)
continue;
i = cell->start_column;
 
for (j = i; j < i + cell->columns; j++) {
col[j].positioned = false;
}
/* count column types in spanned cells */
for (j = 0; j != cell->columns; j++) {
if (col[i + j].type == COLUMN_WIDTH_FIXED) {
fixed_width += col[i + j].width;
fixed_columns++;
} else if (col[i + j].type == COLUMN_WIDTH_PERCENT) {
percent_width += col[i + j].width;
percent_columns++;
} else if (col[i + j].type == COLUMN_WIDTH_AUTO) {
auto_columns++;
} else {
unknown_columns++;
}
}
 
if (!unknown_columns)
continue;
 
type = css_computed_width(cell->style, &value, &unit);
 
/* if cell is fixed width, and all spanned columns are fixed
* or unknown width, split extra width among unknown columns */
if (type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT &&
fixed_columns + unknown_columns ==
cell->columns) {
int width = (FIXTOFLT(nscss_len2px(value, unit,
cell->style)) - fixed_width) /
unknown_columns;
if (width < 0)
width = 0;
for (j = 0; j != cell->columns; j++) {
if (col[i + j].type == COLUMN_WIDTH_UNKNOWN) {
col[i + j].type = COLUMN_WIDTH_FIXED;
col[i + j].width = width;
}
}
}
 
/* as above for percentage width */
if (type == CSS_WIDTH_SET && unit == CSS_UNIT_PCT &&
percent_columns + unknown_columns ==
cell->columns) {
int width = (FIXTOFLT(value) -
percent_width) / unknown_columns;
if (width < 0)
width = 0;
for (j = 0; j != cell->columns; j++) {
if (col[i + j].type == COLUMN_WIDTH_UNKNOWN) {
col[i + j].type = COLUMN_WIDTH_PERCENT;
col[i + j].width = width;
}
}
}
}
 
/* use AUTO if no width type was specified */
for (i = 0; i != table->columns; i++) {
if (col[i].type == COLUMN_WIDTH_UNKNOWN)
col[i].type = COLUMN_WIDTH_AUTO;
}
 
#ifdef TABLE_DEBUG
for (i = 0; i != table->columns; i++)
LOG(("table %p, column %u: type %s, width %i", table, i,
((const char *[]) {"UNKNOWN", "FIXED", "AUTO",
"PERCENT", "RELATIVE"})[col[i].type],
col[i].width));
#endif
 
return true;
}
 
/**
* Calculate used values of border-{trbl}-{style,color,width} for table cells.
*
* \param cell Table cell to consider
*
* \post \a cell's border array is populated
*/
void table_used_border_for_cell(struct box *cell)
{
int side;
 
assert(cell->type == BOX_TABLE_CELL);
 
if (css_computed_border_collapse(cell->style) ==
CSS_BORDER_COLLAPSE_SEPARATE) {
css_fixed width = 0;
css_unit unit = CSS_UNIT_PX;
 
/* Left border */
cell->border[LEFT].style =
css_computed_border_left_style(cell->style);
css_computed_border_left_color(cell->style,
&cell->border[LEFT].c);
css_computed_border_left_width(cell->style, &width, &unit);
cell->border[LEFT].width =
FIXTOINT(nscss_len2px(width, unit, cell->style));
 
/* Top border */
cell->border[TOP].style =
css_computed_border_top_style(cell->style);
css_computed_border_top_color(cell->style,
&cell->border[TOP].c);
css_computed_border_top_width(cell->style, &width, &unit);
cell->border[TOP].width =
FIXTOINT(nscss_len2px(width, unit, cell->style));
 
/* Right border */
cell->border[RIGHT].style =
css_computed_border_right_style(cell->style);
css_computed_border_right_color(cell->style,
&cell->border[RIGHT].c);
css_computed_border_right_width(cell->style, &width, &unit);
cell->border[RIGHT].width =
FIXTOINT(nscss_len2px(width, unit, cell->style));
 
/* Bottom border */
cell->border[BOTTOM].style =
css_computed_border_bottom_style(cell->style);
css_computed_border_bottom_color(cell->style,
&cell->border[BOTTOM].c);
css_computed_border_bottom_width(cell->style, &width, &unit);
cell->border[BOTTOM].width =
FIXTOINT(nscss_len2px(width, unit, cell->style));
} else {
/* Left border */
table_used_left_border_for_cell(cell);
 
/* Top border */
table_used_top_border_for_cell(cell);
 
/* Right border */
table_used_right_border_for_cell(cell);
 
/* Bottom border */
table_used_bottom_border_for_cell(cell);
}
 
/* Finally, ensure that any borders configured as
* hidden or none have zero width. (c.f. layout_find_dimensions) */
for (side = 0; side != 4; side++) {
if (cell->border[side].style == CSS_BORDER_STYLE_HIDDEN ||
cell->border[side].style ==
CSS_BORDER_STYLE_NONE)
cell->border[side].width = 0;
}
}
 
/******************************************************************************
* Helpers for used border calculations *
******************************************************************************/
 
/**
* Calculate used values of border-left-{style,color,width}
*
* \param cell Table cell to consider
*/
void table_used_left_border_for_cell(struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
 
/** \todo Need column and column_group, too */
 
/* Initialise to computed left border for cell */
a.style = css_computed_border_left_style(cell->style);
a.color = css_computed_border_left_color(cell->style, &a.c);
css_computed_border_left_width(cell->style, &a.width, &a.unit);
a.width = nscss_len2px(a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
 
if (cell->prev != NULL || cell->start_column != 0) {
/* Cell to the left -- consider its right border */
struct box *prev = NULL;
 
if (cell->prev == NULL) {
struct box *row;
 
/* Spanned from a previous row */
for (row = cell->parent; row != NULL; row = row->prev) {
for (prev = row->children; prev != NULL;
prev = prev->next) {
if (prev->start_column +
prev->columns ==
cell->start_column)
break;
}
 
if (prev != NULL)
break;
}
 
assert(prev != NULL);
} else {
prev = cell->prev;
}
 
b.style = css_computed_border_right_style(prev->style);
b.color = css_computed_border_right_color(prev->style, &b.c);
css_computed_border_right_width(prev->style, &b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, prev->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_CELL;
 
if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
} else {
/* First cell in row, so consider rows and row group */
struct box *row = cell->parent;
struct box *group = row->parent;
struct box *table = group->parent;
unsigned int rows = cell->rows;
 
while (rows-- > 0 && row != NULL) {
/* Spanned rows -- consider their left border */
b.style = css_computed_border_left_style(row->style);
b.color = css_computed_border_left_color(
row->style, &b.c);
css_computed_border_left_width(
row->style, &b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
if (table_border_is_more_eyecatching(&a, a_src,
&b, b_src)) {
a = b;
a_src = b_src;
}
 
row = row->next;
}
 
/** \todo can cells span row groups? */
 
/* Row group -- consider its left border */
b.style = css_computed_border_left_style(group->style);
b.color = css_computed_border_left_color(group->style, &b.c);
css_computed_border_left_width(group->style, &b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
 
/* The table itself -- consider its left border */
b.style = css_computed_border_left_style(table->style);
b.color = css_computed_border_left_color(table->style, &b.c);
css_computed_border_left_width(table->style, &b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, table->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE;
if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
}
 
/* a now contains the used left border for the cell */
cell->border[LEFT].style = a.style;
cell->border[LEFT].c = a.c;
cell->border[LEFT].width =
FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
}
 
/**
* Calculate used values of border-top-{style,color,width}
*
* \param cell Table cell to consider
*/
void table_used_top_border_for_cell(struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
struct box *row = cell->parent;
bool process_group = false;
 
/* Initialise to computed top border for cell */
a.style = css_computed_border_top_style(cell->style);
css_computed_border_top_color(cell->style, &a.c);
css_computed_border_top_width(cell->style, &a.width, &a.unit);
a.width = nscss_len2px(a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
 
/* Top border of row */
b.style = css_computed_border_top_style(row->style);
css_computed_border_top_color(row->style, &b.c);
css_computed_border_top_width(row->style, &b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
 
if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
 
if (row->prev != NULL) {
/* Consider row(s) above */
while (table_cell_top_process_row(cell, row->prev,
&a, &a_src) == false) {
if (row->prev->prev == NULL) {
/* Consider row group */
process_group = true;
break;
} else {
row = row->prev;
}
}
} else {
process_group = true;
}
 
if (process_group) {
struct box *group = row->parent;
 
/* Top border of row group */
b.style = css_computed_border_top_style(group->style);
b.color = css_computed_border_top_color(group->style, &b.c);
css_computed_border_top_width(group->style, &b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
 
if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
 
if (group->prev == NULL) {
/* Top border of table */
table_cell_top_process_table(group->parent, &a, &a_src);
} else {
/* Process previous group(s) */
while (table_cell_top_process_group(cell, group->prev,
&a, &a_src) == false) {
if (group->prev->prev == NULL) {
/* Top border of table */
table_cell_top_process_table(
group->parent,
&a, &a_src);
break;
} else {
group = group->prev;
}
}
}
}
 
/* a now contains the used top border for the cell */
cell->border[TOP].style = a.style;
cell->border[TOP].c = a.c;
cell->border[TOP].width =
FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
}
 
/**
* Calculate used values of border-right-{style,color,width}
*
* \param cell Table cell to consider
*/
void table_used_right_border_for_cell(struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
 
/** \todo Need column and column_group, too */
 
/* Initialise to computed right border for cell */
a.style = css_computed_border_right_style(cell->style);
css_computed_border_right_color(cell->style, &a.c);
css_computed_border_right_width(cell->style, &a.width, &a.unit);
a.width = nscss_len2px(a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
 
if (cell->next != NULL || cell->start_column + cell->columns !=
cell->parent->parent->parent->columns) {
/* Cell is not at right edge of table -- no right border */
a.style = CSS_BORDER_STYLE_NONE;
a.width = 0;
a.unit = CSS_UNIT_PX;
} else {
/* Last cell in row, so consider rows and row group */
struct box *row = cell->parent;
struct box *group = row->parent;
struct box *table = group->parent;
unsigned int rows = cell->rows;
 
while (rows-- > 0 && row != NULL) {
/* Spanned rows -- consider their right border */
b.style = css_computed_border_right_style(row->style);
b.color = css_computed_border_right_color(
row->style, &b.c);
css_computed_border_right_width(
row->style, &b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
if (table_border_is_more_eyecatching(&a, a_src,
&b, b_src)) {
a = b;
a_src = b_src;
}
 
row = row->next;
}
 
/** \todo can cells span row groups? */
 
/* Row group -- consider its right border */
b.style = css_computed_border_right_style(group->style);
b.color = css_computed_border_right_color(group->style, &b.c);
css_computed_border_right_width(group->style,
&b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
 
/* The table itself -- consider its right border */
b.style = css_computed_border_right_style(table->style);
b.color = css_computed_border_right_color(table->style, &b.c);
css_computed_border_right_width(table->style,
&b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, table->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE;
if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
}
 
/* a now contains the used right border for the cell */
cell->border[RIGHT].style = a.style;
cell->border[RIGHT].c = a.c;
cell->border[RIGHT].width =
FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
}
 
/**
* Calculate used values of border-bottom-{style,color,width}
*
* \param cell Table cell to consider
*/
void table_used_bottom_border_for_cell(struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
struct box *row = cell->parent;
unsigned int rows = cell->rows;
 
/* Initialise to computed bottom border for cell */
a.style = css_computed_border_bottom_style(cell->style);
css_computed_border_bottom_color(cell->style, &a.c);
css_computed_border_bottom_width(cell->style, &a.width, &a.unit);
a.width = nscss_len2px(a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
 
while (rows-- > 0 && row != NULL)
row = row->next;
 
/** \todo Can cells span row groups? */
 
if (row != NULL) {
/* Cell is not at bottom edge of table -- no bottom border */
a.style = CSS_BORDER_STYLE_NONE;
a.width = 0;
a.unit = CSS_UNIT_PX;
} else {
/* Cell at bottom of table, so consider row and row group */
struct box *row = cell->parent;
struct box *group = row->parent;
struct box *table = group->parent;
 
/* Bottom border of row */
b.style = css_computed_border_bottom_style(row->style);
b.color = css_computed_border_bottom_color(row->style, &b.c);
css_computed_border_bottom_width(row->style, &b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
 
/* Row group -- consider its bottom border */
b.style = css_computed_border_bottom_style(group->style);
b.color = css_computed_border_bottom_color(group->style, &b.c);
css_computed_border_bottom_width(group->style,
&b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
 
/* The table itself -- consider its bottom border */
b.style = css_computed_border_bottom_style(table->style);
b.color = css_computed_border_bottom_color(table->style, &b.c);
css_computed_border_bottom_width(table->style,
&b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, table->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE;
if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
}
 
/* a now contains the used bottom border for the cell */
cell->border[BOTTOM].style = a.style;
cell->border[BOTTOM].c = a.c;
cell->border[BOTTOM].width =
FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
}
 
/**
* Determine if a border style is more eyecatching than another
*
* \param a Reference border style
* \param a_src Source of \a a
* \param b Candidate border style
* \param b_src Source of \a b
* \return True if \a b is more eyecatching than \a a
*/
bool table_border_is_more_eyecatching(const struct border *a,
box_type a_src, const struct border *b, box_type b_src)
{
css_fixed awidth, bwidth;
int impact = 0;
 
/* See CSS 2.1 $17.6.2.1 */
 
/* 1 + 2 -- hidden beats everything, none beats nothing */
if (a->style == CSS_BORDER_STYLE_HIDDEN ||
b->style == CSS_BORDER_STYLE_NONE)
return false;
 
if (b->style == CSS_BORDER_STYLE_HIDDEN ||
a->style == CSS_BORDER_STYLE_NONE)
return true;
 
/* 3a -- wider borders beat narrow ones */
/* The widths must be absolute, which will be the case
* if they've come from a computed style. */
assert(a->unit != CSS_UNIT_EM && a->unit != CSS_UNIT_EX);
assert(b->unit != CSS_UNIT_EM && b->unit != CSS_UNIT_EX);
awidth = nscss_len2px(a->width, a->unit, NULL);
bwidth = nscss_len2px(b->width, b->unit, NULL);
 
if (awidth < bwidth)
return true;
else if (bwidth < awidth)
return false;
 
/* 3b -- sort by style */
switch (a->style) {
case CSS_BORDER_STYLE_DOUBLE: impact++;
case CSS_BORDER_STYLE_SOLID: impact++;
case CSS_BORDER_STYLE_DASHED: impact++;
case CSS_BORDER_STYLE_DOTTED: impact++;
case CSS_BORDER_STYLE_RIDGE: impact++;
case CSS_BORDER_STYLE_OUTSET: impact++;
case CSS_BORDER_STYLE_GROOVE: impact++;
case CSS_BORDER_STYLE_INSET: impact++;
default:
break;
}
 
switch (b->style) {
case CSS_BORDER_STYLE_DOUBLE: impact--;
case CSS_BORDER_STYLE_SOLID: impact--;
case CSS_BORDER_STYLE_DASHED: impact--;
case CSS_BORDER_STYLE_DOTTED: impact--;
case CSS_BORDER_STYLE_RIDGE: impact--;
case CSS_BORDER_STYLE_OUTSET: impact--;
case CSS_BORDER_STYLE_GROOVE: impact--;
case CSS_BORDER_STYLE_INSET: impact--;
default:
break;
}
 
if (impact < 0)
return true;
else if (impact > 0)
return false;
 
/* 4a -- sort by origin */
impact = 0;
 
switch (a_src) {
case BOX_TABLE_CELL: impact++;
case BOX_TABLE_ROW: impact++;
case BOX_TABLE_ROW_GROUP: impact++;
/** \todo COL/COL_GROUP */
case BOX_TABLE: impact++;
default:
break;
}
 
switch (b_src) {
case BOX_TABLE_CELL: impact--;
case BOX_TABLE_ROW: impact--;
case BOX_TABLE_ROW_GROUP: impact--;
/** \todo COL/COL_GROUP */
case BOX_TABLE: impact--;
default:
break;
}
 
if (impact < 0)
return true;
else if (impact > 0)
return false;
 
/* 4b -- furthest left (if direction: ltr) and towards top wins */
/** \todo Currently assumes b satisifies this */
return true;
}
 
/******************************************************************************
* Helpers for top border collapsing *
******************************************************************************/
 
/**
* Process a table
*
* \param table Table to process
* \param a Current border style for cell
* \param a_src Source of \a a
*
* \post \a a will be updated with most eyecatching style
* \post \a a_src will be updated also
*/
void table_cell_top_process_table(struct box *table, struct border *a,
box_type *a_src)
{
struct border b;
box_type b_src;
 
/* Top border of table */
b.style = css_computed_border_top_style(table->style);
b.color = css_computed_border_top_color(table->style, &b.c);
css_computed_border_top_width(table->style, &b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, table->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE;
 
if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
}
 
/**
* Process a group
*
* \param cell Cell being considered
* \param group Group to process
* \param a Current border style for cell
* \param a_src Source of \a a
* \return true if group has non-empty rows, false otherwise
*
* \post \a a will be updated with most eyecatching style
* \post \a a_src will be updated also
*/
bool table_cell_top_process_group(struct box *cell, struct box *group,
struct border *a, box_type *a_src)
{
struct border b;
box_type b_src;
 
/* Bottom border of group */
b.style = css_computed_border_bottom_style(group->style);
b.color = css_computed_border_bottom_color(group->style, &b.c);
css_computed_border_bottom_width(group->style, &b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
 
if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
 
if (group->last != NULL) {
/* Process rows in group, starting with last */
struct box *row = group->last;
 
while (table_cell_top_process_row(cell, row,
a, a_src) == false) {
if (row->prev == NULL) {
return false;
} else {
row = row->prev;
}
}
} else {
/* Group is empty, so consider its top border */
b.style = css_computed_border_top_style(group->style);
b.color = css_computed_border_top_color(group->style, &b.c);
css_computed_border_top_width(group->style, &b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, group->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW_GROUP;
 
if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
 
return false;
}
 
return true;
}
 
/**
* Process a row
*
* \param cell Cell being considered
* \param row Row to process
* \param a Current border style for cell
* \param a_src Source of \a a
* \return true if row has cells, false otherwise
*
* \post \a a will be updated with most eyecatching style
* \post \a a_src will be updated also
*/
bool table_cell_top_process_row(struct box *cell, struct box *row,
struct border *a, box_type *a_src)
{
struct border b;
box_type b_src;
 
/* Bottom border of row */
b.style = css_computed_border_bottom_style(row->style);
b.color = css_computed_border_bottom_color(row->style, &b.c);
css_computed_border_bottom_width(row->style, &b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
 
if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
 
if (row->children == NULL) {
/* Row is empty, so consider its top border */
b.style = css_computed_border_top_style(row->style);
b.color = css_computed_border_top_color(row->style, &b.c);
css_computed_border_top_width(row->style, &b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit, row->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_ROW;
 
if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
 
return false;
} else {
/* Process cells that are directly above the cell being
* considered. They may not be in this row, but in one of the
* rows above it in the case where rowspan > 1. */
struct box *c;
bool processed = false;
 
while (processed == false) {
for (c = row->children; c != NULL; c = c->next) {
/* Ignore cells to the left */
if (c->start_column + c->columns <
cell->start_column)
continue;
/* Ignore cells to the right */
if (c->start_column >= cell->start_column +
cell->columns)
continue;
 
/* Flag that we've processed a cell */
processed = true;
 
/* Consider bottom border */
b.style = css_computed_border_bottom_style(
c->style);
b.color = css_computed_border_bottom_color(
c->style, &b.c);
css_computed_border_bottom_width(c->style,
&b.width, &b.unit);
b.width = nscss_len2px(b.width, b.unit,
c->style);
b.unit = CSS_UNIT_PX;
b_src = BOX_TABLE_CELL;
 
if (table_border_is_more_eyecatching(a, *a_src,
&b, b_src)) {
*a = b;
*a_src = b_src;
}
}
 
if (processed == false) {
/* There must be a preceding row */
assert(row->prev != NULL);
 
row = row->prev;
}
}
}
 
return true;
}
 
/programs/network/netsurf/netsurf/render/table.h
0,0 → 1,34
/*
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
* Copyright 2005 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Table processing and layout (interface).
*/
 
#ifndef _NETSURF_RENDER_TABLE_H_
#define _NETSURF_RENDER_TABLE_H_
 
#include <stdbool.h>
 
struct box;
 
bool table_calculate_column_types(struct box *table);
void table_used_border_for_cell(struct box *cell);
 
#endif
/programs/network/netsurf/netsurf/render/textinput.c
0,0 → 1,2213
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk>
* Copyright 2004 John Tytgat <joty@netsurf-browser.org>
* Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* HTML form text input handling (implementation)
*/
 
#include <assert.h>
#include <ctype.h>
#include <string.h>
 
#include <dom/dom.h>
 
#include "desktop/browser.h"
#include "desktop/gui.h"
#include "desktop/mouse.h"
#include "desktop/scrollbar.h"
#include "desktop/selection.h"
#include "desktop/textinput.h"
#include "render/box.h"
#include "render/font.h"
#include "render/form.h"
#include "render/html_internal.h"
#include "render/layout.h"
#include "render/textinput.h"
#include "utils/log.h"
#include "utils/talloc.h"
#include "utils/utf8.h"
#include "utils/utils.h"
 
/* Define to enable textinput debug */
#undef TEXTINPUT_DEBUG
 
 
static bool textinput_textbox_delete(struct content *c,
struct box *text_box, unsigned char_offset,
unsigned utf8_len);
 
/* Textarea callbacks */
static bool textinput_textarea_callback(struct browser_window *bw,
uint32_t key, void *p1, void *p2);
static void textinput_textarea_move_caret(struct browser_window *bw,
void *p1, void *p2);
static bool textinput_textarea_paste_text(struct browser_window *bw,
const char *utf8, unsigned utf8_len, bool last,
void *p1, void *p2);
 
/* Text input callbacks */
static bool textinput_input_callback(struct browser_window *bw,
uint32_t key, void *p1, void *p2);
static void textinput_input_move_caret(struct browser_window *bw,
void *p1, void *p2);
static bool textinput_input_paste_text(struct browser_window *bw,
const char *utf8, unsigned utf8_len, bool last,
void *p1, void *p2);
 
#define SPACE_LEN(b) ((b->space == 0) ? 0 : 1)
 
 
static struct textinput_buffer {
char *buffer;
size_t buffer_len;
size_t length;
} textinput_buffer;
 
 
 
/**
* Given the x,y co-ordinates of a point within a textarea, return the
* TEXT box pointer, and the character and pixel offsets within that
* box at which the caret should be positioned. (eg. for mouse clicks,
* drag-and-drop insertions etc)
*
* \param textarea the textarea being considered
* \param x x ordinate of point
* \param y y ordinate of point
* \param pchar_offset receives the char offset within the TEXT box
* \param ppixel_offset receives the pixel offset within the TEXT box
* \return pointer to TEXT box
*/
 
static struct box *textinput_textarea_get_position(struct box *textarea,
int x, int y, int *pchar_offset, int *ppixel_offset)
{
/* A textarea is an INLINE_BLOCK containing a single
* INLINE_CONTAINER, which contains the text as runs of TEXT
* separated by BR. There is at least one TEXT. The first and
* last boxes are TEXT. Consecutive BR may not be present. These
* constraints are satisfied by using a 0-length TEXT for blank
* lines. */
 
struct box *inline_container, *text_box;
plot_font_style_t fstyle;
size_t char_offset = 0;
 
inline_container = textarea->children;
 
if (inline_container->y + inline_container->height < y) {
/* below the bottom of the textarea: place caret at end */
text_box = inline_container->last;
assert(text_box->type == BOX_TEXT);
assert(text_box->text);
font_plot_style_from_css(text_box->style, &fstyle);
/** \todo handle errors */
nsfont.font_position_in_string(&fstyle, text_box->text,
text_box->length,
(unsigned int)(x - text_box->x),
&char_offset, ppixel_offset);
} else {
/* find the relevant text box */
y -= inline_container->y;
for (text_box = inline_container->children;
text_box &&
text_box->y + text_box->height < y;
text_box = text_box->next)
;
for (; text_box && text_box->type != BOX_BR &&
text_box->y <= y &&
text_box->x + text_box->width < x;
text_box = text_box->next)
;
if (!text_box) {
/* past last text box */
text_box = inline_container->last;
assert(text_box->type == BOX_TEXT);
assert(text_box->text);
font_plot_style_from_css(text_box->style, &fstyle);
nsfont.font_position_in_string(&fstyle,
text_box->text,
text_box->length,
textarea->width,
&char_offset,
ppixel_offset);
} else {
/* in a text box */
if (text_box->type == BOX_BR)
text_box = text_box->prev;
else if (y < text_box->y && text_box->prev) {
if (text_box->prev->type == BOX_BR) {
assert(text_box->prev->prev);
text_box = text_box->prev->prev;
}
else
text_box = text_box->prev;
}
assert(text_box->type == BOX_TEXT);
assert(text_box->text);
font_plot_style_from_css(text_box->style, &fstyle);
nsfont.font_position_in_string(&fstyle,
text_box->text,
text_box->length,
(unsigned int)(x - text_box->x),
&char_offset,
ppixel_offset);
}
}
 
*pchar_offset = char_offset;
 
assert(text_box);
return text_box;
}
 
 
/**
* Delete some text from a box, or delete the box in its entirety
*
* \param c html content
* \param b box
* \param offset start offset of text to be deleted (in bytes)
* \param length length of text to be deleted
* \return true iff successful
*/
 
static bool textinput_delete_handler(struct content *c, struct box *b,
int offset, size_t length)
{
size_t text_length = b->length + SPACE_LEN(b);
 
/* only remove if its not the first box */
if (offset <= 0 && length >= text_length && b->prev != NULL) {
/* remove the entire box */
box_unlink_and_free(b);
 
return true;
} else
return textinput_textbox_delete(c, b, offset,
min(length, text_length - offset));
}
 
 
/**
* Remove the selected text from a text box and gadget (if applicable)
*
* \param c The content containing the selection
* \param s The selection to be removed
*/
 
static void textinput_delete_selection(struct content *c, struct selection *s)
{
size_t start_offset, end_offset;
struct box *text_box;
struct box *end_box;
struct box *next;
size_t sel_len;
int beginning = 0;
 
assert(s->defined);
 
text_box = selection_get_start(s, &start_offset);
end_box = selection_get_end(s, &end_offset);
sel_len = s->end_idx - s->start_idx;
 
/* Clear selection so that deletion from textboxes proceeds */
selection_clear(s, true);
 
/* handle first box */
textinput_delete_handler(c, text_box, start_offset, sel_len);
if (text_box == end_box)
return;
 
for (text_box = text_box->next; text_box != end_box; text_box = next) {
next = text_box->next;
box_unlink_and_free(text_box);
}
 
textinput_delete_handler(c, end_box, beginning, end_offset);
}
 
 
/**
* Insert a number of chars into a text box
*
* \param c html_content
* \param text_box text box
* \param char_offset offset (bytes) at which to insert text
* \param utf8 UTF-8 text to insert
* \param utf8_len length (bytes) of UTF-8 text to insert
* \return true iff successful
*/
 
static bool textinput_textbox_insert(struct content *c,
struct box *text_box, unsigned char_offset, const char *utf8,
unsigned utf8_len)
{
html_content *html = (html_content *)c;
char *text;
struct box *input = text_box->parent->parent;
bool hide;
 
if (html->bw && html->sel.defined)
textinput_delete_selection(c, &html->sel);
 
/* insert into form gadget (text and password inputs only) */
if (input->gadget && (input->gadget->type == GADGET_TEXTBOX ||
input->gadget->type == GADGET_PASSWORD) &&
input->gadget->value) {
size_t form_offset = input->gadget->caret_form_offset;
char *value = realloc(input->gadget->value,
input->gadget->length + utf8_len + 1);
if (!value) {
warn_user("NoMemory", 0);
return true;
}
input->gadget->value = value;
 
memmove(input->gadget->value + form_offset + utf8_len,
input->gadget->value + form_offset,
input->gadget->length - form_offset);
memcpy(input->gadget->value + form_offset, utf8, utf8_len);
input->gadget->length += utf8_len;
input->gadget->value[input->gadget->length] = 0;
}
 
hide = (input->gadget && input->gadget->type == GADGET_PASSWORD);
if (hide) {
/* determine the number of '*'s to be inserted */
const char *eutf8 = utf8 + utf8_len;
utf8_len = 0;
while (utf8 < eutf8) {
utf8 += utf8_next(utf8, eutf8 - utf8, 0);
utf8_len++;
}
}
 
/* insert in text box */
text = talloc_realloc(html->bctx, text_box->text,
char,
text_box->length + SPACE_LEN(text_box) + utf8_len + 1);
if (!text) {
warn_user("NoMemory", 0);
return false;
}
text_box->text = text;
 
if (text_box->space != 0 &&
char_offset == text_box->length + SPACE_LEN(text_box)) {
if (hide)
text_box->space = 0;
else {
unsigned int last_off = utf8_prev(utf8, utf8_len);
if (utf8[last_off] != ' ')
text_box->space = 0;
else
utf8_len = last_off;
}
text_box->text[text_box->length++] = ' ';
} else {
memmove(text_box->text + char_offset + utf8_len,
text_box->text + char_offset,
text_box->length - char_offset);
}
 
if (hide)
memset(text_box->text + char_offset, '*', utf8_len);
else
memcpy(text_box->text + char_offset, utf8, utf8_len);
text_box->length += utf8_len;
 
/* nothing should assume that the text is terminated,
* but just in case */
text_box->text[text_box->length] = 0;
 
text_box->width = UNKNOWN_WIDTH;
 
return true;
}
 
/**
* Calculates the form_offset from the box_offset
*
* \param input The root box containing both the textbox and gadget
* \param text_box The textbox containing the caret
* \param char_offset The caret offset within text_box
* \return the translated form_offset
*/
 
static size_t textinput_get_form_offset(struct box* input, struct box* text_box,
size_t char_offset)
{
int uchars;
unsigned int offset;
 
for (uchars = 0, offset = 0; offset < char_offset; uchars++) {
if ((text_box->text[offset] & 0x80) == 0x00) {
offset++;
continue;
}
assert((text_box->text[offset] & 0xC0) == 0xC0);
for (++offset; offset < char_offset &&
(text_box->text[offset] & 0xC0) == 0x80;
offset++)
/* do nothing */;
}
/* uchars is the number of real Unicode characters at the left
* side of the caret.
*/
for (offset = 0; uchars > 0 && offset < input->gadget->length;
uchars--) {
if ((input->gadget->value[offset] & 0x80) == 0x00) {
offset++;
continue;
}
assert((input->gadget->value[offset] & 0xC0) == 0xC0);
for (++offset; offset < input->gadget->length &&
(input->gadget->value[offset] & 0xC0) == 0x80;
offset++)
/* do nothing */;
}
assert(uchars == 0);
return offset;
}
 
 
/**
* Delete a number of chars from a text box
*
* \param c html content
* \param text_box text box
* \param char_offset offset within text box (bytes) of first char to delete
* \param utf8_len length (bytes) of chars to be deleted
* \return true on success, false otherwise
*
* ::char_offset and ::utf8_len are only considered when there is no selection.
* If there is a selection, the entire selected area is deleted.
*/
 
bool textinput_textbox_delete(struct content *c, struct box *text_box,
unsigned char_offset, unsigned utf8_len)
{
html_content *html = (html_content *)c;
unsigned next_offset = char_offset + utf8_len;
struct box *form = text_box->parent->parent;
 
if (html->bw && html->sel.defined) {
textinput_delete_selection(c, &html->sel);
return true;
}
 
/* delete from form gadget (text and password inputs only) */
if (form->gadget && (form->gadget->type == GADGET_TEXTBOX ||
form->gadget->type == GADGET_PASSWORD) &&
form->gadget->value) {
size_t form_offset = textinput_get_form_offset(form, text_box,
char_offset);
size_t next_offset = textinput_get_form_offset(form, text_box,
char_offset + utf8_len);
 
memmove(form->gadget->value + form_offset,
form->gadget->value + next_offset,
form->gadget->length - next_offset);
form->gadget->length -= (next_offset - form_offset);
form->gadget->value[form->gadget->length] = 0;
}
 
/* delete from visible textbox */
if (next_offset <= text_box->length + SPACE_LEN(text_box)) {
/* handle removal of trailing space */
if (text_box->space != 0 && next_offset > text_box->length) {
if (char_offset > 0) {
/* is the trailing character still a space? */
int tmp = utf8_prev(text_box->text, char_offset);
if (isspace(text_box->text[tmp]))
char_offset = tmp;
else
text_box->space = 0;
} else {
text_box->space = 0;
}
 
text_box->length = char_offset;
} else {
memmove(text_box->text + char_offset,
text_box->text + next_offset,
text_box->length - next_offset);
text_box->length -= utf8_len;
}
 
/* nothing should assume that the text is terminated,
* but just in case */
text_box->text[text_box->length] = 0;
 
text_box->width = UNKNOWN_WIDTH;
 
return true;
}
 
return false;
}
 
/**
* Locate the first inline box at the start of this line
*
* \param text_box text box from which to start searching
*/
 
static struct box *textinput_line_start(struct box *text_box)
{
while (text_box->prev && text_box->prev->type == BOX_TEXT)
text_box = text_box->prev;
return text_box;
}
 
 
/**
* Locate the last inline box in this line
*
* \param text_box text box from which to start searching
*/
 
static struct box *textinput_line_end(struct box *text_box)
{
while (text_box->next && text_box->next->type == BOX_TEXT)
text_box = text_box->next;
return text_box;
}
 
 
/**
* Backtrack to the start of the previous line, if there is one.
*/
 
static struct box *textinput_line_above(struct box *text_box)
{
struct box *prev;
 
text_box = textinput_line_start(text_box);
 
prev = text_box->prev;
while (prev && prev->type == BOX_BR)
prev = prev->prev;
 
return prev ? textinput_line_start(prev) : text_box;
}
 
 
/**
* Advance to the start of the next line, if there is one.
*/
 
static struct box *textinput_line_below(struct box *text_box)
{
struct box *next;
 
text_box = textinput_line_end(text_box);
 
next = text_box->next;
while (next && next->type == BOX_BR)
next = next->next;
 
return next ? next : text_box;
}
 
 
/**
* Add some text to the buffer, optionally appending a trailing space.
*
* \param text text to be added
* \param length length of text in bytes
* \param space indicates whether a trailing space should be appended
* \param fstyle The font style
* \return true if successful
*/
 
static bool textinput_add_to_buffer(const char *text, size_t length, bool space,
const plot_font_style_t *fstyle)
{
size_t new_length = textinput_buffer.length + length + (space ? 1 : 0) + 1;
 
if (new_length > textinput_buffer.buffer_len) {
size_t new_alloc = new_length + (new_length / 4);
char *new_buff;
 
new_buff = realloc(textinput_buffer.buffer, new_alloc);
if (new_buff == NULL)
return false;
 
textinput_buffer.buffer = new_buff;
textinput_buffer.buffer_len = new_alloc;
}
 
memcpy(textinput_buffer.buffer + textinput_buffer.length, text, length);
textinput_buffer.length += length;
 
if (space)
textinput_buffer.buffer[textinput_buffer.length++] = ' ';
 
textinput_buffer.buffer[textinput_buffer.length] = '\0';
 
return true;
}
 
 
/**
* Empty the buffer, called prior to textinput_add_to_buffer sequence
*
* \return true iff successful
*/
 
static bool textinput_empty_buffer(void)
{
const size_t init_size = 1024;
 
if (textinput_buffer.buffer_len == 0) {
textinput_buffer.buffer = malloc(init_size);
if (textinput_buffer.buffer == NULL)
return false;
 
textinput_buffer.buffer_len = init_size;
}
 
textinput_buffer.length = 0;
 
return true;
}
 
 
/**
* Cut a range of text from a text box,
* possibly placing it on the global clipboard.
*
* \param c html content
* \param start_box text box at start of range
* \param start_idx index (bytes) within start box
* \param end_box text box at end of range
* \param end_idx index (bytes) within end box
* \param clipboard whether to place text on the clipboard
* \return true iff successful
*/
 
static bool textinput_textarea_cut(struct content *c,
struct box *start_box, unsigned start_idx,
struct box *end_box, unsigned end_idx,
bool clipboard)
{
struct box *box = start_box;
bool success = true;
bool del = false; /* caller expects start_box to persist */
 
if (textinput_empty_buffer() == false) {
return false;
}
 
while (box && box != end_box) {
/* read before deletion, in case the whole box goes */
struct box *next = box->next;
 
if (box->type == BOX_BR) {
if (clipboard && !textinput_add_to_buffer("\n", 1,
false, plot_style_font)) {
return false;
}
box_unlink_and_free(box);
} else {
/* append box text to clipboard and then delete it */
if (clipboard &&
!textinput_add_to_buffer(box->text + start_idx,
box->length - start_idx,
SPACE_LEN(box), plot_style_font)) {
return false;
}
 
if (del) {
if (!textinput_delete_handler(c, box,
start_idx,
(box->length + SPACE_LEN(box)) -
start_idx) && clipboard) {
return false;
}
} else {
textinput_textbox_delete(c, box, start_idx,
(box->length + SPACE_LEN(box)) -
start_idx);
}
}
 
del = true;
start_idx = 0;
box = next;
}
 
/* and the last box */
if (box) {
if (clipboard && !textinput_add_to_buffer(box->text + start_idx,
end_idx - start_idx, end_idx > box->length,
plot_style_font)) {
success = false;
} else {
if (del) {
if (!textinput_delete_handler(c, box,
start_idx, end_idx - start_idx))
success = false;
} else {
textinput_textbox_delete(c, box, start_idx,
end_idx - start_idx);
}
}
}
 
if (clipboard) {
gui_set_clipboard(textinput_buffer.buffer,
textinput_buffer.length, NULL, 0);
}
 
return true;
}
 
 
/**
* Break a text box into two
*
* \param c html content
* \param text_box text box to be split
* \param char_offset offset (in bytes) at which text box is to be split
*/
 
static struct box *textinput_textarea_insert_break(struct content *c,
struct box *text_box, size_t char_offset)
{
html_content *html = (html_content *)c;
struct box *new_br, *new_text;
char *text;
 
text = talloc_array(html->bctx, char, text_box->length + 1);
if (!text) {
warn_user("NoMemory", 0);
return NULL;
}
 
new_br = box_create(NULL, text_box->style, false, 0, 0, text_box->title,
0, html->bctx);
new_text = talloc(html->bctx, struct box);
if (!new_text) {
warn_user("NoMemory", 0);
return NULL;
}
 
new_br->type = BOX_BR;
box_insert_sibling(text_box, new_br);
 
memcpy(new_text, text_box, sizeof (struct box));
new_text->flags |= CLONE;
new_text->text = text;
memcpy(new_text->text, text_box->text + char_offset,
text_box->length - char_offset);
new_text->length = text_box->length - char_offset;
text_box->length = char_offset;
text_box->width = new_text->width = UNKNOWN_WIDTH;
box_insert_sibling(new_br, new_text);
 
return new_text;
}
 
 
/**
* Reflow textarea preserving width and height
*
* \param c html content
* \param textarea text area box
* \param inline_container container holding text box
*/
 
static void textinput_textarea_reflow(struct content *c,
struct box *textarea, struct box *inline_container)
{
int width = textarea->width;
int height = textarea->height;
 
assert(c != NULL);
 
if (!layout_inline_container(inline_container, width,
textarea, 0, 0, (struct html_content *) c))
warn_user("NoMemory", 0);
textarea->width = width;
textarea->height = height;
layout_calculate_descendant_bboxes(textarea);
box_handle_scrollbars(c, textarea,
box_hscrollbar_present(textarea),
box_vscrollbar_present(textarea));
}
 
 
/**
* Move to the start of the word containing the given character position,
* or the start of the preceding word if already at the start of this one.
*
* \param text UTF-8 text string
* \param poffset offset of caret within string (updated on exit)
* \param pchars receives the number of characters skipped
* \return true iff the start of a word was found before/at the string start
*/
 
static bool textinput_word_left(const char *text,
size_t *poffset, size_t *pchars)
{
size_t offset = *poffset;
bool success = false;
size_t nchars = 0;
 
/* Skip any spaces immediately prior to the offset */
while (offset > 0) {
offset = utf8_prev(text, offset);
nchars++;
if (!isspace(text[offset])) break;
}
 
/* Now skip all non-space characters */
while (offset > 0) {
size_t prev = utf8_prev(text, offset);
success = true;
if (isspace(text[prev]))
break;
offset = prev;
nchars++;
}
 
*poffset = offset;
if (pchars) *pchars = nchars;
 
return success;
}
 
 
/**
* Move to the start of the first word following the given character position.
*
* \param text UTF-8 text string
* \param len length of string in bytes
* \param poffset offset of caret within string (updated on exit)
* \param pchars receives the number of characters skipped
* \return true iff the start of a word was found before the string end
*/
 
static bool textinput_word_right(const char *text, size_t len,
size_t *poffset, size_t *pchars)
{
size_t offset = *poffset;
bool success = false;
size_t nchars = 0;
 
/* Skip all non-space characters after the offset */
while (offset < len) {
if (isspace(text[offset])) break;
offset = utf8_next(text, len, offset);
nchars++;
}
 
/* Now skip all space characters */
while (offset < len) {
offset = utf8_next(text, len, offset);
nchars++;
if (offset < len && !isspace(text[offset])) {
success = true;
break;
}
}
 
*poffset = offset;
if (pchars) *pchars = nchars;
 
return success;
}
 
/**
* Adjust scroll offsets so that the caret is visible
*
* \param c html content where click ocurred
* \param textarea textarea box
* \return true if a change in scroll offsets has occurred
*/
 
static bool textinput_ensure_caret_visible(struct content *c,
struct box *textarea)
{
html_content *html = (html_content *)c;
int cx, cy;
int scrollx, scrolly;
 
assert(textarea->gadget);
 
scrollx = scrollbar_get_offset(textarea->scroll_x);
scrolly = scrollbar_get_offset(textarea->scroll_y);
 
/* Calculate the caret coordinates */
cx = textarea->gadget->caret_pixel_offset +
textarea->gadget->caret_text_box->x;
cy = textarea->gadget->caret_text_box->y;
 
/* Ensure they are visible */
if (textarea->scroll_x == NULL) {
scrollx = 0;
} else if (cx - scrollbar_get_offset(textarea->scroll_x) < 0) {
scrollx = cx;
} else if (cx > scrollbar_get_offset(textarea->scroll_x) +
textarea->width) {
scrollx = cx - textarea->width;
}
 
if (textarea->scroll_y == NULL) {
scrolly = 0;
} else if (cy - scrollbar_get_offset(textarea->scroll_y) < 0) {
scrolly = cy;
} else if (cy + textarea->gadget->caret_text_box->height >
scrollbar_get_offset(textarea->scroll_y) +
textarea->height) {
scrolly = (cy + textarea->gadget->caret_text_box->height) -
textarea->height;
}
 
if ((scrollx == scrollbar_get_offset(textarea->scroll_x)) &&
(scrolly == scrollbar_get_offset(textarea->scroll_y)))
return false;
 
if (textarea->scroll_x != NULL) {
html->scrollbar = textarea->scroll_x;
scrollbar_set(textarea->scroll_x, scrollx, false);
html->scrollbar = NULL;
}
if (textarea->scroll_y != NULL) {
html->scrollbar = textarea->scroll_x;
scrollbar_set(textarea->scroll_y, scrolly, false);
html->scrollbar = NULL;
}
 
return true;
}
 
 
/**
* Paste a block of text into a textarea at the
* current caret position.
*
* \param bw browser window
* \param utf8 pointer to block of text
* \param utf8_len length (bytes) of text block
* \param last true iff this is the last chunk (update screen too)
* \param p1 pointer to textarea
* \param p2 html content with the text area box
* \return true iff successful
*/
 
bool textinput_textarea_paste_text(struct browser_window *bw,
const char *utf8, unsigned utf8_len, bool last,
void *p1, void *p2)
{
struct box *textarea = p1;
struct content *c = p2;
struct box *inline_container =
textarea->gadget->caret_inline_container;
struct box *text_box = textarea->gadget->caret_text_box;
size_t char_offset = textarea->gadget->caret_box_offset;
int pixel_offset = textarea->gadget->caret_pixel_offset;
const char *ep = utf8 + utf8_len;
const char *p = utf8;
bool success = true;
bool update = last;
 
while (p < ep) {
struct box *new_text;
unsigned utf8_len;
 
while (p < ep) {
if (*p == '\n' || *p == '\r') break;
p++;
}
 
utf8_len = p - utf8;
if (!textinput_textbox_insert(c, text_box, char_offset,
utf8, utf8_len))
return false;
 
char_offset += utf8_len;
if (p == ep)
break;
 
new_text = textinput_textarea_insert_break(c, text_box,
char_offset);
if (!new_text) {
/* we still need to update the screen */
update = true;
success = false;
break;
}
 
/* place caret at start of new text box */
text_box = new_text;
char_offset = 0;
 
/* handle CR/LF and LF/CR terminations */
if ((*p == '\n' && p[1] == '\r') ||
(*p == '\r' && p[1] == '\n'))
p++;
utf8 = ++p;
}
 
// textarea->gadget->caret_inline_container = inline_container;
textarea->gadget->caret_text_box = text_box;
textarea->gadget->caret_box_offset = char_offset;
 
if (update) {
int box_x, box_y;
plot_font_style_t fstyle;
 
/* reflow textarea preserving width and height */
textinput_textarea_reflow(c, textarea, inline_container);
/* reflowing may have broken our caret offset
* this bit should hopefully continue to work if
* textarea_reflow is fixed to update the caret itself */
char_offset = textarea->gadget->caret_box_offset;
text_box = textarea->gadget->caret_text_box;
 
while ((char_offset > text_box->length + SPACE_LEN(text_box)) &&
(text_box->next) &&
(text_box->next->type == BOX_TEXT)) {
#ifdef TEXTINPUT_DEBUG
LOG(("Caret out of range: Was %d in boxlen %d "
"space %d", char_offset,
text_box->length, SPACE_LEN(text_box)));
#endif
char_offset -= text_box->length + SPACE_LEN(text_box);
text_box = text_box->next;
}
 
/* not sure if this will happen or not...
* but won't stick an assert here as we can recover from it */
if (char_offset > text_box->length) {
#ifdef TEXTINPUT_DEBUG
LOG(("Caret moved beyond end of line: "
"Was %d in boxlen %d", char_offset,
text_box->length));
#endif
char_offset = text_box->length;
}
 
textarea->gadget->caret_text_box = text_box;
textarea->gadget->caret_box_offset = char_offset;
 
font_plot_style_from_css(text_box->style, &fstyle);
 
nsfont.font_width(&fstyle, text_box->text,
char_offset, &pixel_offset);
 
textarea->gadget->caret_pixel_offset = pixel_offset;
 
box_coords(textarea, &box_x, &box_y);
box_x += scrollbar_get_offset(textarea->scroll_x);
box_y += scrollbar_get_offset(textarea->scroll_y);
textinput_ensure_caret_visible(c, textarea);
box_x -= scrollbar_get_offset(textarea->scroll_x);
box_y -= scrollbar_get_offset(textarea->scroll_y);
 
browser_window_place_caret(bw,
box_x + inline_container->x + text_box->x +
pixel_offset,
box_y + inline_container->y + text_box->y,
text_box->height,
textinput_textarea_callback,
textinput_textarea_paste_text,
textinput_textarea_move_caret,
textarea, c);
 
html__redraw_a_box((html_content *)c, textarea);
}
 
return success;
}
 
 
/**
* Move caret to new position after reformatting
*
* \param bw browser window
* \param p1 pointer textarea box
* \param p2 html content with the text area box
* \return none
*/
 
void textinput_textarea_move_caret(struct browser_window *bw,
void *p1, void *p2)
{
struct box *textarea = p1;
struct content *c = p2;
struct box *inline_container = textarea->gadget->caret_inline_container;
struct box *text_box = textarea->gadget->caret_text_box;
size_t char_offset = textarea->gadget->caret_box_offset;
int pixel_offset;
int box_x, box_y;
plot_font_style_t fstyle;
 
font_plot_style_from_css(text_box->style, &fstyle);
 
box_coords(textarea, &box_x, &box_y);
box_x -= scrollbar_get_offset(textarea->scroll_x);
box_y -= scrollbar_get_offset(textarea->scroll_y);
 
nsfont.font_width(&fstyle, text_box->text,
char_offset, &pixel_offset);
 
browser_window_place_caret(bw,
box_x + inline_container->x + text_box->x +
pixel_offset,
box_y + inline_container->y + text_box->y,
text_box->height,
textinput_textarea_callback,
textinput_textarea_paste_text,
textinput_textarea_move_caret,
textarea, c);
}
 
 
/**
* Update display to reflect modified input field
*
* \param bw browser window
* \param input input field
* \param form_offset
* \param box_offset offset of caret within text box
* \param to_textarea caret is to be moved to a textarea
* \param redraw force redraw even if field hasn't scrolled
*/
 
static void textinput_input_update_display(struct content *c, struct box *input,
unsigned box_offset, bool to_textarea, bool redraw)
{
struct box *text_box = input->children->children;
unsigned pixel_offset;
int box_x, box_y;
int dx;
plot_font_style_t fstyle;
html_content *html = (html_content *)c;
 
font_plot_style_from_css(text_box->style, &fstyle);
 
if (redraw)
nsfont.font_width(&fstyle, text_box->text, text_box->length,
&text_box->width);
 
box_coords(input, &box_x, &box_y);
 
nsfont.font_width(&fstyle, text_box->text, box_offset,
(int *) &pixel_offset);
 
/* Shift text box horizontally, so caret is visible */
dx = text_box->x;
text_box->x = 0;
if (input->width < text_box->width &&
input->width / 2 < (int) pixel_offset) {
/* Make caret appear in centre of text input */
text_box->x = input->width / 2 - pixel_offset;
/* Clamp if we've shifted too far left */
if (text_box->x < input->width - text_box->width)
text_box->x = input->width - text_box->width;
}
dx -= text_box->x;
input->gadget->caret_pixel_offset = pixel_offset;
 
if (to_textarea) {
/* moving to textarea so need to set these up */
input->gadget->caret_inline_container = input->children;
input->gadget->caret_text_box = text_box;
}
 
input->gadget->caret_box_offset = box_offset;
 
browser_window_place_caret(html->bw,
box_x + input->children->x +
text_box->x + pixel_offset,
box_y + input->children->y + text_box->y,
text_box->height,
/* use the appropriate callback */
to_textarea ? textinput_textarea_callback
: textinput_input_callback,
to_textarea ? textinput_textarea_paste_text
: textinput_input_paste_text,
to_textarea ? textinput_textarea_move_caret
: textinput_input_move_caret,
input, c);
 
if (dx || redraw)
html__redraw_a_box(html, input);
}
 
 
/**
* Key press callback for text areas.
*
* \param bw The browser window containing the text area
* \param key The ucs4 character codepoint
* \param p1 The text area box
* \param p2 The html content with the text area box
* \return true if the keypress is dealt with, false otherwise. It can
* return true even if it ran out of memory; this just means that
* it would have claimed it if it could.
*/
bool textinput_textarea_callback(struct browser_window *bw, uint32_t key,
void *p1, void *p2)
{
struct box *textarea = p1;
struct content *c = p2;
html_content *html = (html_content *)c;
struct box *inline_container =
textarea->gadget->caret_inline_container;
struct box *text_box = textarea->gadget->caret_text_box;
struct box *new_text;
size_t char_offset = textarea->gadget->caret_box_offset;
int pixel_offset = textarea->gadget->caret_pixel_offset;
int box_x, box_y;
char utf8[6];
unsigned int utf8_len;
bool scrolled, reflow = false;
bool selection_exists = html->sel.defined;
plot_font_style_t fstyle;
 
/* box_dump(textarea, 0); */
#ifdef TEXTINPUT_DEBUG
LOG(("key %i at %i in '%.*s'", key, char_offset,
(int) text_box->length, text_box->text));
#endif
 
box_coords(textarea, &box_x, &box_y);
box_x -= scrollbar_get_offset(textarea->scroll_x);
box_y -= scrollbar_get_offset(textarea->scroll_y);
 
if (!(key <= 0x001F || (0x007F <= key && key <= 0x009F))) {
/* normal character insertion */
utf8_len = utf8_from_ucs4(key, utf8);
 
if (!textinput_textbox_insert(c, text_box, char_offset,
utf8, utf8_len))
return true;
 
char_offset += utf8_len;
reflow = true;
 
} else switch (key) {
case KEY_DELETE_LEFT:
if (selection_exists) {
/* Have a selection; delete it */
textinput_textbox_delete(c, text_box, 0, 0);
} else if (char_offset == 0) {
/* at the start of a text box */
struct box *prev;
 
if (text_box->prev && text_box->prev->type == BOX_BR) {
/* previous box is BR: remove it */
box_unlink_and_free(text_box->prev);
}
 
/* This needs to be after the BR removal, as that may
* result in no previous box existing */
if (!text_box->prev)
/* at very beginning of text area: ignore */
return true;
 
/* delete space by merging with previous text box */
prev = text_box->prev;
assert(prev->type == BOX_TEXT);
assert(prev->text);
 
char_offset = prev->length; /* caret at join */
 
if (!textinput_textbox_insert(c, prev, prev->length,
text_box->text, text_box->length))
return true;
 
box_unlink_and_free(text_box);
 
/* place caret at join (see above) */
text_box = prev;
 
} else {
/* delete a character */
size_t prev_offset = char_offset;
size_t new_offset =
utf8_prev(text_box->text, char_offset);
 
if (textinput_textbox_delete(c, text_box, new_offset,
prev_offset - new_offset))
char_offset = new_offset;
}
reflow = true;
break;
 
case KEY_DELETE_LINE_START:
{
struct box *start_box = textinput_line_start(text_box);
 
/* Clear the selection, if one exists */
if (selection_exists)
selection_clear(&html->sel, false);
 
textinput_textarea_cut(c, start_box, 0, text_box,
char_offset, false);
text_box = start_box;
char_offset = 0;
reflow = true;
}
break;
 
case KEY_DELETE_LINE_END:
{
struct box *end_box = textinput_line_end(text_box);
 
/* Clear the selection, if one exists */
if (selection_exists)
selection_clear(&html->sel, false);
 
if (end_box != text_box ||
char_offset < text_box->length + SPACE_LEN(text_box)) {
/* there's something at the end of the line to delete */
textinput_textarea_cut(c, text_box,
char_offset, end_box,
end_box->length + SPACE_LEN(end_box),
false);
reflow = true;
break;
}
}
/* no break */
case KEY_DELETE_RIGHT: /* delete to right */
if (selection_exists) {
/* Delete selection */
textinput_textbox_delete(c, text_box, 0, 0);
} else if (char_offset >= text_box->length) {
/* at the end of a text box */
struct box *next;
 
if (text_box->next && text_box->next->type == BOX_BR) {
/* next box is a BR: remove it */
box_unlink_and_free(text_box->next);
}
 
/* This test is after the BR removal, as that may
* result in no subsequent box being present */
if (!text_box->next)
/* at very end of text area: ignore */
return true;
 
/* delete space by merging with next text box */
 
next = text_box->next;
assert(next->type == BOX_TEXT);
assert(next->text);
 
if (!textinput_textbox_insert(c, text_box,
text_box->length,
next->text, next->length))
return true;
 
box_unlink_and_free(next);
 
/* leave caret at join */
} else {
/* delete a character */
size_t next_offset = utf8_next(text_box->text,
text_box->length, char_offset);
 
textinput_textbox_delete(c, text_box, char_offset,
next_offset - char_offset);
}
reflow = true;
break;
 
case KEY_NL:
case KEY_CR: /* paragraph break */
if (selection_exists) {
/* If we have a selection, then delete it,
* so it's replaced by the break */
textinput_textbox_delete(c, text_box, 0, 0);
}
 
new_text = textinput_textarea_insert_break(c, text_box,
char_offset);
if (!new_text)
return true;
 
/* place caret at start of new text box */
text_box = new_text;
char_offset = 0;
 
reflow = true;
break;
 
case KEY_CUT_LINE:
{
struct box *start_box = textinput_line_start(text_box);
struct box *end_box = textinput_line_end(text_box);
 
/* Clear the selection, if one exists */
if (selection_exists)
selection_clear(&html->sel, false);
 
textinput_textarea_cut(c, start_box, 0, end_box,
end_box->length, false);
 
text_box = start_box;
char_offset = 0;
reflow = true;
}
break;
 
case KEY_PASTE:
{
char *buff = NULL;
size_t buff_len;
bool success;
 
gui_get_clipboard(&buff, &buff_len);
if (buff == NULL)
return false;
 
success = browser_window_paste_text(bw, buff, buff_len, true);
free(buff);
 
return success;
}
 
case KEY_CUT_SELECTION:
{
size_t start_idx, end_idx;
struct box *start_box =
selection_get_start(&html->sel, &start_idx);
struct box *end_box = selection_get_end(&html->sel, &end_idx);
 
if (start_box && end_box) {
selection_clear(&html->sel, false);
textinput_textarea_cut(c, start_box, start_idx,
end_box, end_idx, true);
text_box = start_box;
char_offset = start_idx;
reflow = true;
}
}
break;
 
case KEY_RIGHT:
if (selection_exists) {
/* In selection, move caret to end */
text_box = selection_get_end(&html->sel, &char_offset);
} else if (char_offset < text_box->length) {
/* Within-box movement */
char_offset = utf8_next(text_box->text,
text_box->length, char_offset);
} else {
/* Between-box movement */
if (!text_box->next)
/* at end of text area: ignore */
return true;
 
text_box = text_box->next;
if (text_box->type == BOX_BR)
text_box = text_box->next;
char_offset = 0;
}
break;
 
case KEY_LEFT:
if (selection_exists) {
/* In selection, move caret to start */
text_box = selection_get_start(&html->sel, &char_offset);
} else if (char_offset > 0) {
/* Within-box movement */
char_offset = utf8_prev(text_box->text, char_offset);
} else {
/* Between-box movement */
if (!text_box->prev)
/* at start of text area: ignore */
return true;
 
text_box = text_box->prev;
if (text_box->type == BOX_BR)
text_box = text_box->prev;
char_offset = text_box->length;
}
break;
 
case KEY_UP:
selection_clear(&html->sel, true);
textinput_textarea_click(c, BROWSER_MOUSE_CLICK_1,
textarea,
box_x, box_y,
text_box->x + pixel_offset,
inline_container->y + text_box->y - 1);
return true;
 
case KEY_DOWN:
selection_clear(&html->sel, true);
textinput_textarea_click(c, BROWSER_MOUSE_CLICK_1,
textarea,
box_x, box_y,
text_box->x + pixel_offset,
inline_container->y + text_box->y +
text_box->height + 1);
return true;
 
case KEY_LINE_START:
text_box = textinput_line_start(text_box);
char_offset = 0;
break;
 
case KEY_LINE_END:
text_box = textinput_line_end(text_box);
char_offset = text_box->length;
break;
 
case KEY_TEXT_START:
assert(text_box->parent);
 
/* place caret at start of first box */
text_box = text_box->parent->children;
char_offset = 0;
break;
 
case KEY_TEXT_END:
assert(text_box->parent);
 
/* place caret at end of last box */
text_box = text_box->parent->last;
char_offset = text_box->length;
break;
 
case KEY_WORD_LEFT:
{
bool start_of_word;
/* if there is a selection, caret should stay at beginning */
if (selection_exists)
break;
 
start_of_word = (char_offset <= 0 ||
isspace(text_box->text[char_offset - 1]));
 
while (!textinput_word_left(text_box->text,
&char_offset, NULL)) {
struct box *prev = NULL;
 
assert(char_offset == 0);
 
if (start_of_word) {
/* find the preceding non-BR box */
prev = text_box->prev;
if (prev && prev->type == BOX_BR)
prev = prev->prev;
}
 
if (!prev) {
/* just stay at the start of this box */
break;
}
 
assert(prev->type == BOX_TEXT);
 
text_box = prev;
char_offset = prev->length;
}
}
break;
 
case KEY_WORD_RIGHT:
{
bool in_word;
/* if there is a selection, caret should move to the end */
if (selection_exists) {
text_box = selection_get_end(&html->sel, &char_offset);
break;
}
 
in_word = (char_offset < text_box->length &&
!isspace(text_box->text[char_offset]));
 
while (!textinput_word_right(text_box->text, text_box->length,
&char_offset, NULL)) {
struct box *next = text_box->next;
 
/* find the next non-BR box */
if (next && next->type == BOX_BR)
next = next->next;
 
if (!next) {
/* just stay at the end of this box */
char_offset = text_box->length;
break;
}
 
assert(next->type == BOX_TEXT);
 
text_box = next;
char_offset = 0;
 
if (in_word && text_box->length > 0 &&
!isspace(text_box->text[0])) {
/* just stay at the start of this box */
break;
}
}
}
break;
 
case KEY_PAGE_UP:
{
int nlines = (textarea->height / text_box->height) - 1;
 
while (nlines-- > 0)
text_box = textinput_line_above(text_box);
 
if (char_offset > text_box->length)
char_offset = text_box->length;
}
break;
 
case KEY_PAGE_DOWN:
{
int nlines = (textarea->height / text_box->height) - 1;
 
while (nlines-- > 0)
text_box = textinput_line_below(text_box);
 
/* vague attempt to keep the caret at the same horizontal
* position, given that the code currently cannot support it
* being beyond the end of a line */
if (char_offset > text_box->length)
char_offset = text_box->length;
}
break;
 
default:
return false;
}
 
/*
box_dump(textarea, 0);
for (struct box *t = inline_container->children; t; t = t->next) {
assert(t->type == BOX_TEXT);
assert(t->text);
assert(t->parent == inline_container);
if (t->next) assert(t->next->prev == t);
if (t->prev) assert(t->prev->next == t);
if (!t->next) {
assert(inline_container->last == t);
break;
}
if (t->next->type == BOX_BR) {
assert(t->next->next);
t = t->next;
}
} */
 
if (reflow)
textinput_textarea_reflow(c, textarea, inline_container);
 
if (text_box->length + SPACE_LEN(text_box) <= char_offset) {
if (text_box->next && text_box->next->type == BOX_TEXT) {
/* the text box has been split when reflowing and
the caret is in the second part */
char_offset -= (text_box->length + SPACE_LEN(text_box));
text_box = text_box->next;
assert(text_box);
assert(char_offset <= text_box->length);
/* Scroll back to the left */
if (textarea->scroll_x != NULL) {
box_x += scrollbar_get_offset(
textarea->scroll_x);
scrollbar_set(textarea->scroll_x, 0, false);
}
} else {
assert(!text_box->next ||
(text_box->next &&
text_box->next->type == BOX_BR));
 
char_offset = text_box->length + SPACE_LEN(text_box);
}
}
 
font_plot_style_from_css(text_box->style, &fstyle);
 
nsfont.font_width(&fstyle, text_box->text, char_offset, &pixel_offset);
 
selection_clear(&html->sel, true);
 
textarea->gadget->caret_inline_container = inline_container;
textarea->gadget->caret_text_box = text_box;
textarea->gadget->caret_box_offset = char_offset;
textarea->gadget->caret_pixel_offset = pixel_offset;
 
box_x += scrollbar_get_offset(textarea->scroll_x);
box_y += scrollbar_get_offset(textarea->scroll_y);
scrolled = textinput_ensure_caret_visible(c, textarea);
box_x -= scrollbar_get_offset(textarea->scroll_x);
box_y -= scrollbar_get_offset(textarea->scroll_y);
 
browser_window_place_caret(bw,
box_x + inline_container->x + text_box->x +
pixel_offset,
box_y + inline_container->y + text_box->y,
text_box->height,
textinput_textarea_callback,
textinput_textarea_paste_text,
textinput_textarea_move_caret,
textarea, c);
 
if (scrolled || reflow)
html__redraw_a_box(html, textarea);
 
return true;
}
 
 
/**
* Handle clicks in a text area by placing the caret.
*
* \param c html content where click occurred
* \param mouse state of mouse buttons and modifier keys
* \param textarea textarea box
* \param box_x position of textarea in global document coordinates
* \param box_y position of textarea in global document coordinates
* \param x coordinate of click relative to textarea
* \param y coordinate of click relative to textarea
*/
void textinput_textarea_click(struct content *c, browser_mouse_state mouse,
struct box *textarea, int box_x, int box_y, int x, int y)
{
/* A textarea is an INLINE_BLOCK containing a single
* INLINE_CONTAINER, which contains the text as runs of TEXT
* separated by BR. There is at least one TEXT. The first and
* last boxes are TEXT. Consecutive BR may not be present. These
* constraints are satisfied by using a 0-length TEXT for blank
* lines. */
 
int char_offset = 0, pixel_offset = 0;
struct box *inline_container = textarea->children;
struct box *text_box;
bool scrolled;
html_content *html = (html_content *)c;
 
text_box = textinput_textarea_get_position(textarea, x, y,
&char_offset, &pixel_offset);
 
textarea->gadget->caret_inline_container = inline_container;
textarea->gadget->caret_text_box = text_box;
textarea->gadget->caret_box_offset = char_offset;
textarea->gadget->caret_pixel_offset = pixel_offset;
 
box_x += scrollbar_get_offset(textarea->scroll_x);
box_y += scrollbar_get_offset(textarea->scroll_y);
scrolled = textinput_ensure_caret_visible(c, textarea);
box_x -= scrollbar_get_offset(textarea->scroll_x);
box_y -= scrollbar_get_offset(textarea->scroll_y);
 
browser_window_place_caret(html->bw,
box_x + inline_container->x + text_box->x +
pixel_offset,
box_y + inline_container->y + text_box->y,
text_box->height,
textinput_textarea_callback,
textinput_textarea_paste_text,
textinput_textarea_move_caret,
textarea, c);
 
if (scrolled)
html__redraw_a_box(html, textarea);
}
 
 
/**
* Paste a block of text into an input field at the caret position.
*
* \param bw browser window
* \param utf8 pointer to block of text
* \param utf8_len length (bytes) of text block
* \param last true iff this is the last chunk (update screen too)
* \param p1 pointer to input box
* \param p2 html content with the input box
* \return true iff successful
*/
 
bool textinput_input_paste_text(struct browser_window *bw,
const char *utf8, unsigned utf8_len, bool last,
void *p1, void *p2)
{
struct box *input = p1;
struct content *c = p2;
struct box *text_box = input->children->children;
size_t box_offset = input->gadget->caret_box_offset;
unsigned int nchars = utf8_length(input->gadget->value);
const char *ep = utf8 + utf8_len;
const char *p = utf8;
bool success = true;
bool update = last;
 
/* keep adding chars until we've run out or would exceed
the maximum length of the field (in which we silently
ignore all others)
*/
while (p < ep && nchars < input->gadget->maxlength) {
char buf[80 + 6];
int nbytes = 0;
 
/* how many more chars can we insert in one go? */
while (p < ep && nbytes < 80 &&
nchars < input->gadget->maxlength &&
*p != '\n' && *p != '\r') {
unsigned len = utf8_next(p, ep - p, 0);
if (*p == ' ')
nbytes += utf8_from_ucs4(160, &buf[nbytes]);
else {
memcpy(&buf[nbytes], p, len);
nbytes += len;
}
 
p += len;
nchars++;
}
 
if (!textinput_textbox_insert(c, text_box, box_offset,
buf, nbytes)) {
/* we still need to update the screen */
update = true;
success = false;
break;
}
box_offset += nbytes;
/* Keep caret_form_offset in sync -- textbox_insert uses this
* to determine where to insert into the gadget's value */
input->gadget->caret_form_offset += nbytes;
 
/* handle CR/LF and LF/CR terminations */
if (*p == '\n') {
p++;
if (*p == '\r') p++;
}
else if (*p == '\r') {
p++;
if (*p == '\n') p++;
}
}
 
if (update)
textinput_input_update_display(c, input, box_offset,
false, true);
 
return success;
}
 
 
/**
* Move caret to new position after reformatting
*
* \param bw browser window
* \param p1 pointer to text input box
* \param p2 html content with the input box
* \return none
*/
 
void textinput_input_move_caret(struct browser_window *bw,
void *p1, void *p2)
{
struct box *input = (struct box *)p1;
struct content *c = p2;
struct box *text_box = input->children->children;
unsigned int box_offset = input->gadget->caret_box_offset;
int pixel_offset;
int box_x, box_y;
plot_font_style_t fstyle;
 
font_plot_style_from_css(text_box->style, &fstyle);
 
box_coords(input, &box_x, &box_y);
 
nsfont.font_width(&fstyle, text_box->text, box_offset,
&pixel_offset);
 
browser_window_place_caret(bw,
box_x + input->children->x +
text_box->x + pixel_offset,
box_y + input->children->y + text_box->y,
text_box->height,
textinput_input_callback,
textinput_input_paste_text,
textinput_input_move_caret,
input, c);
}
 
/**
* Key press callback for text or password input boxes.
*
* \param bw The browser window containing the input box
* \param key The UCS4 character codepoint
* \param p1 The input box
* \param p2 The html content with the input box
* \return true if the keypress is dealt with, false otherwise. It can
* return true even if it ran out of memory; this just means that
* it would have claimed it if it could.
*/
bool textinput_input_callback(struct browser_window *bw, uint32_t key,
void *p1, void *p2)
{
struct box *input = (struct box *)p1;
struct content *c = p2;
html_content *html = (html_content *)c;
struct box *text_box = input->children->children;
size_t box_offset = input->gadget->caret_box_offset;
size_t end_offset;
int box_x, box_y;
struct form* form = input->gadget->form;
bool changed = false;
char utf8[6];
unsigned int utf8_len;
bool to_textarea = false;
bool selection_exists = html->sel.defined;
 
input->gadget->caret_form_offset =
textinput_get_form_offset(input, text_box, box_offset);
 
/* update the form offset */
input->gadget->caret_form_offset =
textinput_get_form_offset(input, text_box, box_offset);
 
selection_get_end(&html->sel, &end_offset);
 
box_coords(input, &box_x, &box_y);
 
/* normal character insertion */
if (!(key <= 0x001F || (0x007F <= key && key <= 0x009F))) {
/* have we exceeded max length of input? */
utf8_len = utf8_length(input->gadget->value);
if (utf8_len >= input->gadget->maxlength)
return true;
 
utf8_len = utf8_from_ucs4(key, utf8);
 
if (!textinput_textbox_insert(c, text_box, box_offset,
utf8, utf8_len))
return true;
 
box_offset += utf8_len;
 
changed = true;
 
} else switch (key) {
case KEY_DELETE_LEFT:
{
int prev_offset, new_offset;
 
if (selection_exists) {
textinput_textbox_delete(c, text_box, 0, 0);
} else {
/* Can't delete left from text box start */
if (box_offset == 0)
return true;
 
prev_offset = box_offset;
new_offset = utf8_prev(text_box->text, box_offset);
 
if (textinput_textbox_delete(c, text_box, new_offset,
prev_offset - new_offset))
box_offset = new_offset;
}
 
changed = true;
}
break;
 
case KEY_DELETE_RIGHT:
{
unsigned next_offset;
 
if (selection_exists) {
textinput_textbox_delete(c, text_box, 0, 0);
} else {
/* Can't delete right from text box end */
if (box_offset >= text_box->length)
return true;
 
/* Go to the next valid UTF-8 character */
next_offset = utf8_next(text_box->text,
text_box->length, box_offset);
 
textinput_textbox_delete(c, text_box, box_offset,
next_offset - box_offset);
}
 
changed = true;
}
break;
 
case KEY_TAB:
{
struct form_control *next_input;
/* Find next text entry field that is actually
* displayed (i.e. has an associated box) */
for (next_input = input->gadget->next;
next_input &&
((next_input->type != GADGET_TEXTBOX &&
next_input->type != GADGET_TEXTAREA &&
next_input->type != GADGET_PASSWORD) ||
!next_input->box);
next_input = next_input->next)
;
if (!next_input)
return true;
 
input = next_input->box;
box_offset = 0;
to_textarea = next_input->type == GADGET_TEXTAREA;
}
break;
 
case KEY_NL:
case KEY_CR: /* Return/Enter hit */
selection_clear(&html->sel, true);
 
if (form)
form_submit(content_get_url(c), bw, form, 0);
return true;
 
case KEY_SHIFT_TAB:
{
struct form_control *prev_input;
/* Find previous text entry field that is actually
* displayed (i.e. has an associated box) */
for (prev_input = input->gadget->prev;
prev_input &&
((prev_input->type != GADGET_TEXTBOX &&
prev_input->type != GADGET_TEXTAREA &&
prev_input->type != GADGET_PASSWORD) ||
!prev_input->box);
prev_input = prev_input->prev)
;
if (!prev_input)
return true;
 
input = prev_input->box;
box_offset = 0;
to_textarea = prev_input->type == GADGET_TEXTAREA;
}
break;
 
case KEY_CUT_LINE:
/* Clear the selection, if one exists */
if (selection_exists)
selection_clear(&html->sel, false);
 
textinput_textarea_cut(c, text_box, 0, text_box,
text_box->length, false);
box_offset = 0;
 
changed = true;
break;
 
case KEY_PASTE:
{
char *buff = NULL;
size_t buff_len;
bool success;
 
gui_get_clipboard(&buff, &buff_len);
if (buff == NULL)
return false;
 
success = browser_window_paste_text(bw, buff, buff_len, true);
free(buff);
 
return success;
}
 
case KEY_CUT_SELECTION:
{
size_t start_idx, end_idx;
struct box *start_box =
selection_get_start(&html->sel, &start_idx);
struct box *end_box = selection_get_end(&html->sel, &end_idx);
 
if (start_box && end_box) {
selection_clear(&html->sel, false);
textinput_textarea_cut(c, start_box, start_idx,
end_box, end_idx, true);
 
box_offset = start_idx;
changed = true;
}
}
break;
 
case KEY_RIGHT:
if (selection_exists) {
box_offset = end_offset;
break;
}
 
if (box_offset < text_box->length) {
/* Go to the next valid UTF-8 character */
box_offset = utf8_next(text_box->text,
text_box->length, box_offset);
}
 
break;
 
case KEY_LEFT:
/* If there is a selection, caret should remain at start */
if (selection_exists)
break;
 
/* Go to the previous valid UTF-8 character */
box_offset = utf8_prev(text_box->text, box_offset);
break;
 
case KEY_LINE_START:
box_offset = 0;
break;
 
case KEY_LINE_END:
box_offset = text_box->length;
break;
 
case KEY_WORD_LEFT:
/* If there is a selection, caret should remain at start */
if (selection_exists)
break;
 
if (!textinput_word_left(text_box->text, &box_offset, NULL))
box_offset = 0;
 
break;
 
case KEY_WORD_RIGHT:
if (selection_exists) {
box_offset = end_offset;
break;
}
 
if (!textinput_word_right(text_box->text, text_box->length,
&box_offset, NULL))
box_offset = text_box->length;
 
break;
 
case KEY_DELETE_LINE_START:
if (selection_exists)
selection_clear(&html->sel, true);
 
if (box_offset == 0)
return true;
 
textinput_textarea_cut(c, text_box, 0, text_box,
box_offset, false);
box_offset = 0;
 
changed = true;
break;
 
case KEY_DELETE_LINE_END:
if (selection_exists)
selection_clear(&html->sel, true);
 
if (box_offset >= text_box->length)
return true;
 
textinput_textarea_cut(c, text_box, box_offset,
text_box, text_box->length, false);
 
changed = true;
break;
 
default:
return false;
}
 
selection_clear(&html->sel, true);
textinput_input_update_display(c, input, box_offset,
to_textarea, changed);
 
return true;
}
 
 
/**
* Handle clicks in a text or password input box by placing the caret.
*
* \param bw browser window where click occurred
* \param input input box
* \param box_x position of input in global document coordinates
* \param box_y position of input in global document coordinates
* \param x coordinate of click relative to input
* \param y coordinate of click relative to input
*/
void textinput_input_click(struct content *c, struct box *input,
int box_x, int box_y, int x, int y)
{
size_t char_offset = 0;
int pixel_offset = 0, dx = 0;
struct box *text_box = input->children->children;
plot_font_style_t fstyle;
html_content *html = (html_content *)c;
 
font_plot_style_from_css(text_box->style, &fstyle);
 
nsfont.font_position_in_string(&fstyle, text_box->text,
text_box->length, x - text_box->x,
&char_offset, &pixel_offset);
assert(char_offset <= text_box->length);
 
/* Shift the text box horizontally to ensure that the
* caret position is visible, and ideally centred */
text_box->x = 0;
if ((input->width < text_box->width) &&
(input->width / 2 < pixel_offset)) {
dx = text_box->x;
/* Move left so caret is centred */
text_box->x = input->width / 2 - pixel_offset;
/* Clamp, so text box's right hand edge coincides
* with the input's right hand edge */
if (text_box->x < input->width - text_box->width)
text_box->x = input->width - text_box->width;
dx -= text_box->x;
}
input->gadget->caret_box_offset = char_offset;
input->gadget->caret_form_offset =
textinput_get_form_offset(input, text_box, char_offset);
input->gadget->caret_pixel_offset = pixel_offset;
 
browser_window_place_caret(html->bw,
box_x + input->children->x +
text_box->x + pixel_offset,
box_y + input->children->y + text_box->y,
text_box->height,
textinput_input_callback,
textinput_input_paste_text,
textinput_input_move_caret,
input, c);
 
if (dx)
html__redraw_a_box(html, input);
}
 
 
/programs/network/netsurf/netsurf/render/textinput.h
0,0 → 1,41
/*
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk>
* Copyright 2004 John Tytgat <joty@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* HTML form text input handling (interface)
*/
 
#ifndef _NETSURF_RENDER_TEXTINPUT_H_
#define _NETSURF_RENDER_TEXTINPUT_H_
 
#include <stdbool.h>
 
struct box;
struct content;
 
 
void textinput_textarea_click(struct content *c, browser_mouse_state mouse,
struct box *textarea, int box_x, int box_y, int x, int y);
 
void textinput_input_click(struct content *c, struct box *input,
int box_x, int box_y, int x, int y);
 
#endif
/programs/network/netsurf/netsurf/render/textplain.c
0,0 → 1,1268
/*
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
* Copyright 2006 Adrian Lees <adrianl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for text/plain (implementation).
*/
 
#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include <strings.h>
#include <math.h>
 
#include <parserutils/input/inputstream.h>
 
#include "content/content_protected.h"
#include "content/hlcache.h"
#include "css/css.h"
#include "css/utils.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
#include "desktop/options.h"
#include "desktop/plotters.h"
#include "desktop/search.h"
#include "desktop/selection.h"
#include "render/font.h"
#include "render/search.h"
#include "render/textplain.h"
#include "render/html.h"
#include "utils/http.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
#include "utils/utf8.h"
 
struct textplain_line {
size_t start;
size_t length;
};
 
typedef struct textplain_content {
struct content base;
 
lwc_string *encoding;
void *inputstream;
char *utf8_data;
size_t utf8_data_size;
size_t utf8_data_allocated;
unsigned long physical_line_count;
struct textplain_line *physical_line;
int formatted_width;
struct browser_window *bw;
 
struct selection sel; /** Selection state */
 
/** Context for free text search, or NULL if none */
struct search_context *search;
} textplain_content;
 
 
#define CHUNK 32768 /* Must be a power of 2 */
#define MARGIN 4
 
 
#define TAB_WIDTH 8 /* must be power of 2 currently */
#define TEXT_SIZE 10 * FONT_SIZE_SCALE /* Unscaled text size in pt */
 
static plot_font_style_t textplain_style = {
.family = PLOT_FONT_FAMILY_MONOSPACE,
.size = TEXT_SIZE,
.weight = 400,
.flags = FONTF_NONE,
.background = 0xffffff,
.foreground = 0x000000,
};
 
static int textplain_tab_width = 256; /* try for a sensible default */
 
static void textplain_fini(void);
static nserror textplain_create(const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c);
static nserror textplain_create_internal(textplain_content *c,
lwc_string *charset);
static bool textplain_process_data(struct content *c,
const char *data, unsigned int size);
static bool textplain_convert(struct content *c);
static void textplain_mouse_track(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
static void textplain_mouse_action(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
static void textplain_reformat(struct content *c, int width, int height);
static void textplain_destroy(struct content *c);
static bool textplain_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx);
static void textplain_open(struct content *c, struct browser_window *bw,
struct content *page, struct object_params *params);
void textplain_close(struct content *c);
struct selection *textplain_get_selection(struct content *c);
struct search_context *textplain_get_search(struct content *c);
static nserror textplain_clone(const struct content *old,
struct content **newc);
static content_type textplain_content_type(void);
 
static parserutils_error textplain_charset_hack(const uint8_t *data, size_t len,
uint16_t *mibenum, uint32_t *source);
static bool textplain_drain_input(textplain_content *c,
parserutils_inputstream *stream, parserutils_error terminator);
static bool textplain_copy_utf8_data(textplain_content *c,
const uint8_t *buf, size_t len);
static int textplain_coord_from_offset(const char *text, size_t offset,
size_t length);
static float textplain_line_height(void);
 
static const content_handler textplain_content_handler = {
.fini = textplain_fini,
.create = textplain_create,
.process_data = textplain_process_data,
.data_complete = textplain_convert,
.reformat = textplain_reformat,
.destroy = textplain_destroy,
.mouse_track = textplain_mouse_track,
.mouse_action = textplain_mouse_action,
.redraw = textplain_redraw,
.open = textplain_open,
.close = textplain_close,
.get_selection = textplain_get_selection,
.clone = textplain_clone,
.type = textplain_content_type,
.no_share = true,
};
 
static lwc_string *textplain_charset;
static lwc_string *textplain_default_charset;
 
/**
* Initialise the text content handler
*/
nserror textplain_init(void)
{
lwc_error lerror;
nserror error;
 
lerror = lwc_intern_string("charset", SLEN("charset"),
&textplain_charset);
if (lerror != lwc_error_ok) {
return NSERROR_NOMEM;
}
 
lerror = lwc_intern_string("Windows-1252", SLEN("Windows-1252"),
&textplain_default_charset);
if (lerror != lwc_error_ok) {
lwc_string_unref(textplain_charset);
return NSERROR_NOMEM;
}
 
error = content_factory_register_handler("text/plain",
&textplain_content_handler);
if (error != NSERROR_OK) {
lwc_string_unref(textplain_default_charset);
lwc_string_unref(textplain_charset);
}
 
return error;
}
 
/**
* Clean up after the text content handler
*/
void textplain_fini(void)
{
if (textplain_default_charset != NULL) {
lwc_string_unref(textplain_default_charset);
textplain_default_charset = NULL;
}
 
if (textplain_charset != NULL) {
lwc_string_unref(textplain_charset);
textplain_charset = NULL;
}
}
 
/**
* Create a CONTENT_TEXTPLAIN.
*/
 
nserror textplain_create(const content_handler *handler,
lwc_string *imime_type, const http_parameter *params,
llcache_handle *llcache, const char *fallback_charset,
bool quirks, struct content **c)
{
textplain_content *text;
nserror error;
lwc_string *encoding;
 
text = calloc(1, sizeof(textplain_content));
if (text == NULL)
return NSERROR_NOMEM;
 
error = content__init(&text->base, handler, imime_type, params,
llcache, fallback_charset, quirks);
if (error != NSERROR_OK) {
free(text);
return error;
}
 
error = http_parameter_list_find_item(params, textplain_charset,
&encoding);
if (error != NSERROR_OK) {
encoding = lwc_string_ref(textplain_default_charset);
}
 
error = textplain_create_internal(text, encoding);
if (error != NSERROR_OK) {
lwc_string_unref(encoding);
free(text);
return error;
}
 
lwc_string_unref(encoding);
 
*c = (struct content *) text;
 
return NSERROR_OK;
}
 
/*
* Hack around bug in libparserutils: if the client provides an
* encoding up front, but does not provide a charset detection
* callback, then libparserutils will replace the provided encoding
* with UTF-8. This breaks our input handling.
*
* We avoid this by providing a callback that does precisely nothing,
* thus preserving whatever charset information we decided on in
* textplain_create.
*/
parserutils_error textplain_charset_hack(const uint8_t *data, size_t len,
uint16_t *mibenum, uint32_t *source)
{
return PARSERUTILS_OK;
}
 
nserror textplain_create_internal(textplain_content *c, lwc_string *encoding)
{
char *utf8_data;
parserutils_inputstream *stream;
parserutils_error error;
union content_msg_data msg_data;
 
textplain_style.size = (nsoption_int(font_size) * FONT_SIZE_SCALE) / 10;
 
utf8_data = malloc(CHUNK);
if (utf8_data == NULL)
goto no_memory;
 
error = parserutils_inputstream_create(lwc_string_data(encoding), 0,
textplain_charset_hack, ns_realloc, NULL, &stream);
if (error == PARSERUTILS_BADENCODING) {
/* Fall back to Windows-1252 */
error = parserutils_inputstream_create("Windows-1252", 0,
textplain_charset_hack, ns_realloc, NULL,
&stream);
}
if (error != PARSERUTILS_OK) {
free(utf8_data);
goto no_memory;
}
c->encoding = lwc_string_ref(encoding);
c->inputstream = stream;
c->utf8_data = utf8_data;
c->utf8_data_size = 0;
c->utf8_data_allocated = CHUNK;
c->physical_line = 0;
c->physical_line_count = 0;
c->formatted_width = 0;
c->bw = NULL;
 
selection_prepare(&c->sel, (struct content *)c, false);
 
return NSERROR_OK;
 
no_memory:
msg_data.error = messages_get("NoMemory");
content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
return NSERROR_NOMEM;
}
 
bool textplain_drain_input(textplain_content *c,
parserutils_inputstream *stream,
parserutils_error terminator)
{
static const uint8_t *u_fffd = (const uint8_t *) "\xef\xbf\xfd";
const uint8_t *ch;
size_t chlen, offset = 0;
 
while (parserutils_inputstream_peek(stream, offset, &ch, &chlen) !=
terminator) {
/* Replace all instances of NUL with U+FFFD */
if (chlen == 1 && *ch == 0) {
if (offset > 0) {
/* Obtain pointer to start of input data */
parserutils_inputstream_peek(stream, 0,
&ch, &chlen);
/* Copy from it up to the start of the NUL */
if (textplain_copy_utf8_data(c, ch,
offset) == false)
return false;
}
 
/* Emit U+FFFD */
if (textplain_copy_utf8_data(c, u_fffd, 3) == false)
return false;
 
/* Advance inputstream past the NUL we just read */
parserutils_inputstream_advance(stream, offset + 1);
/* Reset the read offset */
offset = 0;
} else {
/* Accumulate input */
offset += chlen;
 
if (offset > CHUNK) {
/* Obtain pointer to start of input data */
parserutils_inputstream_peek(stream, 0,
&ch, &chlen);
 
/* Emit the data we've read */
if (textplain_copy_utf8_data(c, ch,
offset) == false)
return false;
 
/* Advance the inputstream */
parserutils_inputstream_advance(stream, offset);
/* Reset the read offset */
offset = 0;
}
}
}
 
if (offset > 0) {
/* Obtain pointer to start of input data */
parserutils_inputstream_peek(stream, 0, &ch, &chlen);
/* Emit any data remaining */
if (textplain_copy_utf8_data(c, ch, offset) == false)
return false;
 
/* Advance the inputstream past the data we've read */
parserutils_inputstream_advance(stream, offset);
}
 
return true;
}
 
bool textplain_copy_utf8_data(textplain_content *c,
const uint8_t *buf, size_t len)
{
if (c->utf8_data_size + len >= c->utf8_data_allocated) {
/* Compute next multiple of chunk above the required space */
size_t allocated;
char *utf8_data;
 
allocated = (c->utf8_data_size + len + CHUNK - 1) & ~(CHUNK - 1);
utf8_data = realloc(c->utf8_data, allocated);
if (utf8_data == NULL)
return false;
 
c->utf8_data = utf8_data;
c->utf8_data_allocated = allocated;
}
 
memcpy(c->utf8_data + c->utf8_data_size, buf, len);
c->utf8_data_size += len;
 
return true;
}
 
 
/**
* Process data for CONTENT_TEXTPLAIN.
*/
 
bool textplain_process_data(struct content *c,
const char *data, unsigned int size)
{
textplain_content *text = (textplain_content *) c;
parserutils_inputstream *stream = text->inputstream;
union content_msg_data msg_data;
parserutils_error error;
 
error = parserutils_inputstream_append(stream,
(const uint8_t *) data, size);
if (error != PARSERUTILS_OK) {
goto no_memory;
}
 
if (textplain_drain_input(text, stream, PARSERUTILS_NEEDDATA) == false)
goto no_memory;
 
return true;
 
no_memory:
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
return false;
}
 
 
/**
* Convert a CONTENT_TEXTPLAIN for display.
*/
 
bool textplain_convert(struct content *c)
{
textplain_content *text = (textplain_content *) c;
parserutils_inputstream *stream = text->inputstream;
parserutils_error error;
 
error = parserutils_inputstream_append(stream, NULL, 0);
if (error != PARSERUTILS_OK) {
return false;
}
 
if (textplain_drain_input(text, stream, PARSERUTILS_EOF) == false)
return false;
 
parserutils_inputstream_destroy(stream);
text->inputstream = NULL;
 
content_set_ready(c);
content_set_done(c);
content_set_status(c, messages_get("Done"));
 
return true;
}
 
 
/**
* Reformat a CONTENT_TEXTPLAIN to a new width.
*/
 
void textplain_reformat(struct content *c, int width, int height)
{
textplain_content *text = (textplain_content *) c;
char *utf8_data = text->utf8_data;
size_t utf8_data_size = text->utf8_data_size;
unsigned long line_count = 0;
struct textplain_line *line = text->physical_line;
struct textplain_line *line1;
size_t i, space, col;
size_t columns = 80;
int character_width;
size_t line_start;
 
/* compute available columns (assuming monospaced font) - use 8
* characters for better accuracy */
if (!nsfont.font_width(&textplain_style, "ABCDEFGH", 8, &character_width))
return;
columns = (width - MARGIN - MARGIN) * 8 / character_width;
textplain_tab_width = (TAB_WIDTH * character_width) / 8;
 
text->formatted_width = width;
 
text->physical_line_count = 0;
 
if (!line) {
text->physical_line = line =
malloc(sizeof(struct textplain_line) * (1024 + 3));
if (!line)
goto no_memory;
}
 
line[line_count++].start = line_start = 0;
space = 0;
for (i = 0, col = 0; i != utf8_data_size; i++) {
bool term = (utf8_data[i] == '\n' || utf8_data[i] == '\r');
size_t next_col = col + 1;
 
if (utf8_data[i] == '\t')
next_col = (next_col + TAB_WIDTH - 1) & ~(TAB_WIDTH - 1);
 
if (term || next_col >= columns) {
if (line_count % 1024 == 0) {
line1 = realloc(line,
sizeof(struct textplain_line) *
(line_count + 1024 + 3));
if (!line1)
goto no_memory;
text->physical_line = line = line1;
}
if (term) {
line[line_count-1].length = i - line_start;
 
/* skip second char of CR/LF or LF/CR pair */
if (i + 1 < utf8_data_size &&
utf8_data[i+1] != utf8_data[i] &&
(utf8_data[i+1] == '\n' || utf8_data[i+1] == '\r'))
i++;
}
else {
if (space) {
/* break at last space in line */
i = space;
line[line_count-1].length = (i + 1) - line_start;
 
} else
line[line_count-1].length = i - line_start;
}
line[line_count++].start = line_start = i + 1;
col = 0;
space = 0;
} else {
col++;
if (utf8_data[i] == ' ')
space = i;
}
}
line[line_count-1].length = i - line[line_count-1].start;
line[line_count].start = utf8_data_size;
 
text->physical_line_count = line_count;
c->width = width;
c->height = line_count * textplain_line_height() + MARGIN + MARGIN;
 
return;
 
no_memory:
LOG(("out of memory (line_count %lu)", line_count));
return;
}
 
 
/**
* Destroy a CONTENT_TEXTPLAIN and free all resources it owns.
*/
 
void textplain_destroy(struct content *c)
{
textplain_content *text = (textplain_content *) c;
 
lwc_string_unref(text->encoding);
 
if (text->inputstream != NULL) {
parserutils_inputstream_destroy(text->inputstream);
}
 
if (text->physical_line != NULL) {
free(text->physical_line);
}
 
if (text->utf8_data != NULL) {
free(text->utf8_data);
}
}
 
 
nserror textplain_clone(const struct content *old, struct content **newc)
{
const textplain_content *old_text = (textplain_content *) old;
textplain_content *text;
nserror error;
const char *data;
unsigned long size;
 
text = calloc(1, sizeof(textplain_content));
if (text == NULL)
return NSERROR_NOMEM;
 
error = content__clone(old, &text->base);
if (error != NSERROR_OK) {
content_destroy(&text->base);
return error;
}
 
/* Simply replay create/process/convert */
error = textplain_create_internal(text, old_text->encoding);
if (error != NSERROR_OK) {
content_destroy(&text->base);
return error;
}
 
data = content__get_source_data(&text->base, &size);
if (size > 0) {
if (textplain_process_data(&text->base, data, size) == false) {
content_destroy(&text->base);
return NSERROR_NOMEM;
}
}
 
if (old->status == CONTENT_STATUS_READY ||
old->status == CONTENT_STATUS_DONE) {
if (textplain_convert(&text->base) == false) {
content_destroy(&text->base);
return NSERROR_CLONE_FAILED;
}
}
 
return NSERROR_OK;
}
 
content_type textplain_content_type(void)
{
return CONTENT_TEXTPLAIN;
}
 
/**
* Handle mouse tracking (including drags) in a TEXTPLAIN content window.
*
* \param c content of type textplain
* \param bw browser window
* \param mouse state of mouse buttons and modifier keys
* \param x coordinate of mouse
* \param y coordinate of mouse
*/
 
void textplain_mouse_track(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
textplain_content *text = (textplain_content *) c;
 
if (browser_window_get_drag_type(bw) == DRAGGING_SELECTION && !mouse) {
int dir = -1;
size_t idx;
 
if (selection_dragging_start(&text->sel))
dir = 1;
 
idx = textplain_offset_from_coords(c, x, y, dir);
selection_track(&text->sel, mouse, idx);
 
browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);
}
 
switch (browser_window_get_drag_type(bw)) {
 
case DRAGGING_SELECTION: {
int dir = -1;
size_t idx;
 
if (selection_dragging_start(&text->sel)) dir = 1;
 
idx = textplain_offset_from_coords(c, x, y, dir);
selection_track(&text->sel, mouse, idx);
}
break;
 
default:
textplain_mouse_action(c, bw, mouse, x, y);
break;
}
}
 
 
/**
* Handle mouse clicks and movements in a TEXTPLAIN content window.
*
* \param c content of type textplain
* \param bw browser window
* \param click type of mouse click
* \param x coordinate of mouse
* \param y coordinate of mouse
*/
 
void textplain_mouse_action(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
textplain_content *text = (textplain_content *) c;
browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT;
union content_msg_data msg_data;
const char *status = 0;
size_t idx;
int dir = 0;
 
browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);
 
idx = textplain_offset_from_coords(c, x, y, dir);
if (selection_click(&text->sel, mouse, idx)) {
 
if (selection_dragging(&text->sel)) {
browser_window_set_drag_type(bw,
DRAGGING_SELECTION, NULL);
status = messages_get("Selecting");
}
 
} else {
if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) {
browser_window_page_drag_start(bw, x, y);
pointer = BROWSER_POINTER_MOVE;
}
}
 
msg_data.explicit_status_text = status;
content_broadcast(c, CONTENT_MSG_STATUS, msg_data);
 
msg_data.pointer = pointer;
content_broadcast(c, CONTENT_MSG_POINTER, msg_data);
}
 
 
/**
* Draw a CONTENT_TEXTPLAIN using the current set of plotters (plot).
*
* \param c content of type CONTENT_TEXTPLAIN
* \param data redraw data for this content redraw
* \param clip current clip region
* \param ctx current redraw context
* \return true if successful, false otherwise
*
* x, y, clip_[xy][01] are in target coordinates.
*/
 
bool textplain_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
textplain_content *text = (textplain_content *) c;
struct browser_window *bw = text->bw;
const struct plotter_table *plot = ctx->plot;
char *utf8_data = text->utf8_data;
long lineno;
int x = data->x;
int y = data->y;
unsigned long line_count = text->physical_line_count;
float line_height = textplain_line_height();
float scaled_line_height = line_height * data->scale;
long line0 = (clip->y0 - y * data->scale) / scaled_line_height - 1;
long line1 = (clip->y1 - y * data->scale) / scaled_line_height + 1;
struct textplain_line *line = text->physical_line;
size_t length;
plot_style_t *plot_style_highlight;
 
if (line0 < 0)
line0 = 0;
if (line1 < 0)
line1 = 0;
if (line_count < (unsigned long) line0)
line0 = line_count;
if (line_count < (unsigned long) line1)
line1 = line_count;
if (line1 < line0)
line1 = line0;
 
if (!plot->rectangle(clip->x0, clip->y0, clip->x1, clip->y1,
plot_style_fill_white))
return false;
 
if (!line)
return true;
 
/* choose a suitable background colour for any highlighted text */
if ((data->background_colour & 0x808080) == 0x808080)
plot_style_highlight = plot_style_fill_black;
else
plot_style_highlight = plot_style_fill_white;
 
/* Set up font plot style */
textplain_style.background = data->background_colour;
 
x = (x + MARGIN) * data->scale;
y = (y + MARGIN) * data->scale;
for (lineno = line0; lineno != line1; lineno++) {
const char *text_d = utf8_data + line[lineno].start;
int tab_width = textplain_tab_width * data->scale;
size_t offset = 0;
int tx = x;
 
if (!tab_width) tab_width = 1;
 
length = line[lineno].length;
if (!length)
continue;
 
while (offset < length) {
size_t next_offset = offset;
int width;
int ntx;
 
while (next_offset < length && text_d[next_offset] != '\t')
next_offset = utf8_next(text_d, length, next_offset);
 
if (!text_redraw(text_d + offset, next_offset - offset,
line[lineno].start + offset, 0,
&textplain_style,
tx, y + (lineno * scaled_line_height),
clip, line_height, data->scale, false,
(struct content *)text, &text->sel,
text->search, ctx))
return false;
 
if (next_offset >= length)
break;
 
/* locate end of string and align to next tab position */
if (nsfont.font_width(&textplain_style, &text_d[offset],
next_offset - offset, &width))
tx += (int)(width * data->scale);
 
ntx = x + ((1 + (tx - x) / tab_width) * tab_width);
 
/* if the tab character lies within the selection, if any,
then we must draw it as a filled rectangle so that it's
consistent with background of the selected text */
 
if (bw) {
unsigned tab_ofst = line[lineno].start + next_offset;
struct selection *sel = &text->sel;
bool highlighted = false;
 
if (selection_defined(sel)) {
unsigned start_idx, end_idx;
if (selection_highlighted(sel,
tab_ofst, tab_ofst + 1,
&start_idx, &end_idx))
highlighted = true;
}
 
if (!highlighted && (text->search != NULL)) {
unsigned start_idx, end_idx;
if (search_term_highlighted(c,
tab_ofst, tab_ofst + 1,
&start_idx, &end_idx,
text->search))
highlighted = true;
}
 
if (highlighted) {
int sy = y + (lineno * scaled_line_height);
if (!plot->rectangle(tx, sy,
ntx, sy + scaled_line_height,
plot_style_highlight))
return false;
}
}
 
offset = next_offset + 1;
tx = ntx;
}
}
 
return true;
}
 
 
/**
* Handle a window containing a CONTENT_TEXTPLAIN being opened.
*/
 
void textplain_open(struct content *c, struct browser_window *bw,
struct content *page, struct object_params *params)
{
textplain_content *text = (textplain_content *) c;
 
text->bw = bw;
 
/* text selection */
selection_init(&text->sel, NULL);
}
 
 
/**
* Handle a window containing a CONTENT_TEXTPLAIN being closed.
*/
 
void textplain_close(struct content *c)
{
textplain_content *text = (textplain_content *) c;
 
if (text->search != NULL)
search_destroy_context(text->search);
 
text->bw = NULL;
}
 
 
/**
* Return an textplain content's selection context
*/
 
struct selection *textplain_get_selection(struct content *c)
{
textplain_content *text = (textplain_content *) c;
 
return &text->sel;
}
 
 
/**
* Set an TEXTPLAIN content's search context
*
* \param c content of type text
* \param s search context, or NULL if none
*/
 
void textplain_set_search(struct content *c, struct search_context *s)
{
textplain_content *text = (textplain_content *) c;
 
text->search = s;
}
 
 
/**
* Return an TEXTPLAIN content's search context
*
* \param c content of type text
* \return content's search context, or NULL if none
*/
 
struct search_context *textplain_get_search(struct content *c)
{
textplain_content *text = (textplain_content *) c;
 
return text->search;
}
 
/**
* Retrieve number of lines in content
*
* \param h Content to retrieve line count from
* \return Number of lines
*/
unsigned long textplain_line_count(struct content *c)
{
textplain_content *text = (textplain_content *) c;
 
assert(c != NULL);
 
return text->physical_line_count;
}
 
/**
* Retrieve the size (in bytes) of text data
*
* \param h Content to retrieve size of
* \return Size, in bytes, of data
*/
size_t textplain_size(struct content *c)
{
textplain_content *text = (textplain_content *) c;
 
assert(c != NULL);
 
return text->utf8_data_size;
}
 
/**
* Return byte offset within UTF8 textplain content, given the co-ordinates
* of a point within a textplain content. 'dir' specifies the direction in
* which to search (-1 = above-left, +1 = below-right) if the co-ordinates are not
* contained within a line.
*
* \param h content of type CONTENT_TEXTPLAIN
* \param x x ordinate of point
* \param y y ordinate of point
* \param dir direction of search if not within line
* \return byte offset of character containing (or nearest to) point
*/
 
size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir)
{
textplain_content *textc = (textplain_content *) c;
float line_height = textplain_line_height();
struct textplain_line *line;
const char *text;
unsigned nlines;
size_t length;
int idx;
 
assert(c != NULL);
 
y = (int)((float)(y - MARGIN) / line_height);
x -= MARGIN;
 
nlines = textc->physical_line_count;
if (!nlines)
return 0;
 
if (y <= 0) y = 0;
else if ((unsigned)y >= nlines)
y = nlines - 1;
 
line = &textc->physical_line[y];
text = textc->utf8_data + line->start;
length = line->length;
idx = 0;
 
while (x > 0) {
size_t next_offset = 0;
int width = INT_MAX;
 
while (next_offset < length && text[next_offset] != '\t')
next_offset = utf8_next(text, length, next_offset);
 
if (next_offset < length)
nsfont.font_width(&textplain_style, text, next_offset, &width);
 
if (x <= width) {
int pixel_offset;
size_t char_offset;
 
nsfont.font_position_in_string(&textplain_style,
text, next_offset, x,
&char_offset, &pixel_offset);
 
idx += char_offset;
break;
}
 
x -= width;
length -= next_offset;
text += next_offset;
idx += next_offset;
 
/* check if it's within the tab */
width = textplain_tab_width - (width % textplain_tab_width);
if (x <= width) break;
 
x -= width;
length--;
text++;
idx++;
}
 
return line->start + idx;
}
 
 
/**
* Given a byte offset within the text, return the line number
* of the line containing that offset (or -1 if offset invalid)
*
* \param c content of type CONTENT_TEXTPLAIN
* \param offset byte offset within textual representation
* \return line number, or -1 if offset invalid (larger than size)
*/
 
int textplain_find_line(struct content *c, unsigned offset)
{
textplain_content *text = (textplain_content *) c;
struct textplain_line *line;
int nlines;
int lineno = 0;
 
assert(c != NULL);
 
line = text->physical_line;
nlines = text->physical_line_count;
 
if (offset > text->utf8_data_size)
return -1;
 
/* \todo - implement binary search here */
while (lineno < nlines && line[lineno].start < offset)
lineno++;
if (line[lineno].start > offset)
lineno--;
 
return lineno;
}
 
 
/**
* Convert a character offset within a line of text into the
* horizontal co-ordinate, taking into account the font being
* used and any tabs in the text
*
* \param text line of text
* \param offset char offset within text
* \param length line length
* \return x ordinate
*/
 
int textplain_coord_from_offset(const char *text, size_t offset, size_t length)
{
int x = 0;
 
while (offset > 0) {
size_t next_offset = 0;
int tx;
 
while (next_offset < offset && text[next_offset] != '\t')
next_offset = utf8_next(text, length, next_offset);
 
nsfont.font_width(&textplain_style, text, next_offset, &tx);
x += tx;
 
if (next_offset >= offset)
break;
 
/* align to next tab boundary */
next_offset++;
x = (1 + (x / textplain_tab_width)) * textplain_tab_width;
offset -= next_offset;
text += next_offset;
length -= next_offset;
}
 
return x;
}
 
 
/**
* Given a range of byte offsets within a UTF8 textplain content,
* return a box that fully encloses the text
*
* \param h content of type CONTENT_TEXTPLAIN
* \param start byte offset of start of text range
* \param end byte offset of end
* \param r rectangle to be completed
*/
 
void textplain_coords_from_range(struct content *c, unsigned start,
unsigned end, struct rect *r)
{
textplain_content *text = (textplain_content *) c;
float line_height = textplain_line_height();
char *utf8_data;
struct textplain_line *line;
unsigned lineno = 0;
unsigned nlines;
 
assert(c != NULL);
assert(start <= end);
assert(end <= text->utf8_data_size);
 
utf8_data = text->utf8_data;
nlines = text->physical_line_count;
line = text->physical_line;
 
/* find start */
lineno = textplain_find_line(c, start);
 
r->y0 = (int)(MARGIN + lineno * line_height);
 
if (lineno + 1 <= nlines || line[lineno + 1].start >= end) {
/* \todo - it may actually be more efficient just to run
forwards most of the time */
 
/* find end */
lineno = textplain_find_line(c, end);
 
r->x0 = 0;
r->x1 = text->formatted_width;
}
else {
/* single line */
const char *text = utf8_data + line[lineno].start;
 
r->x0 = textplain_coord_from_offset(text, start - line[lineno].start,
line[lineno].length);
 
r->x1 = textplain_coord_from_offset(text, end - line[lineno].start,
line[lineno].length);
}
 
r->y1 = (int)(MARGIN + (lineno + 1) * line_height);
}
 
 
/**
* Return a pointer to the requested line of text.
*
* \param h content of type CONTENT_TEXTPLAIN
* \param lineno line number
* \param poffset receives byte offset of line start within text
* \param plen receives length of returned line
* \return pointer to text, or NULL if invalid line number
*/
 
char *textplain_get_line(struct content *c, unsigned lineno,
size_t *poffset, size_t *plen)
{
textplain_content *text = (textplain_content *) c;
struct textplain_line *line;
 
assert(c != NULL);
 
if (lineno >= text->physical_line_count)
return NULL;
line = &text->physical_line[lineno];
 
*poffset = line->start;
*plen = line->length;
return text->utf8_data + line->start;
}
 
 
/**
* Return a pointer to the raw UTF-8 data, as opposed to the reformatted
* text to fit the window width. Thus only hard newlines are preserved
* in the saved/copied text of a selection.
*
* \param h content of type CONTENT_TEXTPLAIN
* \param start starting byte offset within UTF-8 text
* \param end ending byte offset
* \param plen receives validated length
* \return pointer to text, or NULL if no text
*/
 
char *textplain_get_raw_data(struct content *c, unsigned start, unsigned end,
size_t *plen)
{
textplain_content *text = (textplain_content *) c;
size_t utf8_size;
 
assert(c != NULL);
 
utf8_size = text->utf8_data_size;
 
/* any text at all? */
if (!utf8_size) return NULL;
 
/* clamp to valid offset range */
if (start >= utf8_size) start = utf8_size;
if (end >= utf8_size) end = utf8_size;
 
*plen = end - start;
 
return text->utf8_data + start;
}
 
/**
* Calculate the line height, in pixels
*
* \return Line height, in pixels
*/
float textplain_line_height(void)
{
/* Size is in points, so convert to pixels.
* Then use a constant line height of 1.2 x font size.
*/
return FIXTOFLT(FDIV((FMUL(FLTTOFIX(1.2), FMUL(nscss_screen_dpi,
INTTOFIX((textplain_style.size / FONT_SIZE_SCALE))))), F_72));
}
 
/**
* Get the browser window containing a textplain content
*
* \param c text/plain content
* \return the browser window
*/
struct browser_window *textplain_get_browser_window(struct content *c)
{
textplain_content *text = (textplain_content *) c;
 
assert(c != NULL);
assert(c->handler == &textplain_content_handler);
 
return text->bw;
}
 
/programs/network/netsurf/netsurf/render/textplain.h
0,0 → 1,52
/*
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
* Copyright 2006 Adrian Lees <adrianl@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Content for text/plain (interface).
*/
 
#ifndef _NETSURF_RENDER_TEXTPLAIN_H_
#define _NETSURF_RENDER_TEXTPLAIN_H_
 
#include <stddef.h>
#include "desktop/mouse.h"
 
struct content;
struct hlcache_handle;
struct http_parameter;
struct rect;
 
nserror textplain_init(void);
 
/* access to lines for text selection and searching */
unsigned long textplain_line_count(struct content *c);
size_t textplain_size(struct content *c);
 
size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir);
void textplain_coords_from_range(struct content *c,
unsigned start, unsigned end, struct rect *r);
char *textplain_get_line(struct content *c, unsigned lineno,
size_t *poffset, size_t *plen);
int textplain_find_line(struct content *c, unsigned offset);
char *textplain_get_raw_data(struct content *c,
unsigned start, unsigned end, size_t *plen);
struct browser_window *textplain_get_browser_window(struct content *c);
void textplain_set_search(struct content *c, struct search_context *s);
 
#endif
/programs/network/netsurf/netsurf/resources/FatMessages
0,0 → 1,5783
#
# Messages for NetSurf
#
# ==============================================================================
# Reference version.
# When updating this file, ensure you keep the translations in sync by adding
# the other languages next to your addition.
# ==============================================================================
#
# Description
# -----------
#
# This file contains lines of colon separated key-value pairs in the format:
#
# Key:Value
#
# Contents of Key _must_ be representable in the US-ASCII character set and
# should not be modified for translation purposes.
#
# Values must be UTF-8 encoded strings. When these strings are displayed in
# NetSurf's user interface, they are converted to the system's local character
# set. As a result of this conversion process, unrepresentable characters are
# stripped from the displayed string.
#
# Blank lines and lines starting with a # character are treated as comments and
# ignored.
#
# This file gets processed by utils/split-messages.pl at build-time, which gets
# told the language and the platform. It then emits only messages that are
# in the right language, and are either in the specific platform or 'all'.
#
# If you find something tagged 'all', but it is only relevant to a specific
# front end, please change it. Currently, we have 'all', 'ro', 'gtk' and
# 'ami'.
#
# Globals
en.all.NetSurf:NetSurf
de.all.NetSurf:NetSurf
fr.all.NetSurf:NetSurf
it.all.NetSurf:NetSurf
nl.all.NetSurf:NetSurf
en.all.NetSurfCopyright:Copyright © 2003 - 2012 The NetSurf Developers
de.all.NetSurfCopyright:Copyright © 2003 - 2012 The NetSurf Developers
fr.all.NetSurfCopyright:Copyright © 2003 - 2012 The NetSurf Developers
it.all.NetSurfCopyright:Copyright © 2003 - 2012 The NetSurf Developers
nl.all.NetSurfCopyright:Copyright © 2003 - 2012 The NetSurf Developers
 
# Menus
# =====
#
# This section defines the title and entry text for NetSurf's menus.
#
 
# Iconbar menu
#
en.all.Info:Info
de.all.Info:Info
fr.all.Info:Info
it.all.Info:Info
nl.all.Info:Informatie
en.all.AppHelp:Help... F1
de.all.AppHelp:Hilfe... F1
fr.all.AppHelp:Aide... F1
it.all.AppHelp:Aiuto... F1
nl.all.AppHelp:Hulp... F1
en.all.Open:Open
de.all.Open:Öffnen
fr.all.Open:Ouvrir
it.all.Open:Apri
nl.all.Open:Open
en.all.Choices:Choices...
de.all.Choices:Einstellungen...
fr.all.Choices:Préférences...
it.all.Choices:Scegli...
nl.all.Choices:Keuzes...
en.all.Quit:Quit
de.all.Quit:Beenden
fr.all.Quit:Quitter
it.all.Quit:Esci
nl.all.Quit:Stop
 
# Iconbar -> Open menu
#
en.all.OpenURL:Open URL
de.all.OpenURL:Öffne URL
fr.all.OpenURL:Ouvrir l'URL...
it.all.OpenURL:Apri URL
nl.all.OpenURL:Open URL
 
# Main menu
#
en.all.Page:Page
de.all.Page:Seite
fr.all.Page:Page
it.all.Page:Pagina
nl.all.Page:Pagina
en.all.Object:Object
de.all.Object:Objekt
fr.all.Object:Objet
it.all.Object:Immagine
nl.all.Object:Object
en.all.Navigate:Navigate
de.all.Navigate:Navigieren
fr.all.Navigate:Navigation
it.all.Navigate:Visualizza
nl.all.Navigate:Navigeer
en.all.View:Display
de.all.View:Anzeige
fr.all.View:Affichage
it.all.View:Display
nl.all.View:Weergave
en.all.Utilities:Utilities
de.all.Utilities:Werkzeuge
fr.all.Utilities:Utilitaires
it.all.Utilities:Utilità
nl.all.Utilities:Utilities
en.ro.Help:Help
de.ro.Help:Hilfe
fr.ro.Help:Aide
it.ro.Help:Aiuto
nl.ro.Help:Hulp
 
# Main -> Page menu
#
en.all.PageInfo:Info ^F1
de.all.PageInfo:Info ^F1
fr.all.PageInfo:Info ^F1
it.all.PageInfo:Info ^F1
nl.all.PageInfo:Informatie ^F1
en.all.Save:Save F3
de.all.Save:Speichern F3
fr.all.Save:Sauver F3
it.all.Save:Salva F3
nl.all.Save:Bewaar F3
en.all.SaveComp:Full save ⇑F3
de.all.SaveComp:Alles speichern ⇑F3
fr.all.SaveComp:Sauvegarde Complète ⇑F3
it.all.SaveComp:Salva Tutto ⇑F3
nl.all.SaveComp:Bewaar alles ⇑F3
en.all.Export:Export
de.all.Export:Exportieren
fr.all.Export:Exporter
it.all.Export:Esporta
nl.all.Export:Exporteer
en.all.SaveURL:Save location
de.all.SaveURL:URL speichern
fr.all.SaveURL:Sauver le lieu
it.all.SaveURL:Salva indirizzo
nl.all.SaveURL:Bewaar adres
en.all.Print:Print PRINT
de.all.Print:Drucken DRUCK
fr.all.Print:Imprimer PRINT
it.all.Print:Stampa STAMPA
nl.all.Print:Afdrukken PRINT
en.all.NewWindow:New window ^N
de.all.NewWindow:Neues Fenster ^N
fr.all.NewWindow:Nouvelle fenêtre ^N
it.all.NewWindow:Nuova finestra ^N
nl.all.NewWindow:Nieuw venster ^N
en.all.ViewSrc:View source... F8
de.all.ViewSrc:Quellcode... F8
fr.all.ViewSrc:Voir le source... F8
it.all.ViewSrc:Mostra sorgente... F8
nl.all.ViewSrc:Bekijk HTML... F8
 
# Main -> Page -> Export menu
#
en.all.Draw:Draw ⇑^F3
de.all.Draw:Draw ⇑^F3
fr.all.Draw:Draw ⇑^F3
it.all.Draw:Draw ⇑^F3
nl.all.Draw:Draw ⇑^F3
en.all.PDF:PDF
de.all.PDF:PDF
fr.all.PDF:PDF
it.all.PDF:PDF
nl.all.PDF:PDF
en.all.Text:Text ^F3
de.all.Text:Text ^F3
fr.all.Text:Texte ^F3
it.all.Text:Testo ^F3
nl.all.Text:Tekst ^F3
 
# Main -> Page -> Save location menu
#
en.ro.URI:Acorn URI
de.ro.URI:Acorn URI
fr.ro.URI:Acorn URI
it.ro.URI:Acorn URI
nl.ro.URI:Acorn URI
en.ro.URL:ANT URL
de.ro.URL:ANT URL
fr.ro.URL:ANT URL
it.ro.URL:ANT URL
nl.ro.URL:ANT URL
en.all.LinkText:Text
de.all.LinkText:Text
fr.all.LinkText:Texte
it.all.LinkText:Testo
nl.all.LinkText:Tekst
 
# Main -> Object -> Object menu
#
en.all.ObjInfo:Info
de.all.ObjInfo:Info
fr.all.ObjInfo:Info
it.all.ObjInfo:Info
nl.all.ObjInfo:Informatie
en.all.ObjSave:Save
de.all.ObjSave:Speichern
fr.all.ObjSave:Sauver
it.all.ObjSave:Salva
nl.all.ObjSave:Bewaar
en.all.ObjPrint:Print
de.all.ObjPrint:Drucken
fr.all.ObjPrint:Imprimer
it.all.ObjPrint:Stampa
nl.all.ObjPrint:Afdrukken
en.all.ObjReload:Reload
de.all.ObjReload:erneut laden
fr.all.ObjReload:Recharger
it.all.ObjReload:Ricarica
nl.all.ObjReload:Herlaad
 
# Main -> Object -> Object -> Export menu
#
en.all.Sprite:Sprite
de.all.Sprite:Sprite
fr.all.Sprite:Sprite
it.all.Sprite:Sprite
nl.all.Sprite:Sprite
en.all.ObjDraw:Draw
de.all.ObjDraw:Draw
fr.all.ObjDraw:Draw
it.all.ObjDraw:Draw
nl.all.ObjDraw:Draw
 
# Main -> Object -> Link menu
en.all.LinkSave:Save
de.all.LinkSave:Speichern
fr.all.LinkSave:Save
it.all.LinkSave:Salva
nl.all.LinkSave:Save
en.all.LinkDload:Download target
de.all.LinkDload:Ziel speichern
fr.all.LinkDload:Download target
it.all.LinkDload:Salva file in...
nl.all.LinkDload:Download target
en.all.LinkNew:New window
de.all.LinkNew:Neues Fenster
fr.all.LinkNew:New window
it.all.LinkNew:Nuova finestra
nl.all.LinkNew:New window
 
# Main -> Selection menu
en.all.SelSave:Save
de.all.SelSave:Speichern
fr.all.SelSave:Save
it.all.SelSave:Salva
nl.all.SelSave:Save
 
# Main -> Navigate menu
#
en.all.Home:Home page
de.all.Home:Homepage
fr.all.Home:Page d'accueil
it.all.Home:Pagina iniziale
nl.all.Home:Startpagina
en.all.Back:Back one page
de.all.Back:Eine Seite zurück
fr.all.Back:Retour
it.all.Back:Indietro
nl.all.Back:Vorige pagina
en.all.Forward:Forward one page
de.all.Forward:Eine Seite vor
fr.all.Forward:Avancer
it.all.Forward:Avanti
nl.all.Forward:Volgende pagina
en.all.UpLevel:Up one level
de.all.UpLevel:Eine Ebene hoch
fr.all.UpLevel:Remonter d'un niveau
it.all.UpLevel:Livello superiore
nl.all.UpLevel:Een niveau omhoog
en.all.Reload:Reload this page ^F5
de.all.Reload:Seite erneut laden ^F5
fr.all.Reload:Recharger cette page ^F5
it.all.Reload:Ricarica
nl.all.Reload:Pagina opnieuw laden ^F5
en.all.Stop:Stop loading this page
de.all.Stop:Ladevorgang abbrechen
fr.all.Stop:Arrêter le chargement de la page
it.all.Stop:Stop
nl.all.Stop:Pagina ophalen afbreken
 
# Main -> Display menu
#
en.all.ScaleView:Scale view F11
de.all.ScaleView:Vergrößerung F11
fr.all.ScaleView:Ajuster la vue F11
it.all.ScaleView:Visualizzazione graduale F11
nl.all.ScaleView:Pagina schalen F11
en.all.Images:Images
de.all.Images:Bilder
fr.all.Images:Images
it.all.Images:Immagini
nl.all.Images:Afbeeldingen
en.all.Toolbars:Toolbars
de.all.Toolbars:Anzeigen und Leisten
fr.all.Toolbars:Barre d'outils
it.all.Toolbars:Barre strumenti
nl.all.Toolbars:Werkbalk
en.all.Render:Render
de.all.Render:Rendern
fr.all.Render:Rendu
it.all.Render:Interprete
nl.all.Render:Weergeven
en.all.OptDefault:Save as default
de.all.OptDefault:als Standard speichern
fr.all.OptDefault:Définir par défaut
it.all.OptDefault:Salva come predefinito
nl.all.OptDefault:Als standaard instellen
 
# Main -> Display -> Images menu
#
en.all.ForeImg:Foreground images
de.all.ForeImg:Vordergrundbilder
fr.all.ForeImg:Images de premier plan
it.all.ForeImg:Immagini in primo piano
nl.all.ForeImg:Voorgrondafbeelding
en.all.BackImg:Background images
de.all.BackImg:Hintergrundbilder
fr.all.BackImg:Images de fond
it.all.BackImg:Immagini in sottofondo
nl.all.BackImg:Achtergrondafbeelding
 
# Main -> Display -> Toolbars menu
#
en.all.ToolButtons:Buttons
de.all.ToolButtons:Knopfgrafiken
fr.all.ToolButtons:Boutons
it.all.ToolButtons:Pulsanti
nl.all.ToolButtons:Knoppen
en.all.ToolAddress:Address bar
de.all.ToolAddress:Adressleiste
fr.all.ToolAddress:Barre d'adresse
it.all.ToolAddress:Barra indirizzi
nl.all.ToolAddress:Adresbalk
en.all.ToolThrob:Throbber
de.all.ToolThrob:Ladeaktivität
fr.all.ToolThrob:Pulseur
it.all.ToolThrob:Indicatore di attività
nl.all.ToolThrob:Laadactiviteit
en.all.ToolStatus:Status bar
de.all.ToolStatus:Statusanzeige
fr.all.ToolStatus:Barre d'état
it.all.ToolStatus:Barra di stato
nl.all.ToolStatus:Status balk
 
# Main -> Display -> Render menu
#
en.all.RenderAnims:Buffer animations
de.all.RenderAnims:Animationen zwischenspeichern
fr.all.RenderAnims:Tamponner les animations
it.all.RenderAnims:Blocca le animazioni
nl.all.RenderAnims:Buffer animaties
en.all.RenderAll:Buffer all rendering
de.all.RenderAll:Alles zwischenspeichern
fr.all.RenderAll:Tamponner tous les rendus
it.all.RenderAll:Blocca tutto l'interprete
nl.all.RenderAll:Buffer alle weergaven
 
# Main -> Utilities menu
#
en.all.Hotlist:Hotlist
de.all.Hotlist:Hotlist
fr.all.Hotlist:Favoris
it.all.Hotlist:Segnalibri
nl.all.Hotlist:Bladwijzers
en.all.History:History
de.all.History:History
fr.all.History:Historique
it.all.History:Cronologia locale
nl.all.History:Historie
en.all.Cookies:Cookies
de.all.Cookies:Cookies
fr.all.Cookies:Cookies
it.all.Cookies:Cookie
nl.all.Cookies:Cookies
en.all.FindText:Find text F4
de.all.FindText:Text suchen F4
fr.all.FindText:Recherche de texte F4
it.all.FindText:Trova testo F4
nl.all.FindText:Tekst zoeken F4
en.all.Window:Window
de.all.Window:Fenster
fr.all.Window:Fenêtre
it.all.Window:Finestra
nl.all.Window:Venster
 
# Main -> Utilities -> Hotlist menu
#
en.all.HotlistAdd:Add to hotlist
de.all.HotlistAdd:Eintrag hinzufügen
fr.all.HotlistAdd:Ajouter aux favoris
it.all.HotlistAdd:Aggiungi ai segnalibri
nl.all.HotlistAdd:Toevoegen aan bladwijzers
en.all.HotlistShow:Show hotlist... F6
de.all.HotlistShow:Hotlist zeigen... F6
fr.all.HotlistShow:Montrer les favoris... F6
it.all.HotlistShow:Mostra segnalibri... F6
nl.all.HotlistShow:Toon bladwijzers F6
 
# Main -> Utilities -> History menu
#
en.all.HistLocal:Show local history... F7
de.all.HistLocal:History (lokal) zeigen... F7
fr.all.HistLocal:Montrer l'historique local... F7
it.all.HistLocal:Mostra cronologia locale... F7
nl.all.HistLocal:Toon historie (lokaal)... F7
en.all.HistGlobal:Show global history... ^F7
de.all.HistGlobal:History (global) zeigen... ^F7
fr.all.HistGlobal:Montrer l'historique global... ^F7
it.all.HistGlobal:Mostra cronologia globale... ^F7
nl.all.HistGlobal:Toon historie (globaal)... ^F7
 
# Main -> Utilities -> Cookies menu
en.all.ShowCookies:Show cookies...
de.all.ShowCookies:Cookies verwalten
fr.all.ShowCookies:Montrer les cookies...
it.all.ShowCookies:Mostra cookie...
nl.all.ShowCookies:Toon cookies...
en.all.DeleteCookies:Delete all cookies
de.all.DeleteCookies:Alle Cookies löschen
fr.all.DeleteCookies:Supprimer tous les cookies
it.all.DeleteCookies:Cancella tutti i cookie
nl.all.DeleteCookies:Verwijder alle cookies
 
# Main -> Utilities -> Window menu
#
en.all.WindowSave:Set as default position
de.all.WindowSave:aktuelle Fensterposition speichern
fr.all.WindowSave:Définir comme position par défaut
it.all.WindowSave:Imposta come posizione predefinita
nl.all.WindowSave:Als standaard positie opslaan
en.all.WindowStagr:Stagger window position
de.all.WindowStagr:neue Fenster versetzen
fr.all.WindowStagr:Décaler la position des nouv. fenêtres
it.all.WindowStagr:Sfalsa posizione della finestra
nl.all.WindowStagr:Nieuw venster verplaatsen
en.all.WindowSize:Copy window position
de.all.WindowSize:Fenstergröße beibehalten
fr.all.WindowSize:Garder cette taille de fenêtre
it.all.WindowSize:Copia posizione della finestra
nl.all.WindowSize:Copieer venster positie
en.all.WindowReset:Reset default position
de.all.WindowReset:Fensterposition zurücksetzen
fr.all.WindowReset:RAZ de la position par défaut
it.all.WindowReset:Resetta posizione della finestra
nl.all.WindowReset:Venster positie terugzetten
 
# Main -> Help menu
#
en.ro.HelpContent:Contents F1
de.ro.HelpContent:Inhalt F1
fr.ro.HelpContent:Contenus F1
it.ro.HelpContent:Contenuti F1
nl.ro.HelpContent:Inhoud F1
en.ro.HelpGuide:User guide
de.ro.HelpGuide:Handbuch
fr.ro.HelpGuide:Guide de l'utilisateur
it.ro.HelpGuide:Guida in linea
nl.ro.HelpGuide:Handboek
en.ro.HelpInfo:User information
de.ro.HelpInfo:Nutzerinformation
fr.ro.HelpInfo:Information utilisateur
it.ro.HelpInfo:Informazioni utente
nl.ro.HelpInfo:Gebruikers informatie
en.all.HelpCredits:Credits
de.all.HelpCredits:Credits
fr.all.HelpCredits:Credits
it.all.HelpCredits:Ringraziamenti
nl.all.HelpCredits:Credits
en.all.HelpLicence:Licence
de.all.HelpLicence:Lizenz
fr.all.HelpLicence:Licence
it.all.HelpLicence:Licenza
nl.all.HelpLicence:Licence
en.ro.HelpInter:Interactive help
de.ro.HelpInter:interaktive Hilfe
fr.ro.HelpInter:Aide interactive
it.ro.HelpInter:Aiuto interattivo
nl.ro.HelpInter:Interactieve hulp
 
# Toolbar menu
#
en.all.Toolbar:Toolbar
de.all.Toolbar:Symbolleiste
fr.all.Toolbar:Barre d'outils
it.all.Toolbar:Barra strumenti
nl.all.Toolbar:Werkbalk
en.all.EditToolbar:Edit toolbar
de.all.EditToolbar:Symbolleiste bearbeiten
fr.all.EditToolbar:Barre de configuration
it.all.EditToolbar:Modifica barra strumenti
nl.all.EditToolbar:Werkbalk aanpassen
 
# Generic tree menus (currently Hotlist and Global history)
#
en.all.Selection:Selection
de.all.Selection:Auswahl
fr.all.Selection:Sélection
it.all.Selection:Seleziona
nl.all.Selection:Selectie
en.all.SelectAll:Select all ^A
de.all.SelectAll:Alles auswählen ^A
fr.all.SelectAll:Tout sélectionner ^A
it.all.SelectAll:Seleziona Tutto ^A
nl.all.SelectAll:Selecteer alles ^A
en.all.Clear:Clear selection ^Z
de.all.Clear:Auswahl aufheben ^Z
fr.all.Clear:Effacer la sélection ^Z
it.all.Clear:Cancella selezione ^Z
nl.all.Clear:Selectie opheffen ^Z
en.all.Copy:Copy to clipboard ^C
de.all.Copy:Auswahl kopieren ^C
fr.all.Copy:Copier vers le presse-papier ^C
it.all.Copy:Copia nella clipboard ^C
nl.all.Copy:Copieer naar prikbord ^C
en.all.Cut:Cut to clipboard ^X
de.all.Cut:Ausschneiden ^X
fr.all.Cut:Cut to clipboard ^X
it.all.Cut:Taglia dalla clipboard ^X
nl.all.Cut:Cut to clipboard ^X
en.all.Paste:Paste from clipboard ^V
de.all.Paste:Einfügen ^V
fr.all.Paste:Paste from clipboard ^V
it.all.Paste:Incolla sulla clipboard ^V
nl.all.Paste:Paste from clipboard ^V
 
# Selection Menu
#
en.all.Edit:Edit
de.all.Edit:Bearbeiten
fr.all.Edit:Éditer
it.all.Edit:Modifica
nl.all.Edit:Bewerken
en.all.Launch:Launch RETURN
de.all.Launch:Öffnen RETURN
fr.all.Launch:Lancer RETURN
it.all.Launch:Avvia INVIO
nl.all.Launch:Openen RETURN
en.all.Delete:Delete ^X
de.all.Delete:Löschen ^X
fr.all.Delete:Supprimer ^X
it.all.Delete:Cancella ^X
nl.all.Delete:Verwijderen ^X
en.all.ResetUsage:Reset statistics
de.all.ResetUsage:Statistik zurücksetzen
fr.all.ResetUsage:RAZ des statistiques
it.all.ResetUsage:Resetta statistiche
nl.all.ResetUsage:Statistiek op nul zetten
 
# Hotlist/Global history menu
#
en.all.New:New
de.all.New:Neu
fr.all.New:Nouveau
it.all.New:Nuovo
nl.all.New:Nieuw
en.all.Expand:Expand
de.all.Expand:Expandieren
fr.all.Expand:Déployer
it.all.Expand:Espandi
nl.all.Expand:Uitklappen
en.all.Collapse:Collapse
de.all.Collapse:Zusammenfalten
fr.all.Collapse:Regrouper
it.all.Collapse:Raggruppa
nl.all.Collapse:Inklappen
en.all.Tree:Tree
de.all.Tree:Tree
fr.all.Tree:Tree
it.all.Tree:Albero
nl.all.Tree:Tree
en.all.TreeExport:Export...
de.all.TreeExport:Export...
fr.all.TreeExport:Export...
it.all.TreeExport:Esporta...
nl.all.TreeExport:Export...
 
# New hotlist entry menu
#
en.all.Folder:Directory
de.all.Folder:Verzeichnis
fr.all.Folder:Dossier
it.all.Folder:Cartella
nl.all.Folder:Map
en.all.Link:Address
de.all.Link:Verweis
fr.all.Link:Link
it.all.Link:Link
nl.all.Link:Link
 
# Tree expand/collapse menu
#
en.all.All:All
de.all.All:Alles
fr.all.All:Tout
it.all.All:Tutte
nl.all.All:Alles
en.all.Folders:Directories
de.all.Folders:Verzeichnisse
fr.all.Folders:Dossiers
it.all.Folders:Cartelle
nl.all.Folders:Mappen
en.all.Links:Addresses
de.all.Links:Einträge
fr.all.Links:Adresses
it.all.Links:Indirizzi
nl.all.Links:Adressen
en.all.Domains:Domains
de.all.Domains:Domains
fr.all.Domains:Domains
it.all.Domains:Domini
nl.all.Domains:Domains
 
# Other menus
#
# URL suggestion menu
en.all.URLSuggest:Recent URLs
de.all.URLSuggest:Aktuelle URLs
fr.all.URLSuggest:URLs récentes
it.all.URLSuggest:URL recenti
nl.all.URLSuggest:Recente URLs
 
# Menus within the choices system
#
# Browser pane
en.all.Languages:Language
de.all.Languages:Sprachen
fr.all.Languages:Langue
it.all.Languages:Lingua
nl.all.Languages:Taal
#
# Network pane
en.all.ProxyType:Proxy type
de.all.ProxyType:Proxytyp
fr.all.ProxyType:Type de proxy
it.all.ProxyType:Tipo di Proxy
nl.all.ProxyType:Proxy type
en.all.ProxyNone:No proxy
de.all.ProxyNone:kein Proxy
fr.all.ProxyNone:Pas de proxy
it.all.ProxyNone:Nessuno
nl.all.ProxyNone:Geen proxy
en.all.ProxyNoAuth:Simple proxy
de.all.ProxyNoAuth:normaler Proxy
fr.all.ProxyNoAuth:Proxy simple
it.all.ProxyNoAuth:Semplice
nl.all.ProxyNoAuth:Simpele proxy
en.all.ProxyBasic:Basic authentication
de.all.ProxyBasic:mit Authentifizierung
fr.all.ProxyBasic:Authentification de base
it.all.ProxyBasic:Autentificato di base
nl.all.ProxyBasic:Basis authenticatie
en.all.ProxyNTLM:NTLM authentication
de.all.ProxyNTLM:NTLM Authentifizierung
fr.all.ProxyNTLM:Authentification NTLM
it.all.ProxyNTLM:Autentificato NTLM
nl.all.ProxyNTLM:NTLM authenticatie
#
# Fonts pane
en.all.Fonts:Fonts
de.all.Fonts:Schriften
fr.all.Fonts:Fontes
it.all.Fonts:Font
nl.all.Fonts:Lettertypen
en.all.DefaultFonts:Font Families
de.all.DefaultFonts:Schriftfamilien
fr.all.DefaultFonts:Familles de fontes
it.all.DefaultFonts:Famiglia Font
nl.all.DefaultFonts:Font families
#
# Images pane
en.all.Display:Display
de.all.Display:Ausgabe
fr.all.Display:Affichage
it.all.Display:Display
nl.all.Display:Weergave
en.all.ImgStyle0:Use OS
de.all.ImgStyle0:RISC OS nutzen
fr.all.ImgStyle0:Utiliser l'OS
it.all.ImgStyle0:Usa OS
nl.all.ImgStyle0:RISC OS gebruiken
en.all.ImgStyle1:Direct to screen
de.all.ImgStyle1:Direktausgabe
fr.all.ImgStyle1:Directement sur l'écran
it.all.ImgStyle1:Diretto su schermo
nl.all.ImgStyle1:Direct weergave
en.all.ImgStyle2:Dithered
de.all.ImgStyle2:Dithern
fr.all.ImgStyle2:Tramé
it.all.ImgStyle2:Dithered
nl.all.ImgStyle2:Ditheren
en.all.ImgStyle3:Error diffused
de.all.ImgStyle3:Error-Diffusion
fr.all.ImgStyle3:Avec diffusion d'erreur
it.all.ImgStyle3:Diffusione errore
nl.all.ImgStyle3:Fout-spreiding
 
# Menu items used in the Amiga version.
# Some of these are copies of other strings but without the
# embedded shortcut keys. (NS suffix = No Shortcut)
#
# Project menu
#
en.ami.Project:Project
de.ami.Project:Projekt
fr.ami.Project:Project
it.ami.Project:Progetto
nl.ami.Project:Project
en.all.NewWindowNS:New window
de.all.NewWindowNS:Neues Fenster
fr.all.NewWindowNS:New window
it.all.NewWindowNS:Nuova finestra
nl.all.NewWindowNS:New window
en.all.NewTab:New tab
de.all.NewTab:Neuer Tab
fr.all.NewTab:New tab
it.all.NewTab:Nuova scheda
nl.all.NewTab:New tab
en.all.CloseTab:Close tab
de.all.CloseTab:Schließe Tab
fr.all.CloseTab:Close tab
it.all.CloseTab:Chiudi scheda
nl.all.CloseTab:Close tab
en.all.CloseWindow:Close window
de.all.CloseWindow:Schließe Fenster
fr.all.CloseWindow:Close window
it.all.CloseWindow:Chiudi finestra
nl.all.CloseWindow:Close window
en.all.SaveAsNS:Save as
de.all.SaveAsNS:Speichern als
fr.all.SaveAsNS:Save as
it.all.SaveAsNS:Salva come
nl.all.SaveAsNS:Save as
en.all.Source:Source...
de.all.Source:Quelle...
fr.all.Source:Source...
it.all.Source:Sorgente...
nl.all.Source:Source...
en.all.TextNS:Text...
de.all.TextNS:Text...
fr.all.TextNS:Text...
it.all.TextNS:Testo...
nl.all.TextNS:Text...
en.all.SaveCompNS:Complete...
de.all.SaveCompNS:Komplett...
fr.all.SaveCompNS:Complete...
it.all.SaveCompNS:HTML...
nl.all.SaveCompNS:Complete...
en.all.PDFNS:PDF...
de.all.PDFNS:PDF...
fr.all.PDFNS:PDF...
it.all.PDFNS:PDF...
nl.all.PDFNS:PDF...
en.ami.IFF:IFF...
de.ami.IFF:IFF...
fr.ami.IFF:IFF...
it.ami.IFF:IFF...
nl.ami.IFF:IFF...
en.all.OpenFile:Open local file...
de.all.OpenFile:Öffne lokale Datei...
fr.all.OpenFile:Open local file...
it.all.OpenFile:Apri file locale...
nl.all.OpenFile:Open local file...
en.all.About:About...
de.all.About:Ãœber...
fr.all.About:About...
it.all.About:Informazioni...
nl.all.About:About...
en.all.PrintNS:Print...
de.all.PrintNS:Drucken...
fr.all.PrintNS:Print...
it.all.PrintNS:Stampa...
nl.all.PrintNS:Print...
 
# Edit menu
#
en.all.CutNS:Cut
de.all.CutNS:Ausschneiden
fr.all.CutNS:Cut
it.all.CutNS:Taglia
nl.all.CutNS:Cut
en.all.CopyNS:Copy
de.all.CopyNS:Kopieren
fr.all.CopyNS:Copy
it.all.CopyNS:Copia
nl.all.CopyNS:Copy
en.all.PasteNS:Paste
de.all.PasteNS:Einfügen
fr.all.PasteNS:Paste
it.all.PasteNS:Incolla
nl.all.PasteNS:Paste
en.all.SelectAllNS:Select all
de.all.SelectAllNS:Alles auswählen
fr.all.SelectAllNS:Select all
it.all.SelectAllNS:Seleziona Tutto
nl.all.SelectAllNS:Select all
en.all.ClearNS:Clear selection
de.all.ClearNS:Auswahl rückgängig
fr.all.ClearNS:Clear selection
it.all.ClearNS:Annulla selezione
nl.all.ClearNS:Clear selection
 
# Browser menu
#
en.all.Browser:Browser
de.all.Browser:Browser
fr.all.Browser:Browser
it.all.Browser:Visualizza
nl.all.Browser:Browser
en.all.HistGlobalNS:Show global history...
de.all.HistGlobalNS:Zeige globale History...
fr.all.HistGlobalNS:Show global history...
it.all.HistGlobalNS:Mostra cronologia globale...
nl.all.HistGlobalNS:Show global history...
en.all.HistLocalNS:Show local history...
de.all.HistLocalNS:Zeige lokale History...
fr.all.HistLocalNS:Show local history...
it.all.HistLocalNS:Mostra cronologia locale...
nl.all.HistLocalNS:Show local history...
en.all.FindTextNS:Find text...
de.all.FindTextNS:Suchen...
fr.all.FindTextNS:Find text...
it.all.FindTextNS:Trova testo...
nl.all.FindTextNS:Find text...
en.all.Redraw:Redraw page
de.all.Redraw:Seite neu aufbauen
fr.all.Redraw:Redraw page
it.all.Redraw:Ridisegna pagina
nl.all.Redraw:Redraw page
en.all.ScaleNS:Scale
de.all.ScaleNS:Skalieren
fr.all.ScaleNS:Scale
it.all.ScaleNS:Scala di zoom
nl.all.ScaleNS:Scale
en.all.ScaleInc:Increase
de.all.ScaleInc:Vergrößern
fr.all.ScaleInc:Increase
it.all.ScaleInc:Incrementa
nl.all.ScaleInc:Increase
en.all.ScaleDec:Decrease
de.all.ScaleDec:Verkleinern
fr.all.ScaleDec:Decrease
it.all.ScaleDec:Decrementa
nl.all.ScaleDec:Decrease
en.all.ScaleNorm:Normal
de.all.ScaleNorm:Normal
fr.all.ScaleNorm:Normal
it.all.ScaleNorm:Normale
nl.all.ScaleNorm:Normal
 
# Hotlist menu
#
en.all.HotlistShowNS:Show hotlist...
de.all.HotlistShowNS:Zeige Hotlist...
fr.all.HotlistShowNS:Show hotlist...
it.all.HotlistShowNS:Mostra segnalibri...
nl.all.HotlistShowNS:Show hotlist...
 
# Settings menu
#
en.all.SettingsEdit:Edit preferences...
de.all.SettingsEdit:Voreinstellungen...
fr.all.SettingsEdit:Edit preferences...
it.all.SettingsEdit:Modifica...
nl.all.SettingsEdit:Edit preferences...
en.all.Settings:Settings
de.all.Settings:Einstellungen
fr.all.Settings:Settings
it.all.Settings:Preferenze
nl.all.Settings:Settings
en.all.SnapshotWindow:Snapshot window
de.all.SnapshotWindow:Schnappschuß
fr.all.SnapshotWindow:Snapshot window
it.all.SnapshotWindow:Fissa finestra
nl.all.SnapshotWindow:Snapshot window
en.all.SettingsSave:Save settings
de.all.SettingsSave:Einstellungen speichern
fr.all.SettingsSave:Save settings
it.all.SettingsSave:Salva
nl.all.SettingsSave:Save settings
 
# ARexx menu
#
en.ami.ARexx:ARexx
de.ami.ARexx:ARexx
fr.ami.ARexx:ARexx
it.ami.ARexx:ARexx
nl.ami.ARexx:ARexx
en.ami.ARexxExecute:Execute script...
de.ami.ARexxExecute:Script ausführen...
fr.ami.ARexxExecute:Execute script...
it.ami.ARexxExecute:Esegui script...
nl.ami.ARexxExecute:Execute script...
 
# Context menu
#
en.all.Link:Link
de.all.Link:Link
fr.all.Link:Link
it.all.Link:Link
nl.all.Link:Link
en.all.LinkNewTab:Open in new tab
de.all.LinkNewTab:Öffnen in Tab
fr.all.LinkNewTab:Open in new tab
it.all.LinkNewTab:Apri in una nuova scheda
nl.all.LinkNewTab:Open in new tab
en.all.LinkNewWin:Open in new window
de.all.LinkNewWin:Öffnen in Fenster
fr.all.LinkNewWin:Open in new window
it.all.LinkNewWin:Apri in una nuova finestra
nl.all.LinkNewWin:Open in new window
en.all.CopyURL:Copy URL to clipboard
de.all.CopyURL:URL ins Clipboard
fr.all.CopyURL:Copy URL to clipboard
it.all.CopyURL:Copia URL nella clipboard
nl.all.CopyURL:Copy URL to clipboard
en.all.CopyClip:Copy to clipboard
de.all.CopyClip:Inhalt ins Clipboard
fr.all.CopyClip:Copy to clipboard
it.all.CopyClip:Copia nella clipboard
nl.all.CopyClip:Copy to clipboard
en.all.SaveAs:Save as...
de.all.SaveAs:Speichern als...
fr.all.SaveAs:Save as...
it.all.SaveAs:Salva come...
nl.all.SaveAs:Save as...
en.ami.SaveIFF:Save as IFF...
de.ami.SaveIFF:Speichern als IFF...
fr.ami.SaveIFF:Save as IFF...
it.ami.SaveIFF:Salva come IFF...
nl.ami.SaveIFF:Save as IFF...
en.all.SaveComplete:Save complete...
de.all.SaveComplete:Speichern abgeschlossen...
fr.all.SaveComplete:Save complete...
it.all.SaveComplete:Salva Tutto...
nl.all.SaveComplete:Save complete...
en.all.Close:Close
de.all.Close:Schließen
fr.all.Close:Close
it.all.Close:Chiudi
nl.all.Close:Close
en.all.ObjShow:Show object
de.all.ObjShow:Zeige Objekt
fr.all.ObjShow:Show object
it.all.ObjShow:Mostra
nl.all.ObjShow:Show object
en.all.Frame:Frame
de.all.Frame:Frame
fr.all.Frame:Frame
it.all.Frame:Frame
nl.all.Frame:Frame
en.all.FrameNewWin:Show in new window
de.all.FrameNewWin:In neuem Fenster anzeigen
fr.all.FrameNewWin:Show in new window
it.all.FrameNewWin:Apri frame in nuova finestra...
nl.all.FrameNewWin:Show in new window
en.all.FrameNewTab:Show in new tab
de.all.FrameNewTab:In neuem Tab anzeigen
fr.all.FrameNewTab:Show in new tab
it.all.FrameNewTab:Apri frame in nuova scheda
nl.all.FrameNewTab:Show in new tab
en.all.FrameOnly:Show only this frame
de.all.FrameOnly:Nur diesen Frame anzeigen
fr.all.FrameOnly:Show only this frame
it.all.FrameOnly:Apri frame in questa finestra
nl.all.FrameOnly:Show only this frame
 
en.all.SelectFile:Select file...
de.all.SelectFile:Datei auswählen...
fr.all.SelectFile:Select file...
it.all.SelectFile:Seleziona file...
nl.all.SelectFile:Select file...
en.all.ExternalApp:Open in external application
de.all.ExternalApp:In externer Anwendung öffnen..
fr.all.ExternalApp:Open in external application
it.all.ExternalApp:Apri con applicazione esterna
nl.all.ExternalApp:Open in external application
 
# Treeview interface tokens
# =========================
#
# This section contains tokens which are used in the treeview
# component. (For example, in the main hotlist/global history windows)
#
 
# Tree URL text
#
en.all.TreeAdded:Added: %s
de.all.TreeAdded:eingetragen am: %s
fr.all.TreeAdded:Ajoutée: %s
it.all.TreeAdded:Aggiunto: %s
nl.all.TreeAdded:Toegevoegd: %s
en.all.TreeLast:Last visited: %s
de.all.TreeLast:letzter Besuch: %s
fr.all.TreeLast:Dernière visitée: %s
it.all.TreeLast:Ultima visita: %s
nl.all.TreeLast:Laatst bezocht: %s
en.all.TreeVisited:Visited: %s
de.all.TreeVisited:gesehen am: %s
fr.all.TreeVisited:Visitées: %s
it.all.TreeVisited:Visitato: %s
nl.all.TreeVisited:Bezocht: %s
en.all.TreeVisits:Visits: %i
de.all.TreeVisits:Besuche gesamt: %i
fr.all.TreeVisits:Visites: %i
it.all.TreeVisits:Visite totali: %i
nl.all.TreeVisits:Bezichtigd: %i keer
en.all.TreeUnknown:Unknown
de.all.TreeUnknown:Unbekannt
fr.all.TreeUnknown:Inconnu
it.all.TreeUnknown:Sconosciuta/o
nl.all.TreeUnknown:Onbekend
en.all.TreeValue:Value: %s
de.all.TreeValue:Eintrag: %s
fr.all.TreeValue:Valeur: %s
it.all.TreeValue:Valore: %s
nl.all.TreeValue:Waarde: %s
en.all.TreeComment:Comment: %s
de.all.TreeComment:Kommentar: %s
fr.all.TreeComment:Commentaire: %s
it.all.TreeComment:Commento: %s
nl.all.TreeComment:Commentaar: %s
en.all.TreeDomain:Domain: %s%s
de.all.TreeDomain:Domain: %s%s
fr.all.TreeDomain:Domaine: %s%s
it.all.TreeDomain:Dominio: %s%s
nl.all.TreeDomain:Domein: %s%s
en.all.TreePath:Path: %s%s
de.all.TreePath:Pfad: %s%s
fr.all.TreePath:Chemin: %s%s
it.all.TreePath:Percorso: %s%s
nl.all.TreePath:Pad: %s%s
en.all.TreeExpires:Expires: %s
de.all.TreeExpires:Verfällt: %s
fr.all.TreeExpires:Expire: %s
it.all.TreeExpires:Scadenza: %s
nl.all.TreeExpires:Verloopt: %s
en.all.TreeLastUsed:Last used: %s
de.all.TreeLastUsed:Zuletzt genutzt: %s
fr.all.TreeLastUsed:Dernière utilisation: %s
it.all.TreeLastUsed:Ultimo utilizzo: %s
nl.all.TreeLastUsed:Laatst gebruikt: %s
en.all.TreeSecure:Secure hosts only: %s
de.all.TreeSecure:Nur sichere Hosts: %s
fr.all.TreeSecure:Uniquement des sites sécurisés: %s
it.all.TreeSecure:Solo host sicuri: %s
nl.all.TreeSecure:Alleen secure sites: %s
en.all.TreeVersion:Version: %s
de.all.TreeVersion:Version: %s
fr.all.TreeVersion:Version: %s
it.all.TreeVersion:Versione: %s
nl.all.TreeVersion:Versie: %s
en.all.TreePersistent:Persistent: %s
de.all.TreePersistent:Persistent: %s
fr.all.TreePersistent:Persistent: %s
it.all.TreePersistent:Persistenza: %s
nl.all.TreePersistent:Persistent: %s
en.all.TreeHeaders: (from headers)
de.all.TreeHeaders: (aus Header)
fr.all.TreeHeaders: (à partir des entêtes)
it.all.TreeHeaders: (da intestazioni)
nl.all.TreeHeaders: (van headers)
en.all.TreeVersion0:Netscape
de.all.TreeVersion0:Netscape
fr.all.TreeVersion0:Netscape
it.all.TreeVersion0:Netscape
nl.all.TreeVersion0:Netscape
en.all.TreeVersion1:RFC 2109
de.all.TreeVersion1:RFC 2109
fr.all.TreeVersion1:RFC 2109
it.all.TreeVersion1:RFC 2109
nl.all.TreeVersion1:RFC 2109
en.all.TreeVersion2:RFC 2965
de.all.TreeVersion2:RFC 2965
fr.all.TreeVersion2:RFC 2965
it.all.TreeVersion2:RFC 2965
nl.all.TreeVersion2:RFC 2965
en.all.TreeSession:Session end
de.all.TreeSession:Sitzungsende
fr.all.TreeSession:Fin de session
it.all.TreeSession:Fine sessione
nl.all.TreeSession:Sessie einde
en.all.TreeUnused:Unused
de.all.TreeUnused:Nicht benutzt
fr.all.TreeUnused:Inutilisé
it.all.TreeUnused:Inutilizzato
nl.all.TreeUnused:Ongebruikt
en.all.TreeImport:Imported URL
de.all.TreeImport:Importierte URL
fr.all.TreeImport:URL importée
it.all.TreeImport:URL importati
nl.all.TreeImport:Ge-importeerde URL
en.all.TreeNewLink:New address
de.all.TreeNewLink:New address
fr.all.TreeNewLink:New address
it.all.TreeNewLink:Nuovo indirizzo
nl.all.TreeNewLink:New address
en.all.TreeNewFolder:New directory
de.all.TreeNewFolder:Neues Verzeichnis
fr.all.TreeNewFolder:Nouv. répertoire
it.all.TreeNewFolder:Nuova cartella
nl.all.TreeNewFolder:Nieuwe map
en.all.TreeLaunch:Visit URL
de.all.TreeLaunch:URL ansehen
fr.all.TreeLaunch:Visit URL
it.all.TreeLaunch:Visita URL
nl.all.TreeLaunch:Visit URL
en.all.TreeDelete:Delete
de.all.TreeDelete:Löschen
fr.all.TreeDelete:Delete
it.all.TreeDelete:Elimina
nl.all.TreeDelete:Delete
en.all.TreeDefault:Set as default
de.all.TreeDefault:Set as default
fr.all.TreeDefault:Set as default
it.all.TreeDefault:Imposta come predefinito
nl.all.TreeDefault:Set as default
en.all.TreeClear:Clear default
de.all.TreeClear:Clear default
fr.all.TreeClear:Clear default
it.all.TreeClear:Annulla predefinito
nl.all.TreeClear:Clear default
 
 
# Tree export
#
en.all.TreeHotlist:NetSurf hotlist
de.all.TreeHotlist:NetSurf Hotlist
fr.all.TreeHotlist:Favoris de NetSurf
it.all.TreeHotlist:Segnalibri di NetSurf
nl.all.TreeHotlist:NetSurf bladwijzers
 
 
# Hotlist user interface tokens
# =============================
#
# This section contains tokens which are used in various parts of
# the hotlist user interface.
#
 
# Hotlist sub-window titles
#
en.all.NewLink:Create new address
de.all.NewLink:Neuen Eintrag erstellen
fr.all.NewLink:Créer une nouvelle adresse
it.all.NewLink:Crea nuovo indirizzo
nl.all.NewLink:Nieuw adres aanmaken
en.all.NewFolder:Create new directory
de.all.NewFolder:Verzeichnis anlegen
fr.all.NewFolder:Créer un nouveau dossier
it.all.NewFolder:Crea nuova cartella
nl.all.NewFolder:Nieuwe map aanmaken
en.all.EditTitle:Edit title
de.all.EditTitle:Edit title
fr.all.EditTitle:Edit title
it.all.EditTitle:Modifica titolo
nl.all.EditTitle:Edit title
en.all.EditLink:Edit address
de.all.EditLink:Eintrag bearbeiten
fr.all.EditLink:Éditer l'adresse
it.all.EditLink:Modifica indirizzo
nl.all.EditLink:Bewerk adres
en.all.EditFolder:Rename directory
de.all.EditFolder:Verzeichnis umbenennen
fr.all.EditFolder:Éditer le dossier
it.all.EditFolder:Rinomina cartella
nl.all.EditFolder:Map hernoemen
 
# Default hotlist page names
#
en.all.HotlistHomepage:NetSurf homepage
de.all.HotlistHomepage:NetSurf Homepage
fr.all.HotlistHomepage:Page d'accueil de NetSurf
it.all.HotlistHomepage:Home Page di NetSurf
nl.all.HotlistHomepage:NetSurf thuispagina
en.all.HotlistTestBuild:NetSurf test builds
de.all.HotlistTestBuild:NetSurf Testversionen
fr.all.HotlistTestBuild:Versions test de NetSurf
it.all.HotlistTestBuild:Ultima versione di NetSurf
nl.all.HotlistTestBuild:NetSurf test versie
en.all.HotlistDocumentation:NetSurf documentation
de.all.HotlistDocumentation:NetSurf Dokumentation
fr.all.HotlistDocumentation:Documentation de NetSurf
it.all.HotlistDocumentation:Documentazione di NetSurf
nl.all.HotlistDocumentation:NetSurf documentatie
en.all.HotlistBugTracker:NetSurf bug tracker
de.all.HotlistBugTracker:NetSurf Bug-Tracker
fr.all.HotlistBugTracker:Le traqueur de bogues de NetSurf
it.all.HotlistBugTracker:Bug Tracker di NetSurf
nl.all.HotlistBugTracker:NetSurf bug tracker
en.all.HotlistFeatureRequest:NetSurf feature requests
de.all.HotlistFeatureRequest:NetSurf Verbesserungsvorschläge
fr.all.HotlistFeatureRequest:Demandes de nouvelles fonctions de Netsurf
it.all.HotlistFeatureRequest:Suggerimenti per NetSurf
nl.all.HotlistFeatureRequest:NetSurf feature requests
 
# Default (Amiga) hotlist folder names
#
en.ami.HotlistMenu:Hotlist menu
de.ami.HotlistMenu:Hotlist menu
fr.ami.HotlistMenu:Hotlist menu
it.ami.HotlistMenu:Menu segnalibri
nl.ami.HotlistMenu:Hotlist menu
en.ami.HotlistToolbar:Hotlist toolbar
de.ami.HotlistToolbar:Hotlist toolbar
fr.ami.HotlistToolbar:Hotlist toolbar
it.ami.HotlistToolbar:Barra segnalibri
nl.ami.HotlistToolbar:Hotlist toolbar
 
 
# Global history user interface tokens
# ====================================
#
# This section contains tokens which are used in various parts of
# the global history user interface.
#
 
en.all.GlobalHistory:Global history
de.all.GlobalHistory:History (global)
fr.all.GlobalHistory:Historique globale
it.all.GlobalHistory:Cronologia globale
nl.all.GlobalHistory:Historie (globaal)
en.all.DomainAll:(All domains)
de.all.DomainAll:(All domains)
fr.all.DomainAll:(All domains)
it.all.DomainAll:(Tutti i domini)
nl.all.DomainAll:(All domains)
en.all.DateToday:Today
de.all.DateToday:Heute
fr.all.DateToday:Aujourd'hui
it.all.DateToday:Oggi
nl.all.DateToday:vandaag
en.all.DateYesterday:Yesterday
de.all.DateYesterday:Gestern
fr.all.DateYesterday:Hier
it.all.DateYesterday:Ieri
nl.all.DateYesterday:gisteren
en.all.Date1Week:Last week
de.all.Date1Week:vorige Woche
fr.all.Date1Week:La semaine dernière
it.all.Date1Week:Ultima settimana
nl.all.Date1Week:vorige week
en.all.Date2Week:2 weeks ago
de.all.Date2Week:vor 2 Wochen
fr.all.Date2Week:Il y a 2 semaines
it.all.Date2Week:2 settimane fa
nl.all.Date2Week:2 weken geleden
en.all.Date3Week:3 weeks ago
de.all.Date3Week:vor 3 Wochen
fr.all.Date3Week:Il y a 3 semaines
it.all.Date3Week:3 settimane fa
nl.all.Date3Week:3 weken geleden
en.all.Sunday:Sunday
de.all.Sunday:Sonntag
fr.all.Sunday:Sunday
it.all.Sunday:Domenica
nl.all.Sunday:Sunday
en.all.Monday:Monday
de.all.Monday:Montag
fr.all.Monday:Monday
it.all.Monday:Lunedi
nl.all.Monday:Monday
en.all.Tuesday:Tuesday
de.all.Tuesday:Dienstag
fr.all.Tuesday:Tuesday
it.all.Tuesday:Martedi
nl.all.Tuesday:Tuesday
en.all.Wednesday:Wednesday
de.all.Wednesday:Mittwoch
fr.all.Wednesday:Wednesday
it.all.Wednesday:Mercoledi
nl.all.Wednesday:Wednesday
en.all.Thursday:Thursday
de.all.Thursday:Donnerstag
fr.all.Thursday:Thursday
it.all.Thursday:Giovedi
nl.all.Thursday:Thursday
en.all.Friday:Friday
de.all.Friday:Freitag
fr.all.Friday:Friday
it.all.Friday:Venerdi
nl.all.Friday:Friday
en.all.Saturday:Saturday
de.all.Saturday:Samstag
fr.all.Saturday:Saturday
it.all.Saturday:Sabato
nl.all.Saturday:Saturday
 
 
# Download user interface tokens
# ==============================
#
# This section contains tokens which are used in the download
# window.
#
en.all.Download:%s of %s • %s/s • %s remaining
de.all.Download:%s von %s • %s/s • noch %s
fr.all.Download:%s de %s • %s/s • %s restants
it.all.Download:%s di %s ? %s/s ? %s al termine
nl.all.Download:%s van %s • %s/s • nog %s
en.all.DownloadU:%s of unknown • %s/s • %s total
de.all.DownloadU:%s von unbekannt • %s/s • bisher %s
fr.all.DownloadU:%s sur inconnu • %s/s • %s total
it.all.DownloadU:%s sconosciuto ? %s/s ? %s totale
nl.all.DownloadU:%s van onbekend • %s/s • %s totaal
en.all.Downloaded:%s complete • average %s/s • %s total
de.all.Downloaded:%s komplett • etwa %s/s • gesamt %s
fr.all.Downloaded:%s effectués • moyenne %s/s • %s total
it.all.Downloaded:%s completato ? media di %s/s ? %s totale
nl.all.Downloaded:%s compleet • gemiddeld %s/s • %s totaal
en.all.Unwritten:Writing data to file failed.
de.all.Unwritten:Schreiben der Datei ist fehlgeschlagen.
fr.all.Unwritten:L'écriture de données dans le fichier a échoué.
it.all.Unwritten:Scrittura dei dati sul file fallita.
nl.all.Unwritten:Data naar bestand schrijven ging fout.
en.all.Abort:Abort
de.all.Abort:Abgebrochen
fr.all.Abort:Abort
it.all.Abort:Annulla
nl.all.Abort:Abort
 
# Amiga download window tokens
#
# This section contains tokens which are used in the Amiga
# download window.
#
en.ami.amiDownload:%ld of %ld bytes downloaded
de.ami.amiDownload:%ld von %ld Bytes heruntergeladen
fr.ami.amiDownload:%ld of %ld bytes downloaded
it.ami.amiDownload:%ld di %ld byte scaricati
nl.ami.amiDownload:%ld of %ld bytes downloaded
en.ami.amiDownloadU:%ld bytes downloaded
de.ami.amiDownloadU:%ld Bytes heruntergeladen
fr.ami.amiDownloadU:%ld bytes downloaded
it.ami.amiDownloadU:%ld byte scaricati
nl.ami.amiDownloadU:%ld bytes downloaded
en.ami.amiDownloadComplete:NetSurf: Download completed
de.ami.amiDownloadComplete:NetSurf: Download vollständig
fr.ami.amiDownloadComplete:NetSurf: Download completed
it.ami.amiDownloadComplete:NetSurf: Download completato
nl.ami.amiDownloadComplete:NetSurf: Download completed
 
# Requesters
#
en.ami.amiSizeExisting:Existing file size:
de.ami.amiSizeExisting:Größe der vorhandenen Datei:
fr.ami.amiSizeExisting:Existing file size:
it.ami.amiSizeExisting:Dimensione del file esistente:
nl.ami.amiSizeExisting:Existing file size:
en.ami.amiSizeNew:New file size:
de.ami.amiSizeNew:Größe der neuen Datei:
fr.ami.amiSizeNew:New file size:
it.ami.amiSizeNew:Nuova dimensione del file:
nl.ami.amiSizeNew:New file size:
 
# GTK download window tokens
#
# This section contains tokens which are used in the gtk
# download window.
#
 
en.gtk.gtkSizeInfo:%s of %s
de.gtk.gtkSizeInfo:%s von %s
fr.gtk.gtkSizeInfo:%s de %s
it.gtk.gtkSizeInfo:%s di %s
nl.gtk.gtkSizeInfo:%s of %s
en.gtk.gtkProgressBar:%.0f%% of %u files
de.gtk.gtkProgressBar:%.0f%% von %u Dateien
fr.gtk.gtkProgressBar:%.0f%% de %u fichiers
it.gtk.gtkProgressBar:%. di %% su %u file
nl.gtk.gtkProgressBar:%.0f%% of %u files
en.gtk.gtkProgressBarPulse:Downloading %u files
de.gtk.gtkProgressBarPulse:Lade %u Dateien herunter
fr.gtk.gtkProgressBarPulse:Tèlèchargement %u fichiers
it.gtk.gtkProgressBarPulse:Scaricamento dei file %u
nl.gtk.gtkProgressBarPulse:Downloading %u files
en.gtk.gtkProgressBarPulseSingle:Downloading %u file
de.gtk.gtkProgressBarPulseSingle:Lade %u Datei
fr.gtk.gtkProgressBarPulseSingle:Téléchargement %u fichier
it.gtk.gtkProgressBarPulseSingle:Scaricamento del file %u
nl.gtk.gtkProgressBarPulseSingle:Downloading %u file
 
# Column Headers
#
en.gtk.gtkProgress:Progress
de.gtk.gtkProgress:Fortschritt
fr.gtk.gtkProgress:Progression
it.gtk.gtkProgress:Progressi
nl.gtk.gtkProgress:Progress
en.gtk.gtkDetails:Details
de.gtk.gtkDetails:Details
fr.gtk.gtkDetails:Détails
it.gtk.gtkDetails:Dettagli
nl.gtk.gtkDetails:Details
en.gtk.gtkSpeed:Speed
de.gtk.gtkSpeed:Geschwindigkeit
fr.gtk.gtkSpeed:Vitesse
it.gtk.gtkSpeed:Velocità
nl.gtk.gtkSpeed:Speed
en.gtk.gtkRemaining:Remaining
de.gtk.gtkRemaining:Ãœbrig
fr.gtk.gtkRemaining:Reste
it.gtk.gtkRemaining:Al termine
nl.gtk.gtkRemaining:Remaining
 
# Status Messages
# spaces necessary
#
 
en.gtk.gtkError: Error
de.gtk.gtkError: Fehler
fr.gtk.gtkError: Erreur
it.gtk.gtkError: Errore
nl.gtk.gtkError: Error
en.gtk.gtkComplete: Complete
de.gtk.gtkComplete: Vollständig
fr.gtk.gtkComplete: Terniné
it.gtk.gtkComplete: Completo
nl.gtk.gtkComplete: Complete
en.gtk.gtkCanceled: Canceled
de.gtk.gtkCanceled: Abgebrochen
fr.gtk.gtkCanceled: Annulé
it.gtk.gtkCanceled: Annullato
nl.gtk.gtkCanceled: Canceled
en.gtk.gtkWorking: Working
de.gtk.gtkWorking: Arbeite
fr.gtk.gtkWorking: en cours
it.gtk.gtkWorking: In corso
nl.gtk.gtkWorking: Working
 
# Dialogs
#
en.gtk.gtkQuit:Quit NetSurf?
de.gtk.gtkQuit:NetSurf beenden?
fr.gtk.gtkQuit:Quitter NetSurf?
it.gtk.gtkQuit:Sei sicuro di voler uscire da NetSurf?
nl.gtk.gtkQuit:Quit NetSurf?
en.gtk.gtkDownloadsRunning:There are still downloads running, if you quit now these will be canceled and the files deleted.
de.gtk.gtkDownloadsRunning:Es sind noch Downloads aktiv, beim Beenden werden sie abgebrochen und die Dateien gelöscht.
fr.gtk.gtkDownloadsRunning:Il ya encore des téléchargements en cours, si vous quittez maintenant ceux-ci seront annulés et les fichiers supprimés.
it.gtk.gtkDownloadsRunning:Sono presenti alcuni file in download in attesa di essere completati, chiudendo questa sessione tutti i file incompleti verranno cancellati.
nl.gtk.gtkDownloadsRunning:There are still downloads running, if you quit now these will be canceled and the files deleted.
en.gtk.gtkStartDownload:Download file?
de.gtk.gtkStartDownload:Datei herunterladen?
fr.gtk.gtkStartDownload:Téléchargement du fichier?
it.gtk.gtkStartDownload:Scaricare il file?
nl.gtk.gtkStartDownload:Download file?
en.gtk.gtkOverwrite:A file named "%s" already exists. Do you want to replace it?
de.gtk.gtkOverwrite:Eine Datei mit dem Namen "%s" existiert bereits. Soll sie ersetzt werden?
fr.gtk.gtkOverwrite:Un fichier nommé "%s" existe déja. Voulez-vous le remplacer ?
it.gtk.gtkOverwrite:Il file "%s" è già esistente. Si desidera sovrascriverlo?
nl.gtk.gtkOverwrite:A file named "%s" already exists. Do you want to replace it?
en.gtk.gtkOverwriteTitle:File exists
de.gtk.gtkOverwriteTitle:File exists
fr.gtk.gtkOverwriteTitle:File exists
it.gtk.gtkOverwriteTitle:File già esistente
nl.gtk.gtkOverwriteTitle:File exists
en.gtk.gtkOverwriteInfo:The file already exists in "%s". Replacing it will overwrite its contents.
de.gtk.gtkOverwriteInfo:Die Datei existiert bereits im Verzeichnis "%s". Beim ersetzen wird ihr momentaner Inhalt überschrieben.
fr.gtk.gtkOverwriteInfo:Le fichier existe déja dans "%s". Son remplacement réécrira son contenu.
it.gtk.gtkOverwriteInfo:Il file è già esistente in "%s". Sostituirlo comporterà la sovrascrittura del file.
nl.gtk.gtkOverwriteInfo:The file already exists in "%s". Replacing it will overwrite its contents.
en.gtk.gtkFailed:Download failed
de.gtk.gtkFailed:Download fehlgeschlagen
fr.gtk.gtkFailed:Echec du téléchargement
it.gtk.gtkFailed:Scaricamento fallito
nl.gtk.gtkFailed:Download failed
en.gtk.gtkFileError:File error: %s
de.gtk.gtkFileError:Dateifehler: %s
fr.gtk.gtkFileError:Erreur de fichier: %s
it.gtk.gtkFileError:Errore file: %s
nl.gtk.gtkFileError:File error: %s
en.gtk.gtkInfo:%s from %s is %s in size
de.gtk.gtkInfo:%s von %s ist %s in size
fr.gtk.gtkInfo:La taille de %s de %s est de %s
it.gtk.gtkInfo:%s da %s è %s come dimensione
nl.gtk.gtkInfo:%s from %s is %s in size
en.gtk.gtkSave:Save file as…
de.gtk.gtkSave:Datei speichern unter...
fr.gtk.gtkSave:Enregistrer le fichier sous...
it.gtk.gtkSave:Salva file come...
nl.gtk.gtkSave:Save file as...
en.gtk.gtkSourceSave:Save source
de.gtk.gtkSourceSave:Quelltext speichern
fr.gtk.gtkSourceSave:Enregistrer la Source
it.gtk.gtkSourceSave:Salva sorgente
nl.gtk.gtkSourceSave:Save Source
en.gtk.gtkSourceTabError:Error handling source data
de.gtk.gtkSourceTabError:Fehler beim behandeln der Quelldaten
fr.gtk.gtkSourceTabError:Erreur de manipulation des données source
it.gtk.gtkSourceTabError:Errore di modifica sul sorgente
nl.gtk.gtkSourceTabError:Error handling source data
en.gtk.gtkplainSave:Save plain text
de.gtk.gtkplainSave:Als Text speichern
fr.gtk.gtkplainSave:Enregistrer comme texte
it.gtk.gtkplainSave:Salva come testo
nl.gtk.gtkplainSave:Save as text
en.gtk.gtkcompleteSave:Save webpage complete - select an empty directory
de.gtk.gtkcompleteSave:Save webpage complete - select an empty directory
fr.gtk.gtkcompleteSave:Enregistrer page web complète - sélectioner un dossier vide
it.gtk.gtkcompleteSave:Salva l'intera pagina web - seleziona una directory vuota
nl.gtk.gtkcompleteSave:Save webpage complete - select an empty directory
en.gtk.gtkSaveConfirm:File saved
de.gtk.gtkSaveConfirm:File saved
fr.gtk.gtkSaveConfirm:File saved
it.gtk.gtkSaveConfirm:File salvato
nl.gtk.gtkSaveConfirm:File saved
en.gtk.gtkSaveCancelled:File not saved
de.gtk.gtkSaveCancelled:File not saved
fr.gtk.gtkSaveCancelled:File not saved
it.gtk.gtkSaveCancelled:File non salvato
nl.gtk.gtkSaveCancelled:File not saved
en.gtk.gtkUnknownHost:an unknown host
de.gtk.gtkUnknownHost:ein unbekannter Host
fr.gtk.gtkUnknownHost:un hôte inconnu
it.gtk.gtkUnknownHost:un host sconosciuto
nl.gtk.gtkUnknownHost:an unknown host
en.gtk.gtkUnknownFile:
de.gtk.gtkUnknownFile:
fr.gtk.gtkUnknownFile:
it.gtk.gtkUnknownFile:
nl.gtk.gtkUnknownFile:
en.gtk.gtkUnknownSize:unknown
de.gtk.gtkUnknownSize:unbekannt
fr.gtk.gtkUnknownSize:inconnu
it.gtk.gtkUnknownSize:sconosciuto
nl.gtk.gtkUnknownSize:unknown
 
# gtk Menu / Button labels
#
 
en.gtk.gtkFile:_File
de.gtk.gtkFile:_Datei
fr.gtk.gtkFile:_File
it.gtk.gtkFile:_File
nl.gtk.gtkFile:_File
en.gtk.gtkEdit:_Edit
de.gtk.gtkEdit:_Bearbeiten
fr.gtk.gtkEdit:_Edit
it.gtk.gtkEdit:Mo_difica
nl.gtk.gtkEdit:_Edit
en.gtk.gtkView:_View
de.gtk.gtkView:_Ansicht
fr.gtk.gtkView:_View
it.gtk.gtkView:_Mostra
nl.gtk.gtkView:_View
en.gtk.gtkNavigate:_Navigate
de.gtk.gtkNavigate:_Navigation
fr.gtk.gtkNavigate:_Navigate
it.gtk.gtkNavigate:_Visualizza
nl.gtk.gtkNavigate:_Navigate
en.gtk.gtkTabs:_Tabs
de.gtk.gtkTabs:_Tabs
fr.gtk.gtkTabs:_Tabs
it.gtk.gtkTabs:_Schede
nl.gtk.gtkTabs:_Tabs
en.gtk.gtkHelp:_Help
de.gtk.gtkHelp:_Hilfe
fr.gtk.gtkHelp:_Help
it.gtk.gtkHelp:_Aiuto
nl.gtk.gtkHelp:_Help
 
en.gtk.gtkNewTab:New _Tab
de.gtk.gtkNewTab:Neuer _Tab
fr.gtk.gtkNewTab:Nouvel _Onglet
it.gtk.gtkNewTab:Nuova _scheda
nl.gtk.gtkNewTab:New _Tab
en.gtk.gtkNewTabAccel:<ctrl>t
de.gtk.gtkNewTabAccel:<ctrl>t
fr.gtk.gtkNewTabAccel:<ctrl>t
it.gtk.gtkNewTabAccel:<ctrl>t
nl.gtk.gtkNewTabAccel:<ctrl>t
en.gtk.gtkNewWindow:_New Window
de.gtk.gtkNewWindow:_Neues Fenster
fr.gtk.gtkNewWindow:_Nouvelle Fenêtre
it.gtk.gtkNewWindow:_Nuova finestra
nl.gtk.gtkNewWindow:_New Window
en.gtk.gtkNewWindowAccel:<ctrl>n
de.gtk.gtkNewWindowAccel:<ctrl>n
fr.gtk.gtkNewWindowAccel:<ctrl>n
it.gtk.gtkNewWindowAccel:<ctrl>n
nl.gtk.gtkNewWindowAccel:<ctrl>n
en.gtk.gtkOpenFile:_Open File
de.gtk.gtkOpenFile:Datei öffnen
fr.gtk.gtkOpenFile:_Ouvrir un fichier
it.gtk.gtkOpenFile:_Apri file
nl.gtk.gtkOpenFile:_Open File
en.gtk.gtkOpenFileAccel:<ctrl>o
de.gtk.gtkOpenFileAccel:<ctrl>o
fr.gtk.gtkOpenFileAccel:<ctrl>o
it.gtk.gtkOpenFileAccel:<ctrl>o
nl.gtk.gtkOpenFileAccel:<ctrl>o
en.gtk.gtkCloseWindow:_Close Window
de.gtk.gtkCloseWindow:Fenster schließen
fr.gtk.gtkCloseWindow:_Fermer la fenêtre
it.gtk.gtkCloseWindow:_Chiudi finestra
nl.gtk.gtkCloseWindow:_Close Window
en.gtk.gtkCloseWindowAccel:<ctrl><shift>w
de.gtk.gtkCloseWindowAccel:<ctrl><shift>w
fr.gtk.gtkCloseWindowAccel:<ctrl><shift>w
it.gtk.gtkCloseWindowAccel:<ctrl><shift>w
nl.gtk.gtkCloseWindowAccel:<ctrl><shift>w
en.gtk.gtkSavePage:Save Page…
de.gtk.gtkSavePage:Seite speichern..
fr.gtk.gtkSavePage:Enregistrer la Page..
it.gtk.gtkSavePage:Salva pagina...
nl.gtk.gtkSavePage:Save Page..
en.gtk.gtkSavePageAccel:<ctrl>s
de.gtk.gtkSavePageAccel:<ctrl>s
fr.gtk.gtkSavePageAccel:<ctrl>s
it.gtk.gtkSavePageAccel:<ctrl>s
nl.gtk.gtkSavePageAccel:<ctrl>s
en.gtk.gtkExport:Export
de.gtk.gtkExport:Exportieren
fr.gtk.gtkExport:Exporter
it.gtk.gtkExport:Esporta
nl.gtk.gtkExport:Export
en.gtk.gtkPlainText:Plain Text…
de.gtk.gtkPlainText:Reiner Text..
fr.gtk.gtkPlainText:Texte..
it.gtk.gtkPlainText:Testo normale...
nl.gtk.gtkPlainText:Plain Text..
en.gtk.gtkDrawFile:Drawfile…
de.gtk.gtkDrawFile:Drawfile..
fr.gtk.gtkDrawFile:Dessin..
it.gtk.gtkDrawFile:File Draw...
nl.gtk.gtkDrawFile:Drawfile..
en.gtk.gtkPostScript:PostScript…
de.gtk.gtkPostScript:PostScript..
fr.gtk.gtkPostScript:PostScript..
it.gtk.gtkPostScript:PostScript...
nl.gtk.gtkPostScript:PostScript..
en.gtk.gtkPDF:PDF…
de.gtk.gtkPDF:PDF..
fr.gtk.gtkPDF:PDF..
it.gtk.gtkPDF:PDF...
nl.gtk.gtkPDF:PDF..
en.gtk.gtkPrintPreview:Print Preview…
de.gtk.gtkPrintPreview:Druckvorschau...
fr.gtk.gtkPrintPreview:Aperçu avant impression..
it.gtk.gtkPrintPreview:Anteprima di stampa...
nl.gtk.gtkPrintPreview:Print Preview..
en.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
de.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
fr.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
it.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
nl.gtk.gtkPrintPreviewAccel:<ctrl><shift>p
en.gtk.gtkPrint:Print…
de.gtk.gtkPrint:Drucken...
fr.gtk.gtkPrint:Imprimer..
it.gtk.gtkPrint:Stampa...
nl.gtk.gtkPrint:Print..
en.gtk.gtkPrintAccel:<ctrl>p
de.gtk.gtkPrintAccel:<ctrl>p
fr.gtk.gtkPrintAccel:<ctrl>p
it.gtk.gtkPrintAccel:<ctrl>p
nl.gtk.gtkPrintAccel:<ctrl>p
en.gtk.gtkQuitMenu:_Quit
de.gtk.gtkQuitMenu:Beenden
fr.gtk.gtkQuitMenu:_Quitter
it.gtk.gtkQuitMenu:_Esci
nl.gtk.gtkQuitMenu:_Quit
en.gtk.gtkQuitMenuAccel:<ctrl>q
de.gtk.gtkQuitMenuAccel:<ctrl>q
fr.gtk.gtkQuitMenuAccel:<ctrl>q
it.gtk.gtkQuitMenuAccel:<ctrl>q
nl.gtk.gtkQuitMenuAccel:<ctrl>q
 
en.gtk.gtkCut:Cu_t
de.gtk.gtkCut:Ausschneiden
fr.gtk.gtkCut:Cou_per
it.gtk.gtkCut:Ta_glia
nl.gtk.gtkCut:Cu_t
en.gtk.gtkCutAccel:<ctrl>x
de.gtk.gtkCutAccel:<ctrl>x
fr.gtk.gtkCutAccel:<ctrl>x
it.gtk.gtkCutAccel:<ctrl>x
nl.gtk.gtkCutAccel:<ctrl>x
en.gtk.gtkCopy:_Copy
de.gtk.gtkCopy:Kopieren
fr.gtk.gtkCopy:_Copier
it.gtk.gtkCopy:_Copia
nl.gtk.gtkCopy:_Copy
en.gtk.gtkCopyAccel:<ctrl>c
de.gtk.gtkCopyAccel:<ctrl>c
fr.gtk.gtkCopyAccel:<ctrl>c
it.gtk.gtkCopyAccel:<ctrl>c
nl.gtk.gtkCopyAccel:<ctrl>c
en.gtk.gtkPaste:_Paste
de.gtk.gtkPaste:Einfügen
fr.gtk.gtkPaste:_Coller
it.gtk.gtkPaste:_Incolla
nl.gtk.gtkPaste:_Paste
en.gtk.gtkPasteAccel:<ctrl>v
de.gtk.gtkPasteAccel:<ctrl>v
fr.gtk.gtkPasteAccel:<ctrl>v
it.gtk.gtkPasteAccel:<ctrl>v
nl.gtk.gtkPasteAccel:<ctrl>v
en.gtk.gtkDelete:_Delete
de.gtk.gtkDelete:Löschen
fr.gtk.gtkDelete:_Supprimer
it.gtk.gtkDelete:_Cancella
nl.gtk.gtkDelete:_Delete
en.gtk.gtkSelectAll:Select _All
de.gtk.gtkSelectAll:_Alles auswählen
fr.gtk.gtkSelectAll:_Tout sélectionner
it.gtk.gtkSelectAll:Seleziona _Tutto
nl.gtk.gtkSelectAll:Select _All
en.gtk.gtkSelectAllAccel:<ctrl>a
de.gtk.gtkSelectAllAccel:<ctrl>a
fr.gtk.gtkSelectAllAccel:<ctrl>a
it.gtk.gtkSelectAllAccel:<ctrl>a
nl.gtk.gtkSelectAllAccel:<ctrl>a
en.gtk.gtkFind:_Find…
de.gtk.gtkFind:_Finden..
fr.gtk.gtkFind:_Rechercher..
it.gtk.gtkFind:_Trova...
nl.gtk.gtkFind:_Find..
en.gtk.gtkFindAccel:<ctrl>f
de.gtk.gtkFindAccel:<ctrl>f
fr.gtk.gtkFindAccel:<ctrl>f
it.gtk.gtkFindAccel:<ctrl>f
nl.gtk.gtkFindAccel:<ctrl>f
en.gtk.gtkPreferences:P_references
de.gtk.gtkPreferences:Einstellungen
fr.gtk.gtkPreferences:P_références
it.gtk.gtkPreferences:P_referenze
nl.gtk.gtkPreferences:P_references
 
en.gtk.gtkStop:_Stop
de.gtk.gtkStop:_Stop
fr.gtk.gtkStop:_Stop
it.gtk.gtkStop:_Stop
nl.gtk.gtkStop:_Stop
en.gtk.gtkStopAccel:Escape
de.gtk.gtkStopAccel:Escape
fr.gtk.gtkStopAccel:Escape
it.gtk.gtkStopAccel:Escape
nl.gtk.gtkStopAccel:Escape
en.gtk.gtkReload:_Reload
de.gtk.gtkReload:Neu laden
fr.gtk.gtkReload:_Recharger
it.gtk.gtkReload:_Ricarica
nl.gtk.gtkReload:_Reload
en.gtk.gtkReloadAccel:F5
de.gtk.gtkReloadAccel:F5
fr.gtk.gtkReloadAccel:F5
it.gtk.gtkReloadAccel:F5
nl.gtk.gtkReloadAccel:F5
en.gtk.gtkScaleView:_Scale View
de.gtk.gtkScaleView:Ansicht skalieren
fr.gtk.gtkScaleView:_Zoom
it.gtk.gtkScaleView:_Scala
nl.gtk.gtkScaleView:_Scale View
en.gtk.gtkZoomPlus:Zoom _in
de.gtk.gtkZoomPlus:Here_inzoomen
fr.gtk.gtkZoomPlus:Zoom _+
it.gtk.gtkZoomPlus:_Incrementa zoom
nl.gtk.gtkZoomPlus:Zoom _in
en.gtk.gtkZoomPlusAccel:<ctrl>plus
de.gtk.gtkZoomPlusAccel:<ctrl>plus
fr.gtk.gtkZoomPlusAccel:<ctrl>plus
it.gtk.gtkZoomPlusAccel:<ctrl>più
nl.gtk.gtkZoomPlusAccel:<ctrl>plus
en.gtk.gtkZoomMinus:Zoom _out
de.gtk.gtkZoomMinus:Herausz_oomen
fr.gtk.gtkZoomMinus:Zoom _-
it.gtk.gtkZoomMinus:_Decrementa zoom
nl.gtk.gtkZoomMinus:Zoom _out
en.gtk.gtkZoomMinusAccel:<ctrl>minus
de.gtk.gtkZoomMinusAccel:<ctrl>minus
fr.gtk.gtkZoomMinusAccel:<ctrl>minus
it.gtk.gtkZoomMinusAccel:<ctrl>meno
nl.gtk.gtkZoomMinusAccel:<ctrl>minus
en.gtk.gtkZoomNormal:_Normal size
de.gtk.gtkZoomNormal:_Normalgröße
fr.gtk.gtkZoomNormal:_Taille Normale
it.gtk.gtkZoomNormal:Dimensione _normale
nl.gtk.gtkZoomNormal:_Normal size
en.gtk.gtkZoomNormalAccel:<ctrl>0
de.gtk.gtkZoomNormalAccel:<ctrl>0
fr.gtk.gtkZoomNormalAccel:<ctrl>0
it.gtk.gtkZoomNormalAccel:<ctrl>0
nl.gtk.gtkZoomNormalAccel:<ctrl>0
en.gtk.gtkFullScreen:_Fullscreen
de.gtk.gtkFullScreen:_Vollbild
fr.gtk.gtkFullScreen:_Plein écran
it.gtk.gtkFullScreen:_Tutto schermo
nl.gtk.gtkFullScreen:_Fullscreen
en.gtk.gtkFullScreenAccel:F11
de.gtk.gtkFullScreenAccel:F11
fr.gtk.gtkFullScreenAccel:F11
it.gtk.gtkFullScreenAccel:F11
nl.gtk.gtkFullScreenAccel:F11
en.gtk.gtkViewSource:View S_ource
de.gtk.gtkViewSource: Q_uelltext Anzeigen
fr.gtk.gtkViewSource:Voir la S_ource
it.gtk.gtkViewSource:Mostra s_orgente
nl.gtk.gtkViewSource:View S_ource
en.gtk.gtkViewSourceAccel:F8
de.gtk.gtkViewSourceAccel:F8
fr.gtk.gtkViewSourceAccel:F8
it.gtk.gtkViewSourceAccel:F8
nl.gtk.gtkViewSourceAccel:F8
en.gtk.gtkImages:_Images
de.gtk.gtkImages:B_ilder
fr.gtk.gtkImages:_Images
it.gtk.gtkImages:_Immagini
nl.gtk.gtkImages:_Images
en.gtk.gtkForegroundImages:_Foreground Images
de.gtk.gtkForegroundImages:_Vordergrundbilder
fr.gtk.gtkForegroundImages:_Images de premier plan
it.gtk.gtkForegroundImages:Immagini in _primo piano
nl.gtk.gtkForegroundImages:_Foreground Images
en.gtk.gtkBackgroundImages:_Background Images
de.gtk.gtkBackgroundImages:_Hintergrundbilder
fr.gtk.gtkBackgroundImages:_Images d'arrière plan
it.gtk.gtkBackgroundImages:Immagini in _sottofondo
nl.gtk.gtkBackgroundImages:_Background Images
en.gtk.gtkToolbars:_Toolbars
de.gtk.gtkToolbars:_Werkzeugleisten
fr.gtk.gtkToolbars:_Barre d'outils
it.gtk.gtkToolbars:_Barre strumenti
nl.gtk.gtkToolbars:_Toolbars
en.gtk.gtkMenuBar:_Menu Bar
de.gtk.gtkMenuBar:_Menüleiste
fr.gtk.gtkMenuBar:_Barre de menu
it.gtk.gtkMenuBar:Barra _menu
nl.gtk.gtkMenuBar:_Menu Bar
en.gtk.gtkToolBar:_Button Bar
de.gtk.gtkToolBar:_Buttonleiste
fr.gtk.gtkToolBar:_Barre de boutons
it.gtk.gtkToolBar:Barra p_ulsanti
nl.gtk.gtkToolBar:_Button Bar
en.gtk.gtkStatusBar:_Status Bar
de.gtk.gtkStatusBar:_Statusleiste
fr.gtk.gtkStatusBar:_Bar de statut
it.gtk.gtkStatusBar:Barra di s_tato
nl.gtk.gtkStatusBar:_Status Bar
en.gtk.gtkDownloads:_Downloads
de.gtk.gtkDownloads:_Downloads
fr.gtk.gtkDownloads:_Téléchargements
it.gtk.gtkDownloads:_Trasferimenti
nl.gtk.gtkDownloads:_Downloads
en.gtk.gtkDownloadsAccel:<ctrl>d
de.gtk.gtkDownloadsAccel:<ctrl>d
fr.gtk.gtkDownloadsAccel:<ctrl>d
it.gtk.gtkDownloadsAccel:<ctrl>d
nl.gtk.gtkDownloadsAccel:<ctrl>d
en.gtk.gtkSaveWindowSize:S_ave Window Size
de.gtk.gtkSaveWindowSize:Fenstergröße _speichern
fr.gtk.gtkSaveWindowSize:E_nregistrer la taille de la fenêtre
it.gtk.gtkSaveWindowSize:S_alva dimensione finestra
nl.gtk.gtkSaveWindowSize:S_ave Window Size
en.gtk.gtkDebugging:De_bugging
de.gtk.gtkDebugging:De_bugging
fr.gtk.gtkDebugging:D_ébogage
it.gtk.gtkDebugging:De_bugging
nl.gtk.gtkDebugging:De_bugging
en.gtk.gtkToggleDebugging:T_oggle debug rendering
de.gtk.gtkToggleDebugging:T_oggle debug rendering
fr.gtk.gtkToggleDebugging:Activer le débogage
it.gtk.gtkToggleDebugging:In_verti debug del rendering
nl.gtk.gtkToggleDebugging:T_oggle debug rendering
en.gtk.gtkSaveBoxTree:_Save box tree
de.gtk.gtkSaveBoxTree:_Save box tree
fr.gtk.gtkSaveBoxTree:_Save box tree
it.gtk.gtkSaveBoxTree:_Salva albero Box
nl.gtk.gtkSaveBoxTree:_Save box tree
en.gtk.gtkSaveDomTree:Save DOM tree
de.gtk.gtkSaveDomTree:Save DOM tree
fr.gtk.gtkSaveDomTree:Save DOM tree
it.gtk.gtkSaveDomTree:Salva albero DOM
nl.gtk.gtkSaveDomTree:Save DOM tree
 
en.gtk.gtkBack:_Back
de.gtk.gtkBack:_Zurück
fr.gtk.gtkBack:_Précédent
it.gtk.gtkBack:_Indietro
nl.gtk.gtkBack:_Back
en.gtk.gtkBackAccel:<alt>Left
de.gtk.gtkBackAccel:<alt>Left
fr.gtk.gtkBackAccel:<alt>Left
it.gtk.gtkBackAccel:<alt>Sinistra
nl.gtk.gtkBackAccel:<alt>Left
en.gtk.gtkForward:_Forward
de.gtk.gtkForward:_Vorwärts
fr.gtk.gtkForward:_Suivant
it.gtk.gtkForward:_Avanti
nl.gtk.gtkForward:_Forward
en.gtk.gtkForwardAccel:<alt>Right
de.gtk.gtkForwardAccel:<alt>Right
fr.gtk.gtkForwardAccel:<alt>Right
it.gtk.gtkForwardAccel:<alt>Destra
nl.gtk.gtkForwardAccel:<alt>Right
en.gtk.gtkHome:_Home
de.gtk.gtkHome:_Startseite
fr.gtk.gtkHome:_Accueil
it.gtk.gtkHome:_Home
nl.gtk.gtkHome:_Home
en.gtk.gtkHomeAccel:<alt>Down
de.gtk.gtkHomeAccel:<alt>Down
fr.gtk.gtkHomeAccel:<alt>Down
it.gtk.gtkHomeAccel:<alt>Giù
nl.gtk.gtkHomeAccel:<alt>Down
en.gtk.gtkLocalHistory:_Local History…
de.gtk.gtkLocalHistory:_Lokaler Verlauf
fr.gtk.gtkLocalHistory:_Historique local
it.gtk.gtkLocalHistory:Cronologia _locale
nl.gtk.gtkLocalHistory:_Local History
en.gtk.gtkLocalHistoryAccel:<ctrl>h
de.gtk.gtkLocalHistoryAccel:<ctrl>h
fr.gtk.gtkLocalHistoryAccel:<ctrl>h
it.gtk.gtkLocalHistoryAccel:<ctrl>h
nl.gtk.gtkLocalHistoryAccel:<ctrl>h
en.gtk.gtkGlobalHistory:_Global History…
de.gtk.gtkGlobalHistory:_Globaler Verlauf
fr.gtk.gtkGlobalHistory:_Historique global
it.gtk.gtkGlobalHistory:Cronologia _globale
nl.gtk.gtkGlobalHistory:_Global History
en.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
de.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
fr.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
it.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
nl.gtk.gtkGlobalHistoryAccel:<ctrl><shift>h
en.gtk.gtkAddBookMarks:_Add to Bookmarks…
de.gtk.gtkAddBookMarks:_Lesezeichen hinzufügen..
fr.gtk.gtkAddBookMarks:_Ajouter un marque-page..
it.gtk.gtkAddBookMarks:_Aggiungi ai segnalibri...
nl.gtk.gtkAddBookMarks:_Add to Bookmarks..
en.gtk.gtkShowBookMarks:_Show Bookmarks…
de.gtk.gtkShowBookMarks:Le_sezeichen anzeigen..
fr.gtk.gtkShowBookMarks:_Montrer les marques-pages..
it.gtk.gtkShowBookMarks:_Mostra segnalibri...
nl.gtk.gtkShowBookMarks:_Show Bookmarks..
en.gtk.gtkShowBookMarksAccel:F6
de.gtk.gtkShowBookMarksAccel:F6
fr.gtk.gtkShowBookMarksAccel:F6
it.gtk.gtkShowBookMarksAccel:F6
nl.gtk.gtkShowBookMarksAccel:F6
en.gtk.gtkShowCookies:Show _Cookies…
de.gtk.gtkShowCookies:Show _Cookies..
fr.gtk.gtkShowCookies:Show _Cookies…
it.gtk.gtkShowCookies:Mostra _cookie...
nl.gtk.gtkShowCookies:Show _Cookies…
en.gtk.gtkShowCookiesAccel:F9
de.gtk.gtkShowCookiesAccel:F9
fr.gtk.gtkShowCookiesAccel:F9
it.gtk.gtkShowCookiesAccel:F9
nl.gtk.gtkShowCookiesAccel:F9
en.gtk.gtkOpenLocation:_Open Location…
de.gtk.gtkOpenLocation:_Ort öffnen..
fr.gtk.gtkOpenLocation:_Ouvrir un site..
it.gtk.gtkOpenLocation:_Apri indirizzo...
nl.gtk.gtkOpenLocation:_Open Location..
en.gtk.gtkOpenLocationAccel:<ctrl>l
de.gtk.gtkOpenLocationAccel:<ctrl>l
fr.gtk.gtkOpenLocationAccel:<ctrl>l
it.gtk.gtkOpenLocationAccel:<ctrl>l
nl.gtk.gtkOpenLocationAccel:<ctrl>l
 
en.gtk.gtkNextTab:_Next tab
de.gtk.gtkNextTab:_Nächster Tab
fr.gtk.gtkNextTab:_Onglet précédent
it.gtk.gtkNextTab:Scheda _successiva
nl.gtk.gtkNextTab:_Next tab
en.gtk.gtkNextTabAccel:<ctrl>Right
de.gtk.gtkNextTabAccel:<ctrl>Right
fr.gtk.gtkNextTabAccel:<ctrl>Right
it.gtk.gtkNextTabAccel:<ctrl>Destra
nl.gtk.gtkNextTabAccel:<ctrl>Right
en.gtk.gtkPrevTab:_Previous tab
de.gtk.gtkPrevTab:_Vorheriger tab
fr.gtk.gtkPrevTab:_Onglet suvant
it.gtk.gtkPrevTab:Scheda _precedente
nl.gtk.gtkPrevTab:_Previous tab
en.gtk.gtkPrevTabAccel:<ctrl>Left
de.gtk.gtkPrevTabAccel:<ctrl>Left
fr.gtk.gtkPrevTabAccel:<ctrl>Left
it.gtk.gtkPrevTabAccel:<ctrl>Sinistra
nl.gtk.gtkPrevTabAccel:<ctrl>Left
en.gtk.gtkCloseTab:_Close tab
de.gtk.gtkCloseTab:Tab s_chliessen
fr.gtk.gtkCloseTab:_Fermer l'onglet
it.gtk.gtkCloseTab:_Chiudi scheda
nl.gtk.gtkCloseTab:_Close tab
en.gtk.gtkCloseTabAccel:<ctrl>w
de.gtk.gtkCloseTabAccel:<ctrl>w
fr.gtk.gtkCloseTabAccel:<ctrl>w
it.gtk.gtkCloseTabAccel:<ctrl>w
nl.gtk.gtkCloseTabAccel:<ctrl>w
 
en.gtk.gtkContents:_Contents…
de.gtk.gtkContents:_Inhalt
fr.gtk.gtkContents:_Contenus
it.gtk.gtkContents:_Contenuti
nl.gtk.gtkContents:_Contents
en.gtk.gtkGuide:User _guide…
de.gtk.gtkGuide:H_andbuch
fr.gtk.gtkGuide:Guide _Utilisateur
it.gtk.gtkGuide:_Guida in linea
nl.gtk.gtkGuide:User _guide
en.gtk.gtkUserInformation:User _information…
de.gtk.gtkUserInformation:Benutzer_information
fr.gtk.gtkUserInformation:_Information Utilisateur
it.gtk.gtkUserInformation:Informazioni _utente
nl.gtk.gtkUserInformation:User _information
en.gtk.gtkAbout:_About…
de.gtk.gtkAbout:Ü_ber
fr.gtk.gtkAbout:_A propos...
it.gtk.gtkAbout:_Informazioni
nl.gtk.gtkAbout:_About
 
en.gtk.gtkCustomize:Customise…
de.gtk.gtkCustomize:Customise..
fr.gtk.gtkCustomize:Customise…
it.gtk.gtkCustomize:Personalizza...
nl.gtk.gtkCustomize:Customise…
en.gtk.gtkOpentab:Open Link in _New Tab
de.gtk.gtkOpentab:Link in _neuem Tab öffnen
fr.gtk.gtkOpentab:Open Link in _New Tab
it.gtk.gtkOpentab:Apri in una _nuova scheda
nl.gtk.gtkOpentab:Open Link in _New Tab
en.gtk.gtkOpenwin:Open Link in New Window
de.gtk.gtkOpenwin:Link in neuem Fenster öffnen
fr.gtk.gtkOpenwin:Open Link in New Window
it.gtk.gtkOpenwin:Apri in una nuova finestra
nl.gtk.gtkOpenwin:Open Link in New Window
en.gtk.gtkSavelink:Save Link
de.gtk.gtkSavelink:Link speichern..
fr.gtk.gtkSavelink:Save Link
it.gtk.gtkSavelink:Salva Link
nl.gtk.gtkSavelink:Save Link
 
en.gtk.gtkToolBarTitle:Toolbar custom button store
de.gtk.gtkToolBarTitle:Benutzerdefinierter Ort für Toolbar-Icons
fr.gtk.gtkToolBarTitle:Personaliser la barre d'outils
it.gtk.gtkToolBarTitle:Pulsanti della barra strumenti
nl.gtk.gtkToolBarTitle:Toolbar custom button store
en.gtk.gtkAddThemeTitle:Select folder containing theme images
de.gtk.gtkAddThemeTitle:Ordner mit Themenbildern auswählen
fr.gtk.gtkAddThemeTitle:Sélectionner le dossier contenant des images de thèmes
it.gtk.gtkAddThemeTitle:Seleziona una cartella contenente le immagini del tema in questione
nl.gtk.gtkAddThemeTitle:Select folder containing theme images
 
en.gtk.gtkThemeFolderInstructions:To Install a theme, create a directory full of appropriately-named images as a subdirectory of gtk/res/themes/
de.gtk.gtkThemeFolderInstructions:Erstellen sie ein Verzeichnis mit korrekt benannten Bildern als Unterverzeichnis von gtk/res/themes um ein Thema zu installieren
fr.gtk.gtkThemeFolderInstructions:Pour installer un thème, créer un dossier d'images avec un nom approprié comme sous-dossier de gtk/res/themes/
it.gtk.gtkThemeFolderInstructions:Per installare un nuovo tema crea una directory con delle immagini appropriate ed inseriscile come sotto-directory di gtk/res/themes/
nl.gtk.gtkThemeFolderInstructions:To Install a theme, create a directory full of appropriately-named images as a subdirectory of gtk/res/themes/
en.gtk.gtkThemeFolderSub:Select a subdirectory of the themes folder
de.gtk.gtkThemeFolderSub:Unterverzeichnis mit Themenbildern wählen
fr.gtk.gtkThemeFolderSub:Sélectionner un sous-dossier de thème
it.gtk.gtkThemeFolderSub:Seleziona una sotto-directory della cartella temi
nl.gtk.gtkThemeFolderSub:Select a subdirectory of the themes folder
en.gtk.gtkThemeDup:Theme is already included
de.gtk.gtkThemeDup:Das Thema ist bereits hinzugefügt worden
fr.gtk.gtkThemeDup:Le thème est déjà inclus
it.gtk.gtkThemeDup:Il tema è già incluso
nl.gtk.gtkThemeDup:Theme is already included
en.gtk.gtkThemeAdd:Theme added successfully
de.gtk.gtkThemeAdd:Thema erfolgreich hinzugefügt
fr.gtk.gtkThemeAdd:Le thème a été ajouté avec succes
it.gtk.gtkThemeAdd:Il tema è stato aggiunto con successo
nl.gtk.gtkThemeAdd:Theme added successfully
 
# Printing user interface tokens
# ==============================
#
# This section contains tokens which are used in the printing
# dialog box.
#
 
en.all.PrintSheetFilled:sheet is filled
de.all.PrintSheetFilled:Druckseite
fr.all.PrintSheetFilled:feuille remplie
it.all.PrintSheetFilled:Il foglio stampato è pieno
nl.all.PrintSheetFilled:pagina
en.all.PrintSheetsFilled:sheets are filled
de.all.PrintSheetsFilled:Druckseiten
fr.all.PrintSheetsFilled:feuilles remplies
it.all.PrintSheetsFilled:I fogli stampati sono pieni
nl.all.PrintSheetsFilled:pagina's
en.all.Printer:Printer
de.all.Printer:Drucker
fr.all.Printer:Printer
it.all.Printer:Stampante
nl.all.Printer:Printer
en.all.Copies:Copies
de.all.Copies:Kopien
fr.all.Copies:Copies
it.all.Copies:Copie
nl.all.Copies:Copies
en.all.Printing:Printing page
de.all.Printing:Drucke Seite
fr.all.Printing:Printing page
it.all.Printing:Stampa della pagina
nl.all.Printing:Printing page
 
 
# Find text user interface tokens
# ===============================
#
# This section contains tokens which are used in the find text
# dialog box.
#
en.all.NotFound:Not found
de.all.NotFound:nichts
fr.all.NotFound:Non trouvé
it.all.NotFound:Non trovato
nl.all.NotFound:Niet gevonden
en.all.Next:Next
de.all.Next:Nächster
fr.all.Next:Next
it.all.Next:Successivo
nl.all.Next:Next
en.all.Prev:Previous
de.all.Prev:Vorheriger
fr.all.Prev:Previous
it.all.Prev:Precedente
nl.all.Prev:Previous
en.all.ShowAll:Show All
de.all.ShowAll:Alle zeigen
fr.all.ShowAll:Show All
it.all.ShowAll:Mostra Tutto
nl.all.ShowAll:Show All
en.all.CaseSens:Case Sensitive
de.all.CaseSens:Groß-/Kleinschreibung
fr.all.CaseSens:Case Sensitive
it.all.CaseSens:Maiuscole/Minuscole
nl.all.CaseSens:Case Sensitive
 
 
# 401 login user interface tokens
# ===============================
#
# This section contains tokens which are used in the 401 login
# (authentication) dialog box.
#
en.all.Host:Host
de.all.Host:Host
fr.all.Host:Host
it.all.Host:Host
nl.all.Host:Host
en.all.Realm:Realm
de.all.Realm:Realm
fr.all.Realm:Realm
it.all.Realm:Tipo
nl.all.Realm:Realm
en.all.Username:Username
de.all.Username:Benutzername
fr.all.Username:Username
it.all.Username:Nome Utente
nl.all.Username:Username
en.all.Password:Password
de.all.Password:Passwort
fr.all.Password:Password
it.all.Password:Password
nl.all.Password:Password
en.all.Login:Login
de.all.Login:Login
fr.all.Login:Login
it.all.Login:Login
nl.all.Login:Login
en.all.Cancel:Cancel
de.all.Cancel:Abbruch
fr.all.Cancel:Cancel
it.all.Cancel:Annulla
nl.all.Cancel:Cancel
 
 
# SSL certificate verification
# ============================
#
# This section contains tokens which are used in the
# SSL certificate verification dialog box.
#
en.all.SSLCerts:SSL certificates
de.all.SSLCerts:SSL Zertifikat
fr.all.SSLCerts:SSL certificates
it.all.SSLCerts:Certificati SSL
nl.all.SSLCerts:SSL certificates
en.all.SSLError:NetSurf failed to verify the authenticity of an SSL certificate. Please verify the details presented below.
de.all.SSLError:NetSurf konnte ein SSL Zertifikat nicht prüfen. Bitte die Details unten beachten.
fr.all.SSLError:NetSurf failed to verify the authenticity of an SSL certificate. Please verify the details presented below.
it.all.SSLError:NetSurf non è stato in grado di verificare l'autenticità di questo certificato SSL, per favore verifica i dettagli presenti di seguito.
nl.all.SSLError:NetSurf failed to verify the authenticity of an SSL certificate. Please verify the details presented below.
en.all.SSL_Certificate_Subject:Subject: %s
de.all.SSL_Certificate_Subject:Subject: %s
fr.all.SSL_Certificate_Subject:Subject: %s
it.all.SSL_Certificate_Subject:Oggetto: %s
nl.all.SSL_Certificate_Subject:Subject: %s
en.all.SSL_Certificate_Issuer:Issuer: %s
de.all.SSL_Certificate_Issuer:Issuer: %s
fr.all.SSL_Certificate_Issuer:Issuer: %s
it.all.SSL_Certificate_Issuer:Emittente: %s
nl.all.SSL_Certificate_Issuer:Issuer: %s
en.all.SSL_Certificate_Version:Version: %ld
de.all.SSL_Certificate_Version:Version: %ld
fr.all.SSL_Certificate_Version:Version: %ld
it.all.SSL_Certificate_Version:Versione: %ld
nl.all.SSL_Certificate_Version:Version: %ld
en.all.SSL_Certificate_ValidFrom:Valid from: %s
de.all.SSL_Certificate_ValidFrom:Valid from: %s
fr.all.SSL_Certificate_ValidFrom:Valid from: %s
it.all.SSL_Certificate_ValidFrom:Valido da: %s
nl.all.SSL_Certificate_ValidFrom:Valid from: %s
en.all.SSL_Certificate_ValidTo:Valid until: %s
de.all.SSL_Certificate_ValidTo:Valid until: %s
fr.all.SSL_Certificate_ValidTo:Valid until: %s
it.all.SSL_Certificate_ValidTo:Valido fino a: %s
nl.all.SSL_Certificate_ValidTo:Valid until: %s
en.all.SSL_Certificate_Type:Type: %i
de.all.SSL_Certificate_Type:Type: %i
fr.all.SSL_Certificate_Type:Type: %i
it.all.SSL_Certificate_Type:Tipo: %i
nl.all.SSL_Certificate_Type:Type: %i
en.all.SSL_Certificate_Serial:Serial: %ld
de.all.SSL_Certificate_Serial:Serial: %ld
fr.all.SSL_Certificate_Serial:Serial: %ld
it.all.SSL_Certificate_Serial:Seriale: %ld
nl.all.SSL_Certificate_Serial:Serial: %ld
en.all.SSL_Certificate_Accept:Accept
de.all.SSL_Certificate_Accept:Accept
fr.all.SSL_Certificate_Accept:Accept
it.all.SSL_Certificate_Accept:Accetta
nl.all.SSL_Certificate_Accept:Accept
en.all.SSL_Certificate_Reject:Reject
de.all.SSL_Certificate_Reject:Reject
fr.all.SSL_Certificate_Reject:Reject
it.all.SSL_Certificate_Reject:Rifiuta
nl.all.SSL_Certificate_Reject:Reject
 
 
# Content
# =======
#
# This section contains tokens used by contents
#
 
# Forms
#
en.all.Form_Submit:Submit
de.all.Form_Submit:Ãœbertragen
fr.all.Form_Submit:Soumettre
it.all.Form_Submit:Invia
nl.all.Form_Submit:Versturen
en.all.Form_Reset:Reset
de.all.Form_Reset:Zurücksetzen
fr.all.Form_Reset:Effacer
it.all.Form_Reset:Resetta
nl.all.Form_Reset:Legen
en.all.Form_None:
de.all.Form_None:
fr.all.Form_None:
it.all.Form_None:
nl.all.Form_None:
en.all.Form_Many:(Many)
de.all.Form_Many:(Viele)
fr.all.Form_Many:(Plusieurs)
it.all.Form_Many:(Molti)
nl.all.Form_Many:(Veel)
en.all.Form_Drop:Drop file here
de.all.Form_Drop:Datei hier hinziehen
fr.all.Form_Drop:Déposer les fichiers ici
it.all.Form_Drop:Inserisci un file qui
nl.all.Form_Drop:Plaats bestand hier
en.all.FormSelect:Click to choose a form item
de.all.FormSelect:Anklicken öffnet Auswahlmenü
fr.all.FormSelect:Cliquer pour choisir un item de formulaire
it.all.FormSelect:Clicca per scegliere un oggetto del modulo
nl.all.FormSelect:Klikken selekteert een form item
en.all.FormCheckbox:Click to check this option
de.all.FormCheckbox:Anklicken um die Option an/abzuschalten
fr.all.FormCheckbox:Cliquer pour cocher cette option
it.all.FormCheckbox:Clicca per scegliere questa opzione
nl.all.FormCheckbox:Klikken selekteert deze optie
en.all.FormRadio:Click to choose this option
de.all.FormRadio:Anklicken wählt diese Option
fr.all.FormRadio:Cliquer pour choisir cette option
it.all.FormRadio:Clicca per selezionare questa opzione
nl.all.FormRadio:Klikken kiest deze optie
en.all.FormSubmit:Send form to %s
de.all.FormSubmit:Daten übertragen an %s
fr.all.FormSubmit:Envoyer le formulaire à %s
it.all.FormSubmit:Invia il risultato del modulo a: %s
nl.all.FormSubmit:Verstuur data naar %s
en.all.FormBadSubmit:Warning: form can not be submitted
de.all.FormBadSubmit:Achtung: Daten können nicht gesendet werden
fr.all.FormBadSubmit:Alerte: le formulaire n'a pas pu être envoyé
it.all.FormBadSubmit:Attenzione: Il modulo non può essere inviato
nl.all.FormBadSubmit:Waarschuwing: data kan niet verzonden worden
en.all.FormButton:Warning: button can not be activated
de.all.FormButton:Achtung: Schaltknopf kann nicht aktiviert werden
fr.all.FormButton:Warning: button can not be activated
it.all.FormButton:Attenzione: il pulsante non può essere attivato
nl.all.FormButton:Warning: button can not be activated
en.all.FormTextarea:Click to edit the text
de.all.FormTextarea:Anklicken zum Editieren
fr.all.FormTextarea:Cliquer pour éditer ce texte
it.all.FormTextarea:Clicca per editare il testo
nl.all.FormTextarea:Klikken om tekst te bewerken
en.all.FormTextbox:Click to edit this field
de.all.FormTextbox:Anklicken zum Bearbeiten des Feldes
fr.all.FormTextbox:Cliquer pour éditer ce champ
it.all.FormTextbox:Clicca per editare il campo di testo
nl.all.FormTextbox:Klikken om dit veld te bewerken
en.all.FormReset:Reset form (not implemented)
de.all.FormReset:Zurücksetzen (nicht implementiert)
fr.all.FormReset:RAZ du formulaire (non implémenté)
it.all.FormReset:Resetta il modulo
nl.all.FormReset:Reset form (not implemented)
en.all.FormFile:Drop a file here to upload it
de.all.FormFile:Zum Upload Datei hierhin ziehen und fallenlassen
fr.all.FormFile:Déposer un fichier ici pour le télésauver
it.all.FormFile:Inserisci un file da inviare qui
nl.all.FormFile:Plaats het bestand hier voor uploaden
en.all.SelectMenu:Select
de.all.SelectMenu:Auswahl
fr.all.SelectMenu:Sélection
it.all.SelectMenu:Seleziona
nl.all.SelectMenu:Select
 
# Content titles
#
en.all.DrawTitle:%s (Draw image %lux%lu pixels)
de.all.DrawTitle:%s (Draw Bild %lux%lu pixels)
fr.all.DrawTitle:%s (Image Draw %lux%lu pixels)
it.all.DrawTitle:%s (Immagine Draw %lux%lu pixel)
nl.all.DrawTitle:%s (Draw image %lux%lu pixels)
en.all.GIFTitle:%s (GIF image %lux%lu pixels)
de.all.GIFTitle:%s (GIF Bild %lux%lu pixels)
fr.all.GIFTitle:%s (Image GIF %lux%lu pixels)
it.all.GIFTitle:%s (Immagine GIF %lux%lu pixel)
nl.all.GIFTitle:%s (GIF image %lux%lu pixels)
en.all.BMPTitle:%s (BMP image %lux%lu pixels)
de.all.BMPTitle:%s (BMP Bild %lux%lu pixels)
fr.all.BMPTitle:%s (Image BMP %lux%lu pixels)
it.all.BMPTitle:%s (Immagine BMP %lux%lu pixel)
nl.all.BMPTitle:%s (BMP image %lux%lu pixels)
en.all.ICOTitle:%s (ICO image %lux%lu pixels)
de.all.ICOTitle:%s (ICO Bild %lux%lu pixels)
fr.all.ICOTitle:%s (Image BMP %lux%lu pixels)
it.all.ICOTitle:%s (Immagine ICO %lux%lu pixel)
nl.all.ICOTitle:%s (ICO image %lux%lu pixels)
en.all.JPEGTitle:%s (JPEG image %lux%lu pixels)
de.all.JPEGTitle:%s (JPEG Bild %lux%lu pixels)
fr.all.JPEGTitle:%s (Image JPEG %lux%lu pixels)
it.all.JPEGTitle:%s (Immagine JPEG %lux%lu pixel)
nl.all.JPEGTitle:%s (JPEG image %lux%lu pixels)
en.all.PNGTitle:%s (PNG image %lux%lu pixels)
de.all.PNGTitle:%s (PNG Bild %lux%lu pixels)
fr.all.PNGTitle:%s (Image PNG %lux%lu pixels)
it.all.PNGTitle:%s (Immagine PNG %lux%lu pixel)
nl.all.PNGTitle:%s (PNG image %lux%lu pixels)
en.all.JNGTitle:%s (JNG image %lux%lu pixels)
de.all.JNGTitle:%s (JNG Bild %lux%lu pixels)
fr.all.JNGTitle:%s (Image JNG %lux%lu pixels)
it.all.JNGTitle:%s (Immagine JNG %lux%lu pixel)
nl.all.JNGTitle:%s (JNG image %lux%lu pixels)
en.all.MNGTitle:%s (MNG image %lux%lu pixels)
de.all.MNGTitle:%s (MNG Bild %lux%lu pixels)
fr.all.MNGTitle:%s (Image MNG %lux%lu pixels)
it.all.MNGTitle:%s (Immagine MNG %lux%lu pixel)
nl.all.MNGTitle:%s (MNG image %lux%lu pixels)
en.all.WebPTitle:%s (WebP image %lux%lu pixels)
de.all.WebPTitle:%s (WebP Bild %lux%lu pixels)
fr.all.WebPTitle:%s (Image WebP %lux%lu pixels)
it.all.WebPTitle:%s (Immagine WebP %lux%lu pixel)
nl.all.WebPTitle:%s (WebP image %lux%lu pixels)
en.all.SpriteTitle:%s (Sprite image %lux%lu pixels)
de.all.SpriteTitle:%s (Sprite Bild %lux%lu pixels)
fr.all.SpriteTitle:%s (Image Sprite %lux%lu pixels)
it.all.SpriteTitle:%s (Immagine Sprite %lux%lu pixel)
nl.all.SpriteTitle:%s (Sprite image %lux%lu pixels)
en.all.ArtWorksTitle:%s (ArtWorks image %lux%lu pixels)
de.all.ArtWorksTitle:%s (ArtWorks Bild %lux%lu pixels)
fr.all.ArtWorksTitle:%s (Image ArtWorks %lux%lu pixels)
it.all.ArtWorksTitle:%s (Immagine ArtWorks %lux%lu pixel)
nl.all.ArtWorksTitle:%s (ArtWorks image %lux%lu pixels)
en.ami.DataTypesTitle:%s (%s image %lux%lu pixels)
de.ami.DataTypesTitle:%s (%s Bild %lux%lu pixels)
fr.ami.DataTypesTitle:%s (Image %s %lux%lu pixels)
it.ami.DataTypesTitle:%s (Immagine %s %lux%lu pixel)
nl.ami.DataTypesTitle:%s (%s image %lux%lu pixels)
 
# HTML page character set
#
en.all.Encoding0:from HTTP headers
de.all.Encoding0:aus HTTP Kopfzeilen
fr.all.Encoding0:dans les entêtes HTTP
it.all.Encoding0:da intestazioni HTTP
nl.all.Encoding0:from HTTP headers
en.all.Encoding1:detected
de.all.Encoding1:ermittelt
fr.all.Encoding1:détecté
it.all.Encoding1:rilevato
nl.all.Encoding1:detected
en.all.Encoding2:from <meta>
de.all.Encoding2:aus <meta>
fr.all.Encoding2:de <meta>
it.all.Encoding2:da <meta>
nl.all.Encoding2:from <meta>
en.all.EncodingUnk:Unknown
de.all.EncodingUnk:Unbekannt
fr.all.EncodingUnk:Inconnu
it.all.EncodingUnk:Sconosciuto
nl.all.EncodingUnk:Unknown
 
# Directory browser
#
en.all.FileIndex:Index of %s
de.all.FileIndex:Inhalt von %s
fr.all.FileIndex:Index of %s
it.all.FileIndex:Indice di %s
nl.all.FileIndex:Index of %s
en.all.FileParent:^ Up to parent directory
de.all.FileParent:^ Eine Ebene höher
fr.all.FileParent:^ Up to parent directory
it.all.FileParent:^ Livello superiore
nl.all.FileParent:^ Up to parent directory
en.all.FileDirectory:Directory
de.all.FileDirectory:Verzeichnis
fr.all.FileDirectory:Directory
it.all.FileDirectory:Directory
nl.all.FileDirectory:Directory
en.all.FileName:Name
de.all.FileName:Name
fr.all.FileName:Name
it.all.FileName:Nome
nl.all.FileName:Name
en.all.FileSize:Size
de.all.FileSize:Größe
fr.all.FileSize:Size
it.all.FileSize:Dimensione
nl.all.FileSize:Size
en.all.FileDate:Date
de.all.FileDate:Datum
fr.all.FileDate:Date
it.all.FileDate:Data
nl.all.FileDate:Date
en.all.FileTime:Time
de.all.FileTime:Zeit
fr.all.FileTime:Time
it.all.FileTime:Ora
nl.all.FileTime:Time
en.all.FileType:Type
de.all.FileType:Typ
fr.all.FileType:Type
it.all.FileType:Tipo
nl.all.FileType:Type
 
# Misc
#
en.all.Selecting:Selecting
de.all.Selecting:Auswählen
fr.all.Selecting:Sélection en cours
it.all.Selecting:Selezione
nl.all.Selecting:Selecting
en.all.FrameDrag:Resizing frames
de.all.FrameDrag:Frames ändern
fr.all.FrameDrag:Redimensionnement des cadres en cours
it.all.FrameDrag:Ridimensione dei frame
nl.all.FrameDrag:Resizing frames
 
 
# Errors
# ======
#
# This section contains error and warning messages which
# are displayed to the user.
#
 
# Fetching errors - displayed as an HTML page
#
en.all.Not2xx:Server returned an error
de.all.Not2xx:Server meldet Fehler zurück
fr.all.Not2xx:Le serveur a renvoyé une erreur
it.all.Not2xx:Il Server ha riportato un errore
nl.all.Not2xx:Server retourneert een fout
en.all.InvalidURL:The address <em>%s</em> could not be understood.
de.all.InvalidURL:Die Adresse <em>%s</em> konnte nicht ausgewertet werden.
fr.all.InvalidURL:L'adresse <em>%s</em> est incomprise.
it.all.InvalidURL:L'indirizzo <em>%s</em> non è stato riconosciuto.
nl.all.InvalidURL:Het adres <em>%s</em> klopt niet.
 
# HTML error page
#
en.all.ErrorPage:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Page error</title></head><body><h1>Sorry, NetSurf was unable to display this page</h1><p><strong>%s</strong></p></body></html>
de.all.ErrorPage:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Seitenfehler</title></head><body><h1>NetSurf konnte diese Seite leider nicht darstellen.</h1><p><strong>%s</strong></p></body></html>
fr.all.ErrorPage:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Erreur</title></head><body><h1>Désolé, NetSurf n'a pas pu afficher cette page</h1><p><strong>%s</strong></p></body></html>
it.all.ErrorPage:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Errore nella pagina</title></head><body><h1>Spiacente, NetSurf non è in grado di visualizzare questa pagina.</h1><p><strong>%s</strong></p></body></html>
nl.all.ErrorPage:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Pagina fout</title></head><body><h1>Sorry, NetSurf kan deze pagina</h1><p><strong>%s</strong></p>niet tonen.</body></html>
 
# General errors - displayed in a dialog box
#
# These may be augmented with further relevant information, which
# is displayed after the contents of the relevant token.
#
en.all.PathToURL:An error occurred converting the file path to an URL:
de.all.PathToURL:Fehler beim Konvertieren des Dateipfades in eine URL Adresse:
fr.all.PathToURL:Une erreur s'est produite en convertissant le chemin du fichier en une URL:
it.all.PathToURL:Si è verificato un errore durante la conversione del percorso file nell'URL:
nl.all.PathToURL:Fout tijdens het converteren van het bestandspad naar een URL:
en.all.SaveError:The file could not be saved due to an error:
de.all.SaveError:Die Datei konnte wegen eines Fehlers nicht gespeichert werden:
fr.all.SaveError:Le fichier n'a pas pu être sauvé suite à une erreur:
it.all.SaveError:Il file non può essere salvato a causa di un errore:
nl.all.SaveError:Wegens een fout kan dit bestand niet opgeslagen worden:
en.all.LoadError:The file could not be loaded due to an error:
de.all.LoadError:Die Datei konnte wegen eines Fehlers nicht geladen werden:
fr.all.LoadError:Le fichier n'a pas pu être chargé à cause d'une erreur:
it.all.LoadError:Il file non può essere caricato a causa di un errore:
nl.all.LoadError:Wegens een fout kan dit bestand niet geladen worden:
en.all.MenuError:An error occurred when opening the menu:
de.all.MenuError:Fehler beim Öffnen des Menüs:
fr.all.MenuError:Une erreur s'est produite lors de l'ouverture du menu:
it.all.MenuError:Si è verificato un errore durante l'apertura del menu:
nl.all.MenuError:Fout bij het openen van het menu:
en.all.DragError:An error occurred when dragging the icon:
de.all.DragError:Fehler beim Ziehen des Symboles:
fr.all.DragError:Une erreur s'est produite lors du déplacement d'icône:
it.all.DragError:Si è verificato un errore durante il trascinamento dell'icona:
nl.all.DragError:Fout bij het slepen van het icoon:
en.all.TbarError:An error occurred when constructing the toolbar:
de.all.TbarError:Fehler beim Aufbau der Toolbar:
fr.all.TbarError:Une erreur s'est produite lors de la construction de la barre d'outils:
it.all.TbarError:Si è verificato un errore durante la costruzione della barra strumenti:
nl.all.TbarError:Fout bij het construeren van de gereedschapbalk:
en.all.WimpError:An unexpected Window Manager error occurred:
de.all.WimpError:Unerwarteter Fehler im Window Manager:
fr.all.WimpError:Une erreur inattendue du Gestionnaire de Fenêtres s'est produite:
it.all.WimpError:Si è verificato un errore inatteso nella finestra principale:
nl.all.WimpError:Er trad een onverwachtte Window Manager fout op:
en.all.DownloadWarn:This download may not complete:
de.all.DownloadWarn:Der Download ist wahrscheinlich unvollständig:
fr.all.DownloadWarn:Ce téléchargement ne peut pas se terminer:
it.all.DownloadWarn:Questo trasferimento potrebbe essere incompleto:
nl.all.DownloadWarn:Dit bestand is misschien niet compleet opgehaald:
en.all.MiscError:An unexpected error occurred:
de.all.MiscError:Unerwarteter Fehler:
fr.all.MiscError:Une erreur inattendue s'est produite:
it.all.MiscError:Si è verificato un errore inatteso:
nl.all.MiscError:Er trad een onverwachtte fout op:
en.all.FileError:File does not exist:
de.all.FileError:Datei existiert nicht:
fr.all.FileError:Le fichier n'existe pas:
it.all.FileError:Il file è inesistente:
nl.all.FileError:Bestand bestaat niet:
en.all.PrintError:An error occurred when printing:
de.all.PrintError:Ein Fehler trat während des Druckens auf:
fr.all.PrintError:Une erreur s'est produite lors de l'impression:
it.all.PrintError:Si è verificato un errore durante la stampa:
nl.all.PrintError:Fout tijdens printen:
 
# Specific errors - displayed in a dialog box
#
en.all.NoMemory:NetSurf is running out of memory. Please free some memory and try again.
de.all.NoMemory:Zu wenig Speicher. Bitte mehr Speicher zur Verfügung stellen und erneut versuchen.
fr.all.NoMemory:NetSurf a besoin de plus de mémoire. Veuillez libérer de la mémoire et réessayer.
it.all.NoMemory:Memoria insufficiente per l'esecuzione di NetSurf. Per favore liberane un pò e riprova nuovamente.
nl.all.NoMemory:NetSurf krijgt gebrek aan geheugen. Maak wat geheugen vrij en probeer het dan nog eens.
en.ro.FontBadInst:An error occurred when initialising fonts due to the presence of obsolete copies of the ROM fonts on disc. NetSurf will exit and launch a program which will attempt to fix this.
de.ro.FontBadInst:Font-Initialisierung fehlerhaft. Obsolete Kopien von ROM Fonts auf dem lokalem Speichermedium. Fehlerbehebung startet.
fr.ro.FontBadInst:Une erreur s'est produite lors de l'initialisation des fontes à cause de la présence de copies obsolètes de fontes ROM sur disque. NetSurf va sortir et lancer un programme qui va tenter de réparer cela.
it.ro.FontBadInst:Si è verificato un errore durante l'inizializzazione dei font a causa della presenza di una copia obsoleta dei font "ROM" nel disco. NetSurf verrà chiuso e si cercherà di lanciare un programma in grado di risolvere questo problema.
nl.ro.FontBadInst:An error occurred when initialising fonts due to the presence of obsolete copies of the ROM fonts on disc. NetSurf will exit and launch a program which will attempt to fix this.
en.ro.FontError:Failed to open font "Homerton.Medium" (%s).
de.ro.FontError:Fehler beim öffnen des Fonts "Homerton.Medium" (%s).
fr.ro.FontError:Échec d'ouverture de la fonte "Homerton.Medium" (%s).
it.ro.FontError:Impossibile aprire il font "Homerton.Medium" (%s).
nl.ro.FontError:Het lettertypenbestand "Homerton.Medium" kan niet geopend worden (%s).
en.ro.Resolvers:No domain name servers are configured, so only browsing local files will be possible. Use Configure to set your name server(s).
de.ro.Resolvers:Keine Domain Name Servers (DNS) konfiguriert. Nur lokale Dateien sind ladbar. Bitte DNS unter !Boot eintragen.
fr.ro.Resolvers:Aucun nom de domaine n'étant configuré, seul la consultation de fichiers locaux est possible. Utilisez Configure pour définir les serveurs de noms.
it.ro.Resolvers:Non è stato configurato nessun nome per i domini dei server, perciò sarà possibile effettuare la navigazione dei file solo in modalità locale. Usa "Configura" per impostare il nome (o i nomi) del/dei server.
nl.ro.Resolvers:Er zijn geen DNS servers ingesteld, dus kunnen alleen locale bestanden bekeken worden. Gebruik Configure om uw naam server(s) in te stellen.
en.all.NoDiscSpace:Not enough space available on disc.
de.all.NoDiscSpace:Nicht genug Speicherplatz auf dem Medium vorhanden.
fr.all.NoDiscSpace:Pas assez d'espace disque disponible.
it.all.NoDiscSpace:Spazio insufficiente nel disco.
nl.all.NoDiscSpace:Niet genoeg ruimte beschikbaar op disk.
en.ro.Template:A window template is missing from the Templates file. Please reinstall NetSurf.
de.ro.Template:Ein Template für ein Fenster fehlt in der Datei Templates. Bitte NetSurf neu installieren.
fr.ro.Template:Un modèle de fenêtre est absent du fichier Templates. Réinstallez NetSurf SVP.
it.ro.Template:Una finestra di template risulta mancante. Per favore reinstalla NetSurf.
nl.ro.Template:Er ontbreekt een venster sjabloon in het Templates bestand. Installeer NetSurf opnieuw.
en.all.HotlistSaveError:The hotlist was unable to be correctly saved.
de.all.HotlistSaveError:Hotlist konnte nicht korrekt gespeichert werden.
fr.all.HotlistSaveError:Les favoris n'ont pas pu être sauvés correctement.
it.all.HotlistSaveError:Non è stato possibile salvare correttamente i segnalibri.
nl.all.HotlistSaveError:The hotlist was unable to be correctly saved.
en.all.TreeLoadError:The tree was unable to be correctly loaded.
de.all.TreeLoadError:The tree was unable to be correctly loaded.
fr.all.TreeLoadError:The tree was unable to be correctly loaded.
it.all.TreeLoadError:L'albero non è stato caricato correttamente.
nl.all.TreeLoadError:The tree was unable to be correctly loaded.
en.all.NoDirError:%s is not a directory
de.all.NoDirError:%s ist kein Verzeichnis.
fr.all.NoDirError:%s n'est pas un répertoire
it.all.NoDirError:%s non è una directory
nl.all.NoDirError:%s is not a directory
en.ro.NoPathError:To save, drag the icon to a directory display
de.ro.NoPathError:Symbol in ein Verzeichnisfenster ziehen um zu Speichern.
fr.ro.NoPathError:Pour sauver, lâcher cette icône dans une fenêtre de Filer
it.ro.NoPathError:Per salvare, trascina l'icona in una directory di visualizzazione.
nl.ro.NoPathError:Sleep het icoon naar een bestandsvenster om het op te slaan.
en.all.NoNameError:Please enter a name
de.all.NoNameError:Bitte einen Namen eingeben.
fr.all.NoNameError:Entrez un nom SVP
it.all.NoNameError:Inserisci un nome
nl.all.NoNameError:Geef een naam op
en.all.NoURLError:Please enter a URL
de.all.NoURLError:Bitte eine URL Adresse eingeben.
fr.all.NoURLError:Entrez une URL SVP
it.all.NoURLError:Inserisci un URL
nl.all.NoURLError:Geef een URL op
en.all.URIError:NetSurf was unable to parse this URI file due to a syntax error.
de.all.URIError:NetSurf konnte die URI Datei nicht lesen. Syntax Fehler.
fr.all.URIError:NetSurf est incapable de traiter ce fichier URI à cause d'une erreur de syntaxe.
it.all.URIError:NetSurf non è stato in grado di processare questo file URI a causa di un errore di sintassi.
nl.all.URIError:NetSurf was unable to parse this URI file due to a syntax error.
en.all.EmptyError:file is empty.
de.all.EmptyError:Die Datei ist leer.
fr.all.EmptyError:Le fichier est vide.
it.all.EmptyError:Il file è vuoto.
nl.all.EmptyError:bestand is leeg.
en.all.SearchError:Invalid Search.
de.all.SearchError:Suche fehlerhaft.
fr.all.SearchError:Recherche Non-Valide.
it.all.SearchError:Ricerca non valida.
nl.all.SearchError:Invalid Search.
en.all.PrintErrorRO2:It appears that the printer is busy.
de.all.PrintErrorRO2:Der Drucker scheint beschäftigt zu sein.
fr.all.PrintErrorRO2:Il semble que l'imprimante soit occupée.
it.all.PrintErrorRO2:La stampante sembra essere occupata.
nl.all.PrintErrorRO2:De printer lijkt al bezig te zijn.
en.ro.AWNotSeen:Please locate the AWViewer application and try again.
de.ro.AWNotSeen:Das Programm AWViewer wurde nicht gefunden.
fr.ro.AWNotSeen:Localisez l'application AMViewer SVP puis réessayez.
it.ro.AWNotSeen:Per favore fornisci l'applicativo AWViewer e riprova nuovamente.
nl.ro.AWNotSeen:Zoek eerst de AWViewer applicatie en probeer het dan nog eens.
en.all.EncNotRec:Encoding type not recognised.
de.all.EncNotRec:Encodierung nicht erkannt.
fr.all.EncNotRec:Encoding type not recognised.
it.all.EncNotRec:Tipo di codifica sconosciuta.
nl.all.EncNotRec:Encoding type not recognised.
en.all.FileOpenError:could not open file '%s'
de.all.FileOpenError:Datei ist nicht zu öffnen: '%s'
fr.all.FileOpenError:could not open file '%s'
it.all.FileOpenError:impossibile aprire il file '%s'
nl.all.FileOpenError:could not open file '%s'
en.all.DirectoryError:directory '%s' already exists
de.all.DirectoryError:Verzeichnis '%s' existiert bereits.
fr.all.DirectoryError:directory '%s' already exists
it.all.DirectoryError:La directory '%s' è già esistente
nl.all.DirectoryError:directory '%s' already exists
 
# Error messages for Amiga version only
en.ami.CompError:Unable to open
de.ami.CompError:Nicht zu öffnen
fr.ami.CompError:Unable to open
it.ami.CompError:Impossibile aprire
nl.ami.CompError:Unable to open
en.ami.MultiTabClose:Are you sure you want to close multiple tabs?
de.ami.MultiTabClose:Are you sure you want to close multiple tabs?
fr.ami.MultiTabClose:Are you sure you want to close multiple tabs?
it.ami.MultiTabClose:Sono rimaste aperte più schede, sei sicuro di voler uscire da NetSurf?
nl.ami.MultiTabClose:Are you sure you want to close multiple tabs?
en.ami.TCPIPShutdown:The TCP/IP stack has signalled that it is about to shutdown and NetSurf must exit. NetSurf will quit in 5 seconds unless this shutdown is aborted.
de.ami.TCPIPShutdown:The TCP/IP stack has signalled that it is about to shutdown and NetSurf must exit. NetSurf will quit in 5 seconds unless this shutdown is aborted.
fr.ami.TCPIPShutdown:The TCP/IP stack has signalled that it is about to shutdown and NetSurf must exit. NetSurf will quit in 5 seconds unless this shutdown is aborted.
it.ami.TCPIPShutdown:Lo stack TCP/IP ha dato segnale di essere in procinto di arresto, NetSurf verrà chiuso. NetSurf si chiuderà entro 5 secondi a meno che lo shutdown non venga interrotto.
nl.ami.TCPIPShutdown:The TCP/IP stack has signalled that it is about to shutdown and NetSurf must exit. NetSurf will quit in 5 seconds unless this shutdown is aborted.
en.ami.AbortShutdown:Abort shutdown
de.ami.AbortShutdown:Abort shutdown
fr.ami.AbortShutdown:Abort shutdown
it.ami.AbortShutdown:Interrompi lo shutdown
nl.ami.AbortShutdown:Abort shutdown
 
 
# Queries
# =======
#
# This section contains queries which are displayed to the user
#
 
en.all.AbortDownload:Are you sure you wish to abort this download?
de.all.AbortDownload:Soll das Herunterladen der Datei wirklich abgebrochen werden ?
fr.all.AbortDownload:Étes-vous sûr de vouloir interrompre ce téléchargement ?
it.all.AbortDownload:Sei sicuro di voler annullare questo trasferimento?
nl.all.AbortDownload:Zeker weten dat u deze download af wilt breken?
en.all.QuitDownload:One or more downloads are still in progress. Are you sure you wish to quit?
de.all.QuitDownload:Das Herunterladen ein oder mehrerer Dateien wurde noch nicht abgeschlossen. Soll NetSurf trotzdem beendet werden ?
fr.all.QuitDownload:Un ou plusieurs téléchargements sont en cours. Êtes-vous sûr de vouloir quitter ?
it.all.QuitDownload:Uno o più file si trovano in fase di scaricamento, sei sicuro di voler chiudere NetSurf?
nl.all.QuitDownload:Een of meer downloads zijn nog bezig. Toch afbreken?
en.all.OverwriteFile:A file with that name already exists and would be lost.
de.all.OverwriteFile:Eine Datei mit diesem Namen existiert bereits und würde überschrieben werden.
fr.all.OverwriteFile:Un fichier portant ce nom existe déjà et serait perdu.
it.all.OverwriteFile:Un file con questo nome è già esistente, continuare comporterà la sovrascrittura del file originale.
nl.all.OverwriteFile:Een bestand met deze naam bestaat al en zal verloren gaan.
 
# Page fetching
# =============
#
# This section contains messages which may be displayed whilst
# fetching a page or other content
#
 
# Fetch status messages - displayed in status bar
#
en.all.Progress:%s of %s
de.all.Progress:%s von %s
fr.all.Progress:%s reçus de %s
it.all.Progress:%s di %s
nl.all.Progress:%s van %s
en.all.ProgressU:%s
de.all.ProgressU:%s
fr.all.ProgressU:%s
it.all.ProgressU:%s
nl.all.ProgressU:%s
en.all.RecPercent:Received %s (%u%%)
de.all.RecPercent:Empfangen %s (%u%%)
fr.all.RecPercent:%s (%u%%)
it.all.RecPercent:ricevuti %s (%u%%)
nl.all.RecPercent:ontvangen %s (%u%%)
en.all.Received:Received %s
de.all.Received:Empfangen %s
fr.all.Received:%s reçus
it.all.Received:ricevuti %s
nl.all.Received:ontvangen %s
en.all.Redirecting:Redirecting...
de.all.Redirecting:Umleiten...
fr.all.Redirecting:Redirection en cours...
it.all.Redirecting:redirezione in corso...
nl.all.Redirecting:doorverwijzen...
en.all.Loading:Loading
de.all.Loading:Loading
fr.all.Loading:Loading
it.all.Loading:Caricamento della pagina...
nl.all.Loading:Loading
en.all.Fetching:Fetching data
de.all.Fetching:Ladevorgänge
fr.all.Fetching:Fetching
it.all.Fetching:Ricezione
nl.all.Fetching:Fetching
en.all.Processing:Processing
de.all.Processing:Auswerten
fr.all.Processing:Traitement
it.all.Processing:elaborazione del documento in corso...
nl.all.Processing:verwerking
en.all.Formatting:Formatting
de.all.Formatting:Formatieren
fr.all.Formatting:Formatage
it.all.Formatting:formattazione del documento in corso...
nl.all.Formatting:opmaken
en.all.Done:Done
de.all.Done:Fertiggestellt
fr.all.Done:Terminé
it.all.Done:Completato
nl.all.Done:klaar
en.all.Stopped:Stopped
de.all.Stopped:Stopped
fr.all.Stopped:Stopped
it.all.Stopped:Interrotto
nl.all.Stopped:Stopped
 
# Fetch warning/error messages - displayed in status bar
#
en.all.BadRedirect:Bad redirect URL
de.all.BadRedirect:Falsche URL für Redirect
fr.all.BadRedirect:Mauvais URL de redirection
it.all.BadRedirect:Errata redirezione dell'URL
nl.all.BadRedirect:foutief doorverwijzen naar URL
en.all.FetchFailed:Unable to fetch document
de.all.FetchFailed:Kann Dokument nicht fetchen
fr.all.FetchFailed:Récupération du fichier impossible
it.all.FetchFailed:Impossibile ottenere il documento
nl.all.FetchFailed:kan dit document niet ophalen
en.all.NotCSS:Warning: stylesheet is not CSS
de.all.NotCSS:Warnung:Stylesheet ist kein CSS
fr.all.NotCSS:Attention: feuille de style non CSS
it.all.NotCSS:Attenzione: La dicitura "Foglio di stile" non ha nulla a che vedere con i CSS
nl.all.NotCSS:melding: stylesheet is geen CSS
en.all.NotFavIco:Favicon not supported
de.all.NotFavIco:Favicon wird nicht unterstützt
fr.all.NotFavIco:Favicon non-soutenu
it.all.NotFavIco:Favicon non supportata
nl.all.NotFavIco:Favicon not supported
en.all.BadObject:Warning: bad object type
de.all.BadObject:Warnung: falscher Objekttyp
fr.all.BadObject:Attention: mauvais type d'objet
it.all.BadObject:Errore nell'analisi del tipo di oggetto
nl.all.BadObject:melding: fout object type
en.all.ObjError:Error loading object: %s
de.all.ObjError:Fehler beim Laden des Objektes: %s
fr.all.ObjError:Erreur lors du chargement de: %s
it.all.ObjError:Errore nel caricamento dell'oggetto: %s
nl.all.ObjError:fout bij laden object: %s
en.all.ParsingFail:Parsing the document failed.
de.all.ParsingFail:Dokumentparsing ist fehlgeschlagen.
fr.all.ParsingFail:L'analyse syntaxique du document a échoué.
it.all.ParsingFail:Analisi del documento fallita.
nl.all.ParsingFail:fout bij ontleden van dit document.
en.all.CSSGeneric:Error processing CSS
en.all.CSSBase:Base stylesheet failed to load
en.all.BadGIF:Reading GIF failed.
de.all.BadGIF:Lesen einer GIF Datei fehlgeschlagen.
fr.all.BadGIF:Erreur de lecture de GIF.
it.all.BadGIF:Lettura del file GIF fallita.
nl.all.BadGIF:fout bij lezen GIF.
en.all.BadBMP:Reading BMP failed.
de.all.BadBMP:Lesen einer BMP Datei fehlgeschlagen.
fr.all.BadBMP:Erreur de lecture de BMP.
it.all.BadBMP:Lettura del file BMP fallita.
nl.all.BadBMP:fout bij lezen BMP.
en.all.BadICO:Reading ICO failed.
de.all.BadICO:Lesen einer ICO Datei fehlgeschlagen.
fr.all.BadICO:Erreur de lecture de ICO.
it.all.BadICO:Lettura del file ICO fallita.
nl.all.BadICO:fout bij lezen ICO.
en.all.PNGError:Error converting PNG.
de.all.PNGError:Fehler beim PNG konvertieren.
fr.all.PNGError:Error converting PNG.
it.all.PNGError:Errore durante la conversione PNG.
nl.all.PNGError:Error converting PNG.
en.all.MNGError:Error converting MNG/PNG/JNG: %i
de.all.MNGError:MNG Library Fehler: %i
fr.all.MNGError:Erreur dans la bibliothèque MNG: %i
it.all.MNGError:Errore durante la conversione MNG/PNG/JNG: %i
nl.all.MNGError:MNG library fout: %i
en.all.BadSprite:Invalid or corrupt Sprite data.
de.all.BadSprite:Ungültiges oder beschädigtes Sprite.
fr.all.BadSprite:Les données du sprite sont invalides ou corrompues.
it.all.BadSprite:Dati del file Sprite invalidi o corrotti.
nl.all.BadSprite:foutief sprite bestand.
 
# HTTP status codes
#
en.all.HTTP0:OK
de.all.HTTP0:OK
fr.all.HTTP0:OK
it.all.HTTP0:OK
nl.all.HTTP0:OK
en.all.HTTP200:OK
de.all.HTTP200:OK
fr.all.HTTP200:OK
it.all.HTTP200:OK
nl.all.HTTP200:OK
en.all.HTTP201:Created
de.all.HTTP201:Created
fr.all.HTTP201:Créé
it.all.HTTP201:Creato
nl.all.HTTP201:Created
en.all.HTTP202:Accepted
de.all.HTTP202:Accepted
fr.all.HTTP202:Accepté
it.all.HTTP202:Accettato
nl.all.HTTP202:Accepted
en.all.HTTP203:Non-authoritative information
de.all.HTTP203:Non-authoritative information
fr.all.HTTP203:Information ne faisant pas autorité
it.all.HTTP203:Informazione non autorevole
nl.all.HTTP203:Non-authoritative information
en.all.HTTP204:No content
de.all.HTTP204:No content
fr.all.HTTP204:Pas de contenu
it.all.HTTP204:Nessun contenuto
nl.all.HTTP204:No content
en.all.HTTP205:Reset content
de.all.HTTP205:Reset content
fr.all.HTTP205:Remise-à-Zéro du contenu
it.all.HTTP205:Resetta contenuto
nl.all.HTTP205:Reset content
en.all.HTTP206:Partial content
de.all.HTTP206:Partial content
fr.all.HTTP206:Contenu partiel
it.all.HTTP206:Contenuto parziale
nl.all.HTTP206:Partial content
en.all.HTTP300:Multiple choices
de.all.HTTP300:Multiple choices
fr.all.HTTP300:Choix multiples
it.all.HTTP300:Scelte multiple
nl.all.HTTP300:Multiple choices
en.all.HTTP301:Moved permanently
de.all.HTTP301:Moved permanently
fr.all.HTTP301:A déménagé définitivement
it.all.HTTP301:Rimosso permanentemente
nl.all.HTTP301:Moved permanently
en.all.HTTP302:Found
de.all.HTTP302:Found
fr.all.HTTP302:Trouvé
it.all.HTTP302:Trovato
nl.all.HTTP302:Found
en.all.HTTP303:See other
de.all.HTTP303:See other
fr.all.HTTP303:Voir autre
it.all.HTTP303:Vedi altro
nl.all.HTTP303:See other
en.all.HTTP304:Not modified
de.all.HTTP304:Not modified
fr.all.HTTP304:Pas modifié
it.all.HTTP304:Non modificato
nl.all.HTTP304:Not modified
en.all.HTTP305:Use proxy
de.all.HTTP305:Use proxy
fr.all.HTTP305:Utilisez un proxy
it.all.HTTP305:Usa Proxy
nl.all.HTTP305:Use proxy
en.all.HTTP307:Temporary redirect
de.all.HTTP307:Temporary redirect
fr.all.HTTP307:Redirection temporaire
it.all.HTTP307:Redirezione temporanea
nl.all.HTTP307:Temporary redirect
en.all.HTTP400:Bad request
de.all.HTTP400:Bad request
fr.all.HTTP400:Mauvaise requête
it.all.HTTP400:Richiesta errata
nl.all.HTTP400:Bad request
en.all.HTTP401:Unauthorized
de.all.HTTP401:Unauthorized
fr.all.HTTP401:Sans autorisation
it.all.HTTP401:Autorizzazione negata
nl.all.HTTP401:Unauthorized
en.all.HTTP402:Payment required
de.all.HTTP402:Payment required
fr.all.HTTP402:Paiment nécessaire
it.all.HTTP402:Richiesto di pagamento
nl.all.HTTP402:Payment required
en.all.HTTP403:Forbidden
de.all.HTTP403:Forbidden
fr.all.HTTP403:Interdit
it.all.HTTP403:Vietato
nl.all.HTTP403:Forbidden
en.all.HTTP404:Not found
de.all.HTTP404:Not found
fr.all.HTTP404:Pas trouvé
it.all.HTTP404:Non trovato
nl.all.HTTP404:Not found
en.all.HTTP405:Method not allowed
de.all.HTTP405:Method not allowed
fr.all.HTTP405:Méthode non autorisée
it.all.HTTP405:Metodo non permesso
nl.all.HTTP405:Method not allowed
en.all.HTTP406:Not acceptable
de.all.HTTP406:Not acceptable
fr.all.HTTP406:Pas acceptable
it.all.HTTP406:Non accettabile
nl.all.HTTP406:Not acceptable
en.all.HTTP407:Proxy authentication required
de.all.HTTP407:Proxy authentication required
fr.all.HTTP407:Authentification du proxy nécessaire
it.all.HTTP407:Autentificazione Proxy necessaria
nl.all.HTTP407:Proxy authentication required
en.all.HTTP408:Request timeout
de.all.HTTP408:Request timeout
fr.all.HTTP408:Délai de requête trop long
it.all.HTTP408:Richiesta TimeOut
nl.all.HTTP408:Request timeout
en.all.HTTP409:Conflict
de.all.HTTP409:Conflict
fr.all.HTTP409:Conflit
it.all.HTTP409:Conflitto
nl.all.HTTP409:Conflict
en.all.HTTP410:Gone
de.all.HTTP410:Gone
fr.all.HTTP410:Parti
it.all.HTTP410:Irraggiungibile
nl.all.HTTP410:Gone
en.all.HTTP411:Length required
de.all.HTTP411:Length required
fr.all.HTTP411:Longueur nécessaire
it.all.HTTP411:Lunghezza richiesta
nl.all.HTTP411:Length required
en.all.HTTP412:Precondition failed
de.all.HTTP412:Precondition failed
fr.all.HTTP412:Échec de précondition
it.all.HTTP412:Precondizione fallita
nl.all.HTTP412:Precondition failed
en.all.HTTP413:Request entity too large
de.all.HTTP413:Request entity too large
fr.all.HTTP413:Demande d'entité trop grande
it.all.HTTP413:Entità richiesta troppo larga
nl.all.HTTP413:Request entity too large
en.all.HTTP414:Request-URI too long
de.all.HTTP414:Request-URI too long
fr.all.HTTP414:Request-URI trop long
it.all.HTTP414:Richiesta URI troppo lunga
nl.all.HTTP414:Request-URI too long
en.all.HTTP415:Unsupported media type
de.all.HTTP415:Unsupported media type
fr.all.HTTP415:Type de média non supporté
it.all.HTTP415:Tipo di media non supportato
nl.all.HTTP415:Unsupported media type
en.all.HTTP416:Requested range not satisfiable
de.all.HTTP416:Requested range not satisfiable
fr.all.HTTP416:Étendue demandée non satisfaisable
it.all.HTTP416:Estensione richiesta non soddisfabile
nl.all.HTTP416:Requested range not satisfiable
en.all.HTTP417:Expectation failed
de.all.HTTP417:Expectation failed
fr.all.HTTP417:Attente non satisfaite
it.all.HTTP417:Previsione fallita
nl.all.HTTP417:Expectation failed
en.all.HTTP500:Internal server error
de.all.HTTP500:Internal server error
fr.all.HTTP500:Erreur de serveur interne
it.all.HTTP500:Errore interno del server
nl.all.HTTP500:Internal server error
en.all.HTTP501:Not implemented
de.all.HTTP501:Not implemented
fr.all.HTTP501:Non implémenté
it.all.HTTP501:Non implementata
nl.all.HTTP501:Not implemented
en.all.HTTP502:Bad gateway
de.all.HTTP502:Bad gateway
fr.all.HTTP502:Mauvaise passerelle
it.all.HTTP502:Gateway errato
nl.all.HTTP502:Bad gateway
en.all.HTTP503:Service unavailable
de.all.HTTP503:Service unavailable
fr.all.HTTP503:Service non disponible
it.all.HTTP503:Servizio non disponibile
nl.all.HTTP503:Service unavailable
en.all.HTTP504:Gateway timeout
de.all.HTTP504:Gateway timeout
fr.all.HTTP504:Délai de passerelle trop long
it.all.HTTP504:TimeOut Gateway
nl.all.HTTP504:Gateway timeout
en.all.HTTP505:HTTP version not supported
de.all.HTTP505:HTTP version not supported
fr.all.HTTP505:version d'HTTP non supportée
it.all.HTTP505:Versione HTTP non supportata
nl.all.HTTP505:HTTP version not supported
 
# User interface
# ==============
#
# This section contains messages to deal with user interface
# features.
#
 
# Scrollbars - displayed in status bar
#
en.all.ScrollUp:Click the arrow to scroll up
de.all.ScrollUp:Pfeil anklicken zum Hochscrollen
fr.all.ScrollUp:Cliquez sur la flèche pour faire défiler vers le haut
it.all.ScrollUp:Clicca sulla freccia per scrollare in alto
nl.all.ScrollUp:Click the arrow to scroll up
en.all.ScrollPUp:Click to scroll up one page
de.all.ScrollPUp:Anklicken scrollt eine Seite hoch
fr.all.ScrollPUp:Cliquez pour faire défiler d'une page vers le haut
it.all.ScrollPUp:Clicca per scrollare in alto di una pagina
nl.all.ScrollPUp:Click to scroll up one page
en.all.ScrollV:Drag the bar to scroll vertically
de.all.ScrollV:Ziehen der Leiste scrollt vertikal
fr.all.ScrollV:Tirez la barre pour la faire défiler verticalement
it.all.ScrollV:Trascina la barra per scrollare verticalmente
nl.all.ScrollV:Drag the bar to scroll vertically
en.all.ScrollPDown:Click to scroll down one page
de.all.ScrollPDown:Anklicken scrollt eine Seite nach unten
fr.all.ScrollPDown:Cliquez pour faire défiler d'une page vers le bas
it.all.ScrollPDown:Clicca per scrollare in basso di una pagina
nl.all.ScrollPDown:Click to scroll down one page
en.all.ScrollDown:Click the arrow to scroll down
de.all.ScrollDown:Pfeil anklicken zum Herunterscrollen
fr.all.ScrollDown:Cliquez sur la flèche pour faire défiler vers le bas
it.all.ScrollDown:Clicca sulla freccia per scrollare in basso
nl.all.ScrollDown:Click the arrow to scroll down
en.all.ScrollLeft:Click the arrow to scroll left
de.all.ScrollLeft:Pfeil anklicken scrollt links
fr.all.ScrollLeft:Cliquez sur la flèche pour faire défiler vers la gauche
it.all.ScrollLeft:Clicca sulla freccia per scrollare a sinistra
nl.all.ScrollLeft:Click the arrow to scroll left
en.all.ScrollPLeft:Click to scroll left one page
de.all.ScrollPLeft:Anklicken scrollt eine Seite nach links
fr.all.ScrollPLeft:Cliquez pour faire défiler d'une page vers la gauche
it.all.ScrollPLeft:Clicca per scrollare a sinistra di una pagina
nl.all.ScrollPLeft:Click to scroll left one page
en.all.ScrollH:Drag the bar to scroll horizontally
de.all.ScrollH:Ziehen der Leiste scrollt horizontal
fr.all.ScrollH:Tirez la barre pour la faire défiler horizontalement
it.all.ScrollH:Trascina la barra per scrollare orizzontalmente
nl.all.ScrollH:Drag the bar to scroll horizontally
en.all.ScrollPRight:Click to scroll right one page
de.all.ScrollPRight:Anklicken scrollt eine Seite nach rechts
fr.all.ScrollPRight:Cliquez pour faire défiler d'une page vers la droite
it.all.ScrollPRight:Clicca per scrollare a destra di una pagina
nl.all.ScrollPRight:Click to scroll right one page
en.all.ScrollRight:Click the arrow to scroll right
de.all.ScrollRight:Pfeil anklicken scrollt rechts
fr.all.ScrollRight:Cliquez sur la flèche pour faire défiler vers la droite
it.all.ScrollRight:Clicca sulla freccia per scrollare a destra
nl.all.ScrollRight:Click the arrow to scroll right
en.all.ScrollBoth:Move your mouse while keeping the button pressed to scroll the content
de.all.ScrollBoth:Bewege die Maus bei gedrückten Mausknopf zum Scrollen des Inhalts
fr.all.ScrollBoth:Move your mouse while keeping the button pressed to scroll the content
it.all.ScrollBoth:Sposta il mouse tenendo premuto il tasto sinistro per scrollare il contenuto della pagina
nl.all.ScrollBoth:Move your mouse while keeping the button pressed to scroll the content
 
# Select menu - displayed in status bar
#
en.all.SelectClick:Click on entry to select it
de.all.SelectClick:Anklicken um auszuwählen
fr.all.SelectClick:Click on entry to select it
it.all.SelectClick:Clicca sull'elemento per selezionarlo
nl.all.SelectClick:Click on entry to select it
en.all.SelectMClick:Click on entry to select it, multiple options can be selected
de.all.SelectMClick:Anklicken um auszuwählen, auch mehrere Optionen sind auswählbar
fr.all.SelectMClick:Click on entry to select it, multiple options can be selected
it.all.SelectMClick:Clicca sull'elemento per selezionarlo, sono supportate le scelte multiple
nl.all.SelectMClick:Click on entry to select it, multiple options can be selected
en.all.SelectClose:Click to close the select menu
de.all.SelectClose:Anklicken zum Schließen des Menus
fr.all.SelectClose:Click to close the select menu
it.all.SelectClose:Clicca per chiudere l'elemento selezionato
nl.all.SelectClose:Click to close the select menu
 
# Saving
# ======
#
# Messages used when saving
#
 
en.all.SaveSource:Source
de.all.SaveSource:Quellcode
fr.all.SaveSource:Source
it.all.SaveSource:Sorgente
nl.all.SaveSource:Bron
en.all.SaveDraw:Webpage
de.all.SaveDraw:Webseite
fr.all.SaveDraw:PageWeb
it.all.SaveDraw:Pagina Web
nl.all.SaveDraw:Webpagina
en.all.SaveText:Webpage
de.all.SaveText:Webseite
fr.all.SaveText:PageWeb
it.all.SaveText:Pagina Web
nl.all.SaveText:Webpagina
en.all.SaveObject:Object
de.all.SaveObject:Objekt
fr.all.SaveObject:Objet
it.all.SaveObject:Oggetto
nl.all.SaveObject:Object
en.all.SaveLink:Link
de.all.SaveLink:Link
fr.all.SaveLink:Lien
it.all.SaveLink:Link
nl.all.SaveLink:Link
en.all.SaveSelection:Selection
de.all.SaveSelection:Auswahl
fr.all.SaveSelection:Texte
it.all.SaveSelection:Selezione
nl.all.SaveSelection:Selectie
 
# Themes
# ======
#
# Messages used when installing new themes
#
 
en.all.ThemeInstActive:A theme is currently being downloaded or installed. Please wait for it to finish or cancel it before installing more themes.
de.all.ThemeInstActive:Ein Thema wird gerade geladen oder installiert. Bitte vor Installation weiterer Themen diesen Vorgang abwarten oder beenden.
fr.all.ThemeInstActive:Un thème est en cours de téléchargement ou d'installation. Veuillez attendre que ce soit fini ou annulez l'opération avant d'installer de nouveaux thèmes.
it.all.ThemeInstActive:Il tema è attualmente in fase di scaricamento o di installazione. Attendere il completamente del processo oppure annullare l'intera operazione prima di installare altri temi.
nl.all.ThemeInstActive:A theme is currently being downloaded or installed. Please wait for it to finish or cancel it before installing more themes.
en.all.ThemeInstDown:Please wait for the theme to download.
de.all.ThemeInstDown:Bitte warten bis das Thema vollständig heruntergeladen wurde.
fr.all.ThemeInstDown:Veuillez attendre le téléchargement du thème.
it.all.ThemeInstDown:Per favore attendere lo scaricamento del tema grafico.
nl.all.ThemeInstDown:Please wait for the theme to download.
en.all.ThemeInvalid:The downloaded theme is invalid or requires a newer version of NetSurf.
de.all.ThemeInvalid:Das geladene Thema ist fehlerhaft oder benötigt eine neuere Version von NetSurf.
fr.all.ThemeInvalid:Le thème téléchargé est invalide ou nécessite une version plus récente de NetSurf.
it.all.ThemeInvalid:Il tema scaricato non è compatibile oppure richiede una versione più recente di NetSurf.
nl.all.ThemeInvalid:The downloaded theme is invalid or requires a newer version of NetSurf.
en.all.ThemeInstall:Would you like to install the theme '%s' by %s?
de.all.ThemeInstall:Soll das Thema '%s' von %s installiert werden ?
fr.all.ThemeInstall:Voulez-vous installer le thème '%s' par %s?
it.all.ThemeInstall:Si desidera installare il tema '%s' di %s?
nl.all.ThemeInstall:Would you like to install the theme '%s' by %s?
en.all.ThemeInstallErr:An error occurred whilst trying to install the downloaded theme.
de.all.ThemeInstallErr:Beim Installieren des geladenen Themas trat ein Fehler auf.
fr.all.ThemeInstallErr:Une erreur s'est produite pendant l'installation du thème téléchargé.
it.all.ThemeInstallErr:Si è verificato un errore durante il tentativo di installazione del tema scaricato
nl.all.ThemeInstallErr:An error occurred whilst trying to install the downloaded theme.
en.all.ThemeApplyErr:An error occurred whilst trying to apply the downloaded theme.
de.all.ThemeApplyErr:Beim Versuch der Anwendung eines geladenen Themas trat ein Fehler auf.
fr.all.ThemeApplyErr:Une erreur s'est produite en essayant d'appliquer le thème téléchargé.
it.all.ThemeApplyErr:Si è verificato un errore durante il tentativo di applicazione del tema
nl.all.ThemeApplyErr:An error occurred whilst trying to apply the downloaded theme.
 
 
# General
# =======
#
# Some general purpose words and phrases
#
 
en.all.Bytes: B
de.all.Bytes: B
fr.all.Bytes: O
it.all.Bytes: Byte
nl.all.Bytes: B
en.all.kBytes: kB
de.all.kBytes: kB
fr.all.kBytes: KO
it.all.kBytes: KB
nl.all.kBytes: kB
en.all.MBytes: MB
de.all.MBytes: MB
fr.all.MBytes: MO
it.all.MBytes: MB
nl.all.MBytes: MB
en.all.GBytes: GB
de.all.GBytes: GB
fr.all.GBytes: GO
it.all.GBytes: GB
nl.all.GBytes: GB
 
en.all.Yes:Yes
de.all.Yes:Ja
fr.all.Yes:Oui
it.all.Yes:Si
nl.all.Yes:Ja
en.all.No:No
de.all.No:Nein
fr.all.No:Non
it.all.No:No
nl.all.No:Nee
en.all.Replace:Replace file
de.all.Replace:Ãœberschreiben
fr.all.Replace:Remplacer le fichier
it.all.Replace:Sostituire il file
nl.all.Replace:Bestand vervangen
en.all.DontReplace:Don't replace
de.all.DontReplace:Abbrechen
fr.all.DontReplace:Ne pas remplacer le fichier
it.all.DontReplace:Non sostituire
nl.all.DontReplace:Bestand niet vervangen
en.all.obj:object
de.all.obj:Objekt
fr.all.obj:objet
it.all.obj:oggetto
nl.all.obj:object
en.all.objs:objects
de.all.objs:Objekte
fr.all.objs:objets
it.all.objs:oggetti
nl.all.objs:objecten
en.all.styl:stylesheet
de.all.styl:Formatvorlage
fr.all.styl:feuille de styles
it.all.styl:foglio di stile
nl.all.styl:stijlblad
en.all.styls:stylesheets
de.all.styls:Formatvorlagen
fr.all.styls:feuilles de styles
it.all.styls:fogli di stile
nl.all.styls:stijlbladen
en.all.OK:OK
de.all.OK:OK
fr.all.OK:OK
it.all.OK:OK
nl.all.OK:OK
 
# Interactive help
# ================
#
# This section contains interactive help messages
#
en.ro.HelpToolbar0:\Tback button.|M\Straverse back one page in the history tree.|MDoes not resubmit form information.
de.ro.HelpToolbar0:Schaltet zurück auf die zuvor dargestellte Seite.|MDer Inhalt wird dabei nicht aktualisiert.
fr.ro.HelpToolbar0:\Tle bouton de retour.|M\Srevenir d'une page en arrière dans l'historique.|MNe renvoie pas l'information de formulaire.
it.ro.HelpToolbar0:\Ttorna indietro di una pagina
nl.ro.HelpToolbar0:\Tback button.|M\Straverse back one page in the history tree.|MDoes not resubmit form information.
en.ro.HelpToolbar1:\Tforward button.|M\Straverse forward one page in the history tree.|MDoes not resubmit form information.
de.ro.HelpToolbar1:Schaltet vorwärts auf die nächste Seite.|MDer Inhalt wird dabei nicht aktualisiert.
fr.ro.HelpToolbar1:\Tle bouton d'avance.|M\Savancer d'une page dans l'historique.|MNe renvoie pas l'information de formulaire.
it.ro.HelpToolbar1:\Tvai avanti di una pagina
nl.ro.HelpToolbar1:\Tforward button.|M\Straverse forward one page in the history tree.|MDoes not resubmit form information.
en.ro.HelpToolbar2:\Tstop button.|M\Sstop loading this page.
de.ro.HelpToolbar2:Das ist der Stop Schaltknopf.|MUnterbricht den Ladvorgang.
fr.ro.HelpToolbar2:\Tle bouton Stop.|M\Sarrêter le chargement de la page.
it.ro.HelpToolbar2:\Tinterrompi il caricamento della pagina
nl.ro.HelpToolbar2:\Tstop button.|M\Sstop loading this page.
en.ro.HelpToolbar3:\Treload button.|M\Sreload this page.|M\Areload this page and any objects it contains.
de.ro.HelpToolbar3:Aktualisiert den Seiteninhalt.|MKlicken mit AUSWAHL lädt die Seite neu.|MKlicken mit SPEZIAL lädt die Seite und alle zugehörigen Objekte neu.
fr.ro.HelpToolbar3:\Tle bouton de recharge.|M\Srecharger cette page.|M\Arecharger cette page et tous les objets qu'elle contient.
it.ro.HelpToolbar3:\Tricarica la pagina corrente
nl.ro.HelpToolbar3:\Treload button.|M\Sreload this page.|M\Areload this page and any objects it contains.
en.ro.HelpToolbar4:\Thome button.|M\Sgo to your home page.
de.ro.HelpToolbar4:Lädt die Homepage.
fr.ro.HelpToolbar4:\Tle bouton Accueil.|M\Saller à votre page d'accueil.
it.ro.HelpToolbar4:\Tvai alla pagina iniziale
nl.ro.HelpToolbar4:\Thome button.|M\Sgo to your home page.
en.ro.HelpToolbar5:\Thistory button.|M\Sopen the local history \w.|M\Aopen the global history \w.
de.ro.HelpToolbar5:Das ist der Schaltknopf zur History-Funktion.|MKlicken mit AUSWAHL öffnet die lokale History.|MKlicken mit SPEZIAL öffnet das Fenster mit der globalen History.
fr.ro.HelpToolbar5:\Tle bouton d'historique.|M\Souvrir la \w d'historique locale.|M\Aopen the global history \w.
it.ro.HelpToolbar5:\Tmostra la cronologia locale o globale
nl.ro.HelpToolbar5:\Thistory button.|M\Sopen the local history \w.|M\Aopen the global history \w.
en.ro.HelpToolbar6:\Tsave button.|M\Ssave the current document.
de.ro.HelpToolbar6:Speichert das aktuelle Dokument als HTML Datei.
fr.ro.HelpToolbar6:\Tle bouton de sauvegarde.|M\Ssauver le document en cours.
it.ro.HelpToolbar6:\Tsalva il documento corrente
nl.ro.HelpToolbar6:\Tsave button.|M\Ssave the current document.
en.ro.HelpToolbar7:\Tprint button.|M\Sopen the print dialogue box.
de.ro.HelpToolbar7:Drucken der aktuellen Seite.|MAnklicken öffnet den 'Drucken' Dialog.
fr.ro.HelpToolbar7:\Tle bouton d'impression.|M\Simprimer cette page.|MOuvre une bo�te de dialogue pour l'impression.
it.ro.HelpToolbar7:\Tapri la finestra di stampa
nl.ro.HelpToolbar7:\Tprint button.|M\Sopen the print dialogue box.
en.ro.HelpToolbar8:\Thotlist button.|M\Sopen the hotlist management \w.|M\Aadd this address to the hotlist.
de.ro.HelpToolbar8:Das ist der Hotlist Schaltknopf.|MKlicken mit AUSWAHL öffnet die Hotlist.|MKlicken mit SPEZIAL trägt die aktuelle Seite in die Hotlist ein.
fr.ro.HelpToolbar8:\Tle bouton de favoris.|M\Souvrir la \w de gestion des favoris.|M\Aajouter cette adresse aux favoris.
it.ro.HelpToolbar8:\Tapri o aggiungi un link ai segnalibri
nl.ro.HelpToolbar8:\Thotlist button.|M\Sopen the hotlist management \w.|M\Aadd this address to the hotlist.
en.ro.HelpToolbar9:\Tscale view button.|M\Sscale the page, affecting both text and images.
de.ro.HelpToolbar9:Anklicken öffnet den Vergrößerungs-Dialog.|MDie Vergrößerung betrifft Text und Bilder.
fr.ro.HelpToolbar9:\Tle bouton de changement d'échelle.|M\Sredimensionner la page, texte et images comprises.
it.ro.HelpToolbar9:\Tscala la dimensione del testo e delle immagini
nl.ro.HelpToolbar9:\Tscale view button.|M\Sscale the page, affecting both text and images.
en.ro.HelpToolbar10:\Tsearch button.|M\Sfind instances of a string of text on the page.
de.ro.HelpToolbar10:Anklicken öffnet das Fenster zur Textsuche.
fr.ro.HelpToolbar10:\Tle bouton de recherche.|M\Strouver des occurences de fragment de texte dans une page.
it.ro.HelpToolbar10:\Tcerca un occorrenza di testo all'interno della pagina web
nl.ro.HelpToolbar10:\Tsearch button.|M\Sfind instances of a string of text on the page.
en.ro.HelpToolbar11:\Tup button.|M\Straverse up one level on the current website
de.ro.HelpToolbar11:Das ist der Aufwärtsknopf.|MKlicken mit AUSWAHL führt auf die nächsthöhere Ebene der innerhalb Webseite.
fr.ro.HelpToolbar11:\Tle bouton haut.|M\Sremonte d'un niveau sur le site web en cours.
it.ro.HelpToolbar11:\Tsale di un livello rispetto al corrente indirizzo
nl.ro.HelpToolbar11:\Tup button.|M\Straverse up one level on the current website
en.ro.HelpToolbar14:\TURL bar.|MType in the address of a site to visit and press Return to go there.
de.ro.HelpToolbar14:Das ist die Adressleiste.|MHier die Adresse (URL) eingeben und Entertaste drücken, um eine neue Seite zu laden.
fr.ro.HelpToolbar14:\Tla barre d'URL.|MTapez l'adresse d'un site à visiter et appuyez sur Return pour y aller.
it.ro.HelpToolbar14:\Tdigita un indirizzo e premi invio
nl.ro.HelpToolbar14:\TURL bar.|MType in the address of a site to visit and press Return to go there.
en.ro.HelpToolbar15:\TURL suggestion icon.|M\Sopen a list of recently typed URLs.
de.ro.HelpToolbar15:Das ist das URL-Schnellwahl Symbol.|MKlicken mit AUSWAHL öffnet eine Liste der zuletzt eingegebenen Web-Adressen.
fr.ro.HelpToolbar15:\Tl'icône de suggestion d'URL.|M\Souvrir une liste d'URLs tapées récemment.
it.ro.HelpToolbar15:\Tapri la lista dei siti visitati più recenti
nl.ro.HelpToolbar15:\TURL suggestion icon.|M\Sopen a list of recently typed URLs.
en.ro.HelpToolbar16:\Tthrobber.|MIt animates while this \w is active.
de.ro.HelpToolbar16:Das ist die Ladeaktivitätsanzeige.|MSie wird animiert, wenn NetSurf aktiv ist.
fr.ro.HelpToolbar16:\Tle pulseur.|MIl s'anime lorsque cette \w est active.
it.ro.HelpToolbar16:\Tthrobber animato durante le attività di rete
nl.ro.HelpToolbar16:\Tthrobber.|MIt animates while this \w is active.
 
en.ro.HelpStatus0:\Tstatus bar resizer.|MDrag to alter the size of the status bar.
de.ro.HelpStatus0:Das ist die Begrenzung der Statusanzeige.|MKlicken und Ziehen verändert die Länge der Statusanzeige.
fr.ro.HelpStatus0:\Tla glissière de la barre d'état.|MDéplacez-la pour changer la taille de la barre d'état.
it.ro.HelpStatus0:\Ttrascina per modificare la dimensione della barra di stato
nl.ro.HelpStatus0:\Tstatus bar resizer.|MDrag to alter the size of the status bar.
en.ro.HelpStatus1:\Tstatus bar.|MIt displays information on what the browser \w is doing.
de.ro.HelpStatus1:Das ist die Statusanzeige|MSie zeigt an, was gerade im Browserfenster geschieht.
fr.ro.HelpStatus1:\Tla barre d'état.|MElle affiche des informations sur ce que fait la \w de navigateur.
it.ro.HelpStatus1:\Tmostra informazioni relative alle attività del browser
nl.ro.HelpStatus1:\Tstatus bar.|MIt displays information on what the browser \w is doing.
 
en.ro.HelpIconMenu0:\Rview information about this software.
de.ro.HelpIconMenu0:Zeigt Informationen zu dieser Software.
fr.ro.HelpIconMenu0:\Rvoir des informations sur ce logiciel.
it.ro.HelpIconMenu0:\Rmostra le informazioni su NetSurf
nl.ro.HelpIconMenu0:\Rview information about this software.
en.ro.HelpIconMenu1:\Sview NetSurf's documentation.
de.ro.HelpIconMenu1:Lädt die NetSurf Dokumentation in einem neuen Browserfenster.
fr.ro.HelpIconMenu1:\Svoir la documentation de NetSurf.
it.ro.HelpIconMenu1:\Smostra la documentazione di NetSurf
nl.ro.HelpIconMenu1:\Sview NetSurf's documentation.
en.ro.HelpIconMenu2:\Ropen a window.
de.ro.HelpIconMenu2:Mauszeiger nach rechts bewegen, um ein Fenster zu öffnen.
fr.ro.HelpIconMenu2:\Rouvrir une fenêtre.
it.ro.HelpIconMenu2:\Rapri una finestra
nl.ro.HelpIconMenu2:\Ropen a window.
en.ro.HelpIconMenu2-0:\Renter an address to visit.
de.ro.HelpIconMenu2-0:Erlaubt die Eingabe einer Web-Adresse.
fr.ro.HelpIconMenu2-0:\Rentrer une adresse à visiter.
it.ro.HelpIconMenu2-0:\Rdigita un indirizzo da visitare
nl.ro.HelpIconMenu2-0:\Renter an address to visit.
en.ro.HelpIconMenu2-1:\Sopen the hotlist management \w.
de.ro.HelpIconMenu2-1:Klicken mit AUSWAHL öffnet die Hotlist.
fr.ro.HelpIconMenu2-1:\Souvrir la fenêtre de gestion des favoris.
it.ro.HelpIconMenu2-1:\Sapri la finestra dei segnalibri
nl.ro.HelpIconMenu2-1:\Sopen the hotlist management \w.
en.ro.HelpIconMenu2-2:\Sopen the global history \w.
de.ro.HelpIconMenu2-2:Klicken mit AUSWAHL öffnet das Fenster mit der globalen History.
fr.ro.HelpIconMenu2-2:\Souvrir la fenêtre d'historique global.
it.ro.HelpIconMenu2-2:\Smostra la cronologia globale
nl.ro.HelpIconMenu2-2:\Sopen the global history \w.
en.ro.HelpIconMenu2-3:\Sopen the cookie management \w.
de.ro.HelpIconMenu2-3:Klicken mit AUSWAHL öffnet die Cookie Verwaltung.
fr.ro.HelpIconMenu2-3:\Souvrir la fenêtre de gestion des cookies.
it.ro.HelpIconMenu2-3:\Sapri la finestra di gestione dei cookie
nl.ro.HelpIconMenu2-3:\Sopen the cookie management \w.
en.ro.HelpIconMenu3:\Sopen the Choices dialogue box.
de.ro.HelpIconMenu3:Öffnet einen Dialog mit Einstellungen für NetSurf.
fr.ro.HelpIconMenu3:\Souvrir la boîte de dialogue des Préférences.
it.ro.HelpIconMenu3:\Sapri una finestra di dialogo/scelta
nl.ro.HelpIconMenu3:\Sopen the Choices dialogue box.
en.ro.HelpIconMenu4:\Squit NetSurf.
de.ro.HelpIconMenu4:Beendet das Programm.|MAlle Browserfenster werden geschlossen. Downloads werden abgebrochen.
fr.ro.HelpIconMenu4:\Squitter NetSurf.
it.ro.HelpIconMenu4:\Schiudi NetSurf
nl.ro.HelpIconMenu4:\Squit NetSurf.
 
en.ro.HelpBrowserMenu0:\Rsee the options relating to the current page.
de.ro.HelpBrowserMenu0:Untermenü Seite.|MMenüpunkte beziehen sich auf die angezeigte Seite.
fr.ro.HelpBrowserMenu0:\Rvoir les options en rapport avec la page en cours.
it.ro.HelpBrowserMenu0:\Rmostra le opzioni relative a questa pagina
nl.ro.HelpBrowserMenu0:\Rsee the options relating to the current page.
en.ro.HelpBrowserMenu0-0:\Rsee information about the current page.
de.ro.HelpBrowserMenu0-0:Zeigt Informationen zur aktuellen Seite.
fr.ro.HelpBrowserMenu0-0:\Rvoir les informations concernant la page en cours.
it.ro.HelpBrowserMenu0-0:\Rmostra le informazioni di questa pagina
nl.ro.HelpBrowserMenu0-0:\Rsee information about the current page.
en.ro.HelpBrowserMenu0-1:\Rsave the current page as an HTML file.
de.ro.HelpBrowserMenu0-1:Abspeichern der Seite als HTML Datei.|MGespeichert wird nur der HTML Quellcode (keine Bilder etc.).
fr.ro.HelpBrowserMenu0-1:\Rsauver la page courante en fichier HTML.
it.ro.HelpBrowserMenu0-1:\Rsalva la pagina corrente come file HTML
nl.ro.HelpBrowserMenu0-1:\Rsave the current page as an HTML file.
en.ro.HelpBrowserMenu0-2:\Rsave the current page including all the images and style sheets used.
de.ro.HelpBrowserMenu0-2:Abspeichern der kompletten Seite.|MDer HTML Quellcode sowie alle Bilder und StyleSheets werden gespeichert.
fr.ro.HelpBrowserMenu0-2:\Rsauver la page courante y compris toutes les images et les feuilles de style utilisées.
it.ro.HelpBrowserMenu0-2:\Rsalva la pagina corrente includendo tutte le immagini ed i fogli di stile usati
nl.ro.HelpBrowserMenu0-2:\Rsave the current page including all the images and style sheets used.
en.ro.HelpBrowserMenu0-3:\Rsee the export options.
de.ro.HelpBrowserMenu0-3:Abspeichern der Seite in verschiedenen Formaten.
fr.ro.HelpBrowserMenu0-3:\Rvoir les options d'exportation.
it.ro.HelpBrowserMenu0-3:\Rmostra le opzioni di esportazione
nl.ro.HelpBrowserMenu0-3:\Rsee the export options.
en.ro.HelpBrowserMenu0-3-0:\Rexport the current page as a Drawfile.
de.ro.HelpBrowserMenu0-3-0:Exportieren der Seite als Draw Datei.
fr.ro.HelpBrowserMenu0-3-0:\Rexporter la page courante en Drawfile.
it.ro.HelpBrowserMenu0-3-0:\Resporta la pagina corrente come file Draw
nl.ro.HelpBrowserMenu0-3-0:\Rexport the current page as a Drawfile.
en.ro.HelpBrowserMenu0-3-1:\Rexport the current page as a plain text file.
de.ro.HelpBrowserMenu0-3-1:Exportieren der Seite als Text Datei.
fr.ro.HelpBrowserMenu0-3-1:\Rexporter la page courante en simple fichier texte.
it.ro.HelpBrowserMenu0-3-1:\Resporta la pagina corrente come file di testo
nl.ro.HelpBrowserMenu0-3-1:\Rexport the current page as a plain text file.
en.ro.HelpBrowserMenu0-4:\Rsave the address of the current page.
de.ro.HelpBrowserMenu0-4:Adresse der Seite speichern.
fr.ro.HelpBrowserMenu0-4:\Rsauver l'adresse de la page courante.
it.ro.HelpBrowserMenu0-4:\Rsalva l'indirizzo della pagina corrente
nl.ro.HelpBrowserMenu0-4:\Rsave the address of the current page.
en.ro.HelpBrowserMenu0-4-0:\Rsave the current address in Acorn URI format.
de.ro.HelpBrowserMenu0-4-0:Speichert die Adresse der Seite im Acorn URI Format.
fr.ro.HelpBrowserMenu0-4-0:\Rsauver l'adresse en cours au format Acorn URI.
it.ro.HelpBrowserMenu0-4-0:\Rsalva l'indirizzo corrente nel formato Acorn URI
nl.ro.HelpBrowserMenu0-4-0:\Rsave the current address in Acorn URI format.
en.ro.HelpBrowserMenu0-4-1:\Rsave the current address in Ant URL format.
de.ro.HelpBrowserMenu0-4-1:Speichert die Adresse der Seite im Ant URL Format.
fr.ro.HelpBrowserMenu0-4-1:\Rsauver l'adresse en cours au format Ant URL.
it.ro.HelpBrowserMenu0-4-1:\Rsalva l'indirizzo corrente nel formato Ant URL
nl.ro.HelpBrowserMenu0-4-1:\Rsave the current address in Ant URL format.
en.ro.HelpBrowserMenu0-4-2:\Rsave the current address as plain text.
de.ro.HelpBrowserMenu0-4-2:Speichert die Adresse der Seite als Text.
fr.ro.HelpBrowserMenu0-4-2:\Rsauver l'adresse courante en simple texte.
it.ro.HelpBrowserMenu0-4-2:\Rsalva l'indirizzo corrente come file di testo
nl.ro.HelpBrowserMenu0-4-2:\Rsave the current address as plain text.
en.ro.HelpBrowserMenu0-5:\Sopen the print dialogue box.
de.ro.HelpBrowserMenu0-5:Dialogfenster zum Drucken der Seite.
fr.ro.HelpBrowserMenu0-5:\Souvrir la boîte de dialogue d'impression.
it.ro.HelpBrowserMenu0-5:\Sapri la finestra di stampa
nl.ro.HelpBrowserMenu0-5:\Sopen the print dialogue box.
en.ro.HelpBrowserMenu0-6:\Sopen the current page in a new window.
de.ro.HelpBrowserMenu0-6:Öffnet die aktuelle Seite in einem neuen Fenster.
fr.ro.HelpBrowserMenu0-6:\Souvrir la page courante dans une nouvelle fenêtre.
it.ro.HelpBrowserMenu0-6:\Sapri la pagina corrente in una nuova finestra
nl.ro.HelpBrowserMenu0-6:\Sopen the current page in a new window.
en.ro.HelpBrowserMenu0-7:\Rsearch for instances of a string of text on the page.
de.ro.HelpBrowserMenu0-7:Erlaubt das Suchen einer Zeichenkette im Text des aktuellen Browserfensters.
fr.ro.HelpBrowserMenu0-7:\Rchercher un fragment de texte sur la page.
it.ro.HelpBrowserMenu0-7:\Rcerca una stringa di testo all'interno della pagina web
nl.ro.HelpBrowserMenu0-7:\Rsearch for instances of a string of text on the page.
en.ro.HelpBrowserMenu0-8:\Sview the source code of the current page in a text editor.
de.ro.HelpBrowserMenu0-8:Lädt den Quellcode der Seite in einen Editor.
fr.ro.HelpBrowserMenu0-8:\Svoir le code source de la page courante dans un éditeur de texte.
it.ro.HelpBrowserMenu0-8:\Smostra il sorgente della pagina
nl.ro.HelpBrowserMenu0-8:\Sview the source code of the current page in a text editor.
en.ro.HelpBrowserMenu1:\Rsee the options relating to the current item.
de.ro.HelpBrowserMenu1:Untermenü Objekt.|MMenöpunkte beziehen sich auf das aktuelle Objekt.
fr.ro.HelpBrowserMenu1:\Rvoir les options correspondant à l'objet courant.
it.ro.HelpBrowserMenu1:\Rmostra le opzioni relative al corrente oggetto
nl.ro.HelpBrowserMenu1:\Rsee the options relating to the current item.
en.ro.HelpBrowserMenu1-0-0:\Rsee information about the current item.
de.ro.HelpBrowserMenu1-0-0:Informationen zum aktuellen Objekt zeigen.
fr.ro.HelpBrowserMenu1-0-0:\Rvoir les informations sur l'objet en cours.
it.ro.HelpBrowserMenu1-0-0:\Rmostra le informazioni relative al corrente oggetto
nl.ro.HelpBrowserMenu1-0-0:\Rsee information about the current item.
en.ro.HelpBrowserMenu1-0-1:\Rsave the current item.
de.ro.HelpBrowserMenu1-0-1:Abspeichern des Objektes (Original).
fr.ro.HelpBrowserMenu1-0-1:\Rsauver l'objet courant.
it.ro.HelpBrowserMenu1-0-1:\Rsalva l'oggetto corrente
nl.ro.HelpBrowserMenu1-0-1:\Rsave the current item.
en.ro.HelpBrowserMenu1-0-2:\Rsee the export options.
de.ro.HelpBrowserMenu1-0-2:Optionen zum Export des aktuellen Objektes zeigen.
fr.ro.HelpBrowserMenu1-0-2:\Rvoir les options d'exportation.
it.ro.HelpBrowserMenu1-0-2:\Rmostra le opzioni di esportazione
nl.ro.HelpBrowserMenu1-0-2:\Rsee the export options.
en.ro.HelpBrowserMenu1-0-2-0:\Rsave the image as a Sprite.
de.ro.HelpBrowserMenu1-0-2-0:Abspeichern des Bildes als Sprite Datei.
fr.ro.HelpBrowserMenu1-0-2-0:\Rsauver l'image au format Sprite.
it.ro.HelpBrowserMenu1-0-2-0:\Rsalva l'immagine come file Sprite
nl.ro.HelpBrowserMenu1-0-2-0:\Rsave the image as a Sprite.
en.ro.HelpBrowserMenu1-0-2-1:\Rsave the image as a DrawFile
de.ro.HelpBrowserMenu1-0-2-1:\Rsave the image as a DrawFile
fr.ro.HelpBrowserMenu1-0-2-1:\Rsave the image as a DrawFile
it.ro.HelpBrowserMenu1-0-2-1:\Rsalva l'immagine come file Draw
nl.ro.HelpBrowserMenu1-0-2-1:\Rsave the image as a DrawFile
en.ro.HelpBrowserMenu1-0-3:\Rsave the address of the current item.
de.ro.HelpBrowserMenu1-0-3:Die Adresse des Objektes speichern.
fr.ro.HelpBrowserMenu1-0-3:\Rsauver l'adresse de l'objet courant.
it.ro.HelpBrowserMenu1-0-3:\Rsalva l'indirizzo del corrente oggetto
nl.ro.HelpBrowserMenu1-0-3:\Rsave the address of the current item.
en.ro.HelpBrowserMenu1-0-3-0:\Rsave the current item's address in Acorn URI format.
de.ro.HelpBrowserMenu1-0-3-0:Speichert die Adresse des Objektes im Acorn URI Format.
fr.ro.HelpBrowserMenu1-0-3-0:\Rsauver l'adresse de l'objet courant au format Acorn URI.
it.ro.HelpBrowserMenu1-0-3-0:\Rsalva l'indirizzo del corrente oggetto nel formato Acorn URI
nl.ro.HelpBrowserMenu1-0-3-0:\Rsave the current item's address in Acorn URI format.
en.ro.HelpBrowserMenu1-0-3-1:\Rsave the current item's address in Ant URL format.
de.ro.HelpBrowserMenu1-0-3-1:Speichert die Adresse des Objektes im Ant URL Format.
fr.ro.HelpBrowserMenu1-0-3-1:\Rsauver l'adresse de l'objet courant au format Ant URL.
it.ro.HelpBrowserMenu1-0-3-1:\Rsalva l'indirizzo del corrente oggetto nel formato Ant URL
nl.ro.HelpBrowserMenu1-0-3-1:\Rsave the current item's address in Ant URL format.
en.ro.HelpBrowserMenu1-0-3-2:\Rsave the current item's address as plain text.
de.ro.HelpBrowserMenu1-0-3-2:Speichert die Adresse des Objektes als Text.
fr.ro.HelpBrowserMenu1-0-3-2:\Rsauver l'adresse de l'objet courant en texte simple.
it.ro.HelpBrowserMenu1-0-3-2:\Rsalva l'indirizzo del corrente oggetto come file di testo
nl.ro.HelpBrowserMenu1-0-3-2:\Rsave the current item's address as plain text.
en.ro.HelpBrowserMenu1-0-4:\Sreload all the items on this page.
de.ro.HelpBrowserMenu1-0-4:Anklicken mit AUSWAHL um alle Objekte der Seite erneut zu laden.
fr.ro.HelpBrowserMenu1-0-4:\Srecharger tous les objets de cete page.
it.ro.HelpBrowserMenu1-0-4:\Sricarica tutti gli elementi di questa pagina
nl.ro.HelpBrowserMenu1-0-4:\Sreload all the items on this page.
en.ro.HelpBrowserMenu1-1:\Rsee the options relating to the current link.
de.ro.HelpBrowserMenu1-1:Optionen für den aktuellen Verweis
fr.ro.HelpBrowserMenu1-1:\Rsee the options relating to the current link.
it.ro.HelpBrowserMenu1-1:\Rmostra le opzioni relative al corrente link
nl.ro.HelpBrowserMenu1-1:\Rsee the options relating to the current link.
en.ro.HelpBrowserMenu1-1-0:\Rsave the current link.
de.ro.HelpBrowserMenu1-1-0:Die Adresse des aktuellen Verweises abspeichern.
fr.ro.HelpBrowserMenu1-1-0:\Rsave the current link.
it.ro.HelpBrowserMenu1-1-0:\Rsalva il link corrente
nl.ro.HelpBrowserMenu1-1-0:\Rsave the current link.
en.ro.HelpBrowserMenu1-1-0-0:\Rsave the link in Acorn URI format.
de.ro.HelpBrowserMenu1-1-0-0:Speichert die Adresse des Verweises im Acorn URI Format.
fr.ro.HelpBrowserMenu1-1-0-0:\Rsave the link in Acorn URI format.
it.ro.HelpBrowserMenu1-1-0-0:\Rsalva il link nel formato Acorn URI
nl.ro.HelpBrowserMenu1-1-0-0:\Rsave the link in Acorn URI format.
en.ro.HelpBrowserMenu1-1-0-1:\Rsave the link in Ant URL format.
de.ro.HelpBrowserMenu1-1-0-1:Speichert die Adresse des Verweises im Ant URL Format.
fr.ro.HelpBrowserMenu1-1-0-1:\Rsave the link in Ant URL format.
it.ro.HelpBrowserMenu1-1-0-1:\Rsalva il link nel formato Ant URL
nl.ro.HelpBrowserMenu1-1-0-1:\Rsave the link in Ant URL format.
en.ro.HelpBrowserMenu1-1-0-2:\Rsave the link as plain text.
de.ro.HelpBrowserMenu1-1-0-2:Speichert die Adresse des Verweises als Text.
fr.ro.HelpBrowserMenu1-1-0-2:\Rsave the link as plain text.
it.ro.HelpBrowserMenu1-1-0-2:\Rsalva il link come file di testo
nl.ro.HelpBrowserMenu1-1-0-2:\Rsave the link as plain text.
en.ro.HelpBrowserMenu1-1-1:\Sdownload from this link.
de.ro.HelpBrowserMenu1-1-1:Anklicken mit AUSWAHL startet einen Download von diesem Link.
fr.ro.HelpBrowserMenu1-1-1:\Sdownload from this link.
it.ro.HelpBrowserMenu1-1-1:\Sscarica da questo link
nl.ro.HelpBrowserMenu1-1-1:\Sdownload from this link.
en.ro.HelpBrowserMenu1-1-2:\Sopen this link in a new window.
de.ro.HelpBrowserMenu1-1-2:Anklicken mit AUSWAHL öffnet den Link in einem neuen Fenster.
fr.ro.HelpBrowserMenu1-1-2:\Sopen this link in a new window.
it.ro.HelpBrowserMenu1-1-2:\Sapri questo link in una nuova finestra
nl.ro.HelpBrowserMenu1-1-2:\Sopen this link in a new window.
en.ro.HelpBrowserMenu2:\Rsee the selection options.
de.ro.HelpBrowserMenu2:Optionen für die manuell markierten Webseitenbereiche
fr.ro.HelpBrowserMenu2:\Rsee the selection options.
it.ro.HelpBrowserMenu2:\Rmostra le opzioni di selezione
nl.ro.HelpBrowserMenu2:\Rsee the selection options.
en.ro.HelpBrowserMenu2-0:\Rsave the current selection.
de.ro.HelpBrowserMenu2-0:Die aktuell markierten Bereiche abspeichern.
fr.ro.HelpBrowserMenu2-0:\Rsave the current selection.
it.ro.HelpBrowserMenu2-0:\Rsalva la selezione corrente
nl.ro.HelpBrowserMenu2-0:\Rsave the current selection.
en.ro.HelpBrowserMenu2-1:\Scopy the selected text to the clipboard.
de.ro.HelpBrowserMenu2-1:Den markierten Text ins Clipboard kopieren.
fr.ro.HelpBrowserMenu2-1:\Scopy the selected text to the clipboard.
it.ro.HelpBrowserMenu2-1:\Scopia il testo selezionato nella clipboard
nl.ro.HelpBrowserMenu2-1:\Scopy the selected text to the clipboard.
en.ro.HelpBrowserMenu2-2:\Scut the selected text to the clipboard.
de.ro.HelpBrowserMenu2-2:Den markierten Text ausschneiden und ins Clipboard transferieren.
fr.ro.HelpBrowserMenu2-2:\Scut the selected text to the clipboard.
it.ro.HelpBrowserMenu2-2:\Staglia il testo selezionato nella clipboard
nl.ro.HelpBrowserMenu2-2:\Scut the selected text to the clipboard.
en.ro.HelpBrowserMenu2-3:\Spaste text from the clipboard.
de.ro.HelpBrowserMenu2-3:Text aus dem Clipboard einfügen.
fr.ro.HelpBrowserMenu2-3:\Spaste text from the clipboard.
it.ro.HelpBrowserMenu2-3:\Sincolla il testo dalla clipboard
nl.ro.HelpBrowserMenu2-3:\Spaste text from the clipboard.
en.ro.HelpBrowserMenu3:\Rsee the navigation options.
de.ro.HelpBrowserMenu3:Untermenü Navigieren.
fr.ro.HelpBrowserMenu3:\Rvoir les options de navigation.
it.ro.HelpBrowserMenu3:\Rmostra le opzioni di navigazione
nl.ro.HelpBrowserMenu3:\Rsee the navigation options.
en.ro.HelpBrowserMenu3-0:\Sreturn to the configured home page.
de.ro.HelpBrowserMenu3-0:Öffnet die Homepage im aktuellen Fenster.
fr.ro.HelpBrowserMenu3-0:\Srevenir à la page d'accueil configurée.
it.ro.HelpBrowserMenu3-0:\Storna alla pagina iniziale preconfigurata
nl.ro.HelpBrowserMenu3-0:\Sreturn to the configured home page.
en.ro.HelpBrowserMenu3-1:\Sgo back a page in the local history.|MForm information is not resubmitted.
de.ro.HelpBrowserMenu3-1:Schaltet zurück zur vorher dargestellten Seite.|MDie Seite wird dabei nicht aktualisiert.
fr.ro.HelpBrowserMenu3-1:\Sreculer d'une page dans l'historique local.|ML'information du formlaire n'est pas réenvoyée.
it.ro.HelpBrowserMenu3-1:\Storna indietro di una pagina nella cronologia locale.|MIl form non verrà reinviato.
nl.ro.HelpBrowserMenu3-1:\Sgo back a page in the local history.|MForm information is not resubmitted.
en.ro.HelpBrowserMenu3-2:\Sstep forward a page in the local history.|MForm information is not resubmitted.
de.ro.HelpBrowserMenu3-2:Schaltet zur nächsten Seite in der lokalen History Liste.|MDie Seite wird dabei nicht aktualisiert.
fr.ro.HelpBrowserMenu3-2:\Savancer d'une page dans l'historique local.|ML'information du formlaire n'est pas réenvoyée.
it.ro.HelpBrowserMenu3-2:\Svai avanti di una pagina nella cronologia locale.|MLe informazioni contenute nel form non verranno inviate.
nl.ro.HelpBrowserMenu3-2:\Sstep forward a page in the local history.|MForm information is not resubmitted.
en.ro.HelpBrowserMenu3-3:\Straverse up one level in the directory tree.
de.ro.HelpBrowserMenu3-3:Wechselt in das übergeordnete Verzeichnis in der Hierarchie des Verzeichnisbaumes.
fr.ro.HelpBrowserMenu3-3:\Straverse up one level in the directory tree.
it.ro.HelpBrowserMenu3-3:\Sscorri in alto di un livello rispetto all'albero della directory.
nl.ro.HelpBrowserMenu3-3:\Straverse up one level in the directory tree.
en.ro.HelpBrowserMenu3-4:\Sfetch the current page again.
de.ro.HelpBrowserMenu3-4:Lädt die aktuelle Seite erneut.|MDie Seite wird aktualisiert. Ältere Informationen zu dieser Seite, die noch im lokalen Zwischenpuffer gespeichert sind, werden dabei überschrieben.
fr.ro.HelpBrowserMenu3-4:\Srecommencer le chargement de la page courante.
it.ro.HelpBrowserMenu3-4:\Sottieni nuovamente la corrente pagina.
nl.ro.HelpBrowserMenu3-4:\Sfetch the current page again.
en.ro.HelpBrowserMenu3-5:\Sstop NetSurf from continuing to load this page.
de.ro.HelpBrowserMenu3-5:Unterbricht den Ladevorgang und alle anderen Prozesse im aktuellen Browserfenster.
fr.ro.HelpBrowserMenu3-5:\Sarrêter le chargement de la page par NetSurf.
it.ro.HelpBrowserMenu3-5:\Simpedisci a NetSurf di continuare a caricare questa pagina.
nl.ro.HelpBrowserMenu3-5:\Sstop NetSurf from continuing to load this page.
en.ro.HelpBrowserMenu4:\Rset the local display options.
de.ro.HelpBrowserMenu4:Untermenü Anzeige.|MFestlegen der Darstellungsparameter für das Browserfenster.
fr.ro.HelpBrowserMenu4:\Rdéfinir les options d'affichage locales.
it.ro.HelpBrowserMenu4:\Rimposta le opzioni di visualizzazione locale.
nl.ro.HelpBrowserMenu4:\Rset the local display options.
en.ro.HelpBrowserMenu4-0:\Rscale the page, affecting both text and images.
de.ro.HelpBrowserMenu4-0:Ändern der Größe der Darstellung. Beeinflußt werden Text und Bilder.
fr.ro.HelpBrowserMenu4-0:\Rredimensionner la page, y compris texte et images.
it.ro.HelpBrowserMenu4-0:\Rscala la pagina, questo agirà sia sul testo che sulle immagini.
nl.ro.HelpBrowserMenu4-0:\Rscale the page, affecting both text and images.
en.ro.HelpBrowserMenu4-1:\Rset the local image options.
de.ro.HelpBrowserMenu4-1:Optionen zur Anzeige von Bildern.
fr.ro.HelpBrowserMenu4-1:\Rdéfinir les options d'images locales.
it.ro.HelpBrowserMenu4-1:\Rimposta le opzioni relative alle immagini locali.
nl.ro.HelpBrowserMenu4-1:\Rset the local image options.
#HelpBrowserMen43-1-0:\Stoggle the display of foreground images.
en.ro.HelpBrowserMenu4-1-1:\Stoggle the display of background images.
de.ro.HelpBrowserMenu4-1-1:Schaltet Hintergrundbilder ein/aus.
fr.ro.HelpBrowserMenu4-1-1:\Safficher ou pas des images de fond.
it.ro.HelpBrowserMenu4-1-1:\Salterna la visualizzazione delle immagini di sfondo.
nl.ro.HelpBrowserMenu4-1-1:\Stoggle the display of background images.
en.ro.HelpBrowserMenu4-1-2:\Stoggle the display of animations.|MIf turned off, the first frame is displayed.
de.ro.HelpBrowserMenu4-1-2:Schaltet Animationen ein/aus.|MBei ausgeschalteter Animation, wird nur das erste Teilbild (Frame) angezeigt.
fr.ro.HelpBrowserMenu4-1-2:\Safficher ou pas des animations.|MSi les animations ne sont pas montrées, seule la première image est affichée.
it.ro.HelpBrowserMenu4-1-2:\Salterna la visualizzazione delle animazioni.|MSe disattivato verrà visualizzato solo il primo frame.
nl.ro.HelpBrowserMenu4-1-2:\Stoggle the display of animations.|MIf turned off, the first frame is displayed.
en.ro.HelpBrowserMenu4-2:\Rcontrol the display of NetSurf's toolbars.
de.ro.HelpBrowserMenu4-2:Optionen zur Anzeige von Kontroll- und Steuerelementen.
fr.ro.HelpBrowserMenu4-2:\Rcontroler l'affichage des barres d'outils de NetSurf.
it.ro.HelpBrowserMenu4-2:\Rcontrolla la visualizzazione delle barre strumenti di NetSurf.
nl.ro.HelpBrowserMenu4-2:\Rcontrol the display of NetSurf's toolbars.
en.ro.HelpBrowserMenu4-2-0:\Stoggle the display of the toolbar buttons.|MURL bar uses the remaining space.
de.ro.HelpBrowserMenu4-2-0:Schaltet die Schaltknöpfe am oberen Fensterrand ein/aus.|MDie Länge der Adressleiste wird angepaßt.
fr.ro.HelpBrowserMenu4-2-0:\Safficher ou pas les boutons de la barre d'outil.|MLa barre d'URL utilise l'espace restant.
it.ro.HelpBrowserMenu4-2-0:\Salterna la visualizzazione dei pulsanti della barra strumenti.|MLa barra URL coprirà lo spazio eccedente.
nl.ro.HelpBrowserMenu4-2-0:\Stoggle the display of the toolbar buttons.|MURL bar uses the remaining space.
en.ro.HelpBrowserMenu4-2-1:\Stoggle the display of the address (URL) bar.
de.ro.HelpBrowserMenu4-2-1:Schaltet die Adressleiste am oberen Fensterrand ein/aus.
fr.ro.HelpBrowserMenu4-2-1:\Safficher ou pas la barre d'adresse (URL).
it.ro.HelpBrowserMenu4-2-1:\Salterna la visualizzazione della barra indirizzi (URL).
nl.ro.HelpBrowserMenu4-2-1:\Stoggle the display of the address (URL) bar.
en.ro.HelpBrowserMenu4-2-2:\Stoggle the display of the throbber.|MURL bar uses the remaining space.
de.ro.HelpBrowserMenu4-2-2:Schaltet die Ladeaktivitätsanzeige am oberen Fensterrand ein/aus.|MDie Länge der Adressleiste wird angepaßt.
fr.ro.HelpBrowserMenu4-2-2:\Safficher le pulseur ou pas.|MLa barre d'URL utilise l'espace restant.
it.ro.HelpBrowserMenu4-2-2:\Salterna la visualizzazione del throbber.|MLa barra URL coprirà lo spazio eccedente.
nl.ro.HelpBrowserMenu4-2-2:\Stoggle the display of the throbber.|MURL bar uses the remaining space.
en.ro.HelpBrowserMenu4-2-3:\Stoggle the display of the status bar.|MHorizontal scroll bar uses the remaining width.
de.ro.HelpBrowserMenu4-2-3:Schaltet die Statusanzeige am unteren Fensterrand ein/aus.|MDie Länge des horizontalen Schiebebalkens wird angepaßt.
fr.ro.HelpBrowserMenu4-2-3:\Safficher la barre d'état ou pas.|MLa barre de défilement horizontal utilise la largeur restante.
it.ro.HelpBrowserMenu4-2-3:\Salterna la visualizzazione della barra di stato.|MLa barra di scrolling orizzontale coprirà la larghezza eccedente.
nl.ro.HelpBrowserMenu4-2-3:\Stoggle the display of the status bar.|MHorizontal scroll bar uses the remaining width.
en.ro.HelpBrowserMenu4-2-4:\Stoggle toolbar edit mode.
de.ro.HelpBrowserMenu4-2-4:Schaltet in den Modus zur Bearbeitung der Iconleiste am oberen Fensterrand.
fr.ro.HelpBrowserMenu4-2-4:\Schanger le mode d'édition de barre d'outils.
it.ro.HelpBrowserMenu4-2-4:\Salterna la modalità di modifica della barra strumenti.
nl.ro.HelpBrowserMenu4-2-4:\Stoggle toolbar edit mode.
en.ro.HelpBrowserMenu4-3:\Scontrol the manner in which the display is rendered.
de.ro.HelpBrowserMenu4-3:Einstellungen zur Berechnung der Seitendarstellung.
fr.ro.HelpBrowserMenu4-3:\Scontroler la façon d'afficher.
it.ro.HelpBrowserMenu4-3:\Scontrolla il modo in cui è resa l'esposizione.
nl.ro.HelpBrowserMenu4-3:\Scontrol the manner in which the display is rendered.
en.ro.HelpBrowserMenu4-3-0:\Stoggle whether animations are not displayed until all calculations are complete.
de.ro.HelpBrowserMenu4-3-0:Schaltet das Puffern von Objekten ein/aus.|MNachzuzeichnende Objekte, z.B. Bildanimationen oder Textbereiche, werden zwischengespeichert um Flackern zu vermeiden.
fr.ro.HelpBrowserMenu4-3-0:\Sdécider si les animations sont affichées quand tous les calculs sont terminés (ou avant).
it.ro.HelpBrowserMenu4-3-0:\Simposta la non visualizzazione delle animazioni fino al completamento dei calcoli.
nl.ro.HelpBrowserMenu4-3-0:\Stoggle whether animations are not displayed until all calculations are complete.
en.ro.HelpBrowserMenu4-3-1:\Stoggle whether everything is not displayed until all calculations are complete.
de.ro.HelpBrowserMenu4-3-1:Schaltet das Puffern der gesamten Seitenberechnung ein/aus.|MDie komplette Seite wird nach Berechnung und Aufbau zwischengespeichert. Das ist vorteilhaft bei großen Hintergrundbildern und vielen sich überschneidenden Seitenelementen.
fr.ro.HelpBrowserMenu4-3-1:\Sdécider si tout doit être affiché quand tous les calculs sont terminés (ou avant).
it.ro.HelpBrowserMenu4-3-1:\Simposta la non visualizzazione di tutto il processo fino al completamento dei calcoli.
nl.ro.HelpBrowserMenu4-3-1:\Stoggle whether everything is not displayed until all calculations are complete.
en.ro.HelpBrowserMenu4-4:\Smake your local display options the default options for NetSurf.
de.ro.HelpBrowserMenu4-4:Übernimmt die vorgenommenen Anzeigeeinstellungen als globale Standardwerte für die Darstellung aller weiteren Seiten.
fr.ro.HelpBrowserMenu4-4:\Spromouvoir vos options d'affichage locales en options par défaut pour NetSurf.
it.ro.HelpBrowserMenu4-4:\Simposta come predefinite tutte le impostazioni di visualizzazione.
nl.ro.HelpBrowserMenu4-4:\Smake your local display options the default options for NetSurf.
en.ro.HelpBrowserMenu4-5:\Rcontrol the default \w positioning.
de.ro.HelpBrowserMenu4-5:Kontrolle über Anordnung und Positionierung neuer Fenster.
fr.ro.HelpBrowserMenu4-5:\Rcontroler le positionnement de fenêtre par défaut.
it.ro.HelpBrowserMenu4-5:\Rimposta il posizionamento predefinito della finestra.
nl.ro.HelpBrowserMenu4-5:\Rcontrol the default \w positioning.
en.ro.HelpBrowserMenu4-5-0:\S make the current \w position the default.
de.ro.HelpBrowserMenu4-5-0:Die Position des aktuellen Fensters wird als globaler Standardwert übernommen. Alle nachfolgend neu geöffneten Fenster werden an dieser Position plaziert.
fr.ro.HelpBrowserMenu4-5-0:\Spromouvoir la position de fenêtre courante en celle par défault.
it.ro.HelpBrowserMenu4-5-0:\S imposta come predefinita la posizione corrente della finestra.
nl.ro.HelpBrowserMenu4-5-0:\Sto make the current \w position the default.
en.ro.HelpBrowserMenu4-5-1:\S toggle whether subsequent windows are staggered down the screen.
de.ro.HelpBrowserMenu4-5-1:Neu geöffnete Fenster werden nicht alle an der Standardposition sondern zueinander leicht versetzt plaziert.
fr.ro.HelpBrowserMenu4-5-1:\Sdécider si les fenêtres suivantes doivent être ouvertes en décalage à l'écran.
it.ro.HelpBrowserMenu4-5-1:\S imposta nel caso le finestre successive siano sfalsate rispetto alla parte bassa dello schermo.
nl.ro.HelpBrowserMenu4-5-1:\Sto toggle whether subsequent windows are staggered down the screen.
en.ro.HelpBrowserMenu4-5-2:\S toggle whether child windows copy the size and position of their parent.|MWhen off, all new windows open in the default position.
de.ro.HelpBrowserMenu4-5-2:Neue Fenster behalten die Größe des Fensters, aus dem heraus sie geöffnet werden, bei.
fr.ro.HelpBrowserMenu4-5-2:\Sdécider si les fenêtres-filles doivent être ouvertes à la même taille que celle de leurs parents.
it.ro.HelpBrowserMenu4-5-2:\S alterna nel caso le finestre figlie seguano la dimensione ed il posizionamento di quelle genitrici.|MSe disattivato tutte le finestre verranno aperte nel posizionamento predefinito.
nl.ro.HelpBrowserMenu4-5-2:\Sto toggle whether child windows copy the size and position of their parent.|MWhen off, all new windows open in the default position.
en.ro.HelpBrowserMenu4-5-3:\S return to the default \w positioning.
de.ro.HelpBrowserMenu4-5-3:Setzt die festgelegte Standardposition für Fenster auf einen in NetSurf voreingestellten Wert zurück.
fr.ro.HelpBrowserMenu4-5-3:\Srevenir au positionnement de fenêtre par défaut.
it.ro.HelpBrowserMenu4-5-3:\S ritorna al posizionamento della finestra predefinito.
nl.ro.HelpBrowserMenu4-5-3:\Sto return to the default \w positioning.
en.ro.HelpBrowserMenu5:\Raccess NetSurf's built in utilities.|MUtilities are tools such as the hotlist, history tree and various setup options.
de.ro.HelpBrowserMenu5:Untermenü Werkzeuge.|MEnthält verschiedene nützliche Zusatz- und Sonderfunktionen.
fr.ro.HelpBrowserMenu5:\Raccéder aux utilitaires intégrés à NetSurf.|MLes utilitaires sont des outils comme les favoris, l'historique arborescent et diverses options de configuration.
it.ro.HelpBrowserMenu5:\Raccesso a NetSurf attraverso le utilità.|MLe utilità sono strumenti simili ai segnalibri, gli alberi della cronologia e le altre opzioni di configurazione.
nl.ro.HelpBrowserMenu5:\Rto access NetSurf's built in utilities.|MUtilities are tools such as the hotlist, history tree and various setup options.
en.ro.HelpBrowserMenu5-0:\Rmanage the hotlist.
de.ro.HelpBrowserMenu5-0:Verwaltung der Hotlist.
fr.ro.HelpBrowserMenu5-0:\Rgérer les favoris.
it.ro.HelpBrowserMenu5-0:\Rgestisci i segnalibri.
nl.ro.HelpBrowserMenu5-0:\Rmanage the hotlist.
en.ro.HelpBrowserMenu5-0-0:\Sadd the current page to the hotlist.
de.ro.HelpBrowserMenu5-0-0:Anklicken trägt die Adresse der aktuellen Seite in die Hotlist ein.
fr.ro.HelpBrowserMenu5-0-0:\Sajouter la page en cours aux favoris.
it.ro.HelpBrowserMenu5-0-0:\Saggiungi la pagina corrente ai segnalibri
nl.ro.HelpBrowserMenu5-0-0:\Sadd the current page to the hotlist.
en.ro.HelpBrowserMenu5-0-1:\Sopen the hotlist management \w.
de.ro.HelpBrowserMenu5-0-1:Öffnet die Hotlist.
fr.ro.HelpBrowserMenu5-0-1:\Souvrir la \w de gestion des favoris.
it.ro.HelpBrowserMenu5-0-1:\Sapri la finestra del gestore dei segnalibri
nl.ro.HelpBrowserMenu5-0-1:\Sopen the hotlist management \w.
en.ro.HelpBrowserMenu5-1:\Rview the history options.
de.ro.HelpBrowserMenu5-1:Zugriff auf die History Funktionen.|MIn die History werden bereits besuchte Webseiten eingetragen. Dies erlaubt das einfache Wiederfinden einmal gesehener Web-Inhalte.
fr.ro.HelpBrowserMenu5-1:\Rview the history options.
it.ro.HelpBrowserMenu5-1:\Rmostra le opzioni della cronologia
nl.ro.HelpBrowserMenu5-1:\Rview the history options.
en.ro.HelpBrowserMenu5-1-0:\Sopen the local history \w.
de.ro.HelpBrowserMenu5-1-0:Anklicken mit AUSWAHL öffnet das Fenster mit der lokalen History.|MIn der lokalen History werden alle Webseiten notiert, die mit dem aktuellen Browserfenster bereits besucht worden waren.
fr.ro.HelpBrowserMenu5-1-0:\Souvrir la \w d'historique local.
it.ro.HelpBrowserMenu5-1-0:\Sapri la cronologia locale
nl.ro.HelpBrowserMenu5-1-0:\Sopen the local history \w.
en.ro.HelpBrowserMenu5-1-1:\Sopen the global history \w.
de.ro.HelpBrowserMenu5-1-1:Anklicken mit AUSWAHL öffnet das Fenster mit der globalen History.|MIn der globalen History werden alle mit NetSurf besuchten Webseiten notiert.
fr.ro.HelpBrowserMenu5-1-1:\Souvrir la fenêtre d'historique global.
it.ro.HelpBrowserMenu5-1-1:\Sapri la cronologia globale
nl.ro.HelpBrowserMenu5-1-1:\Sopen the global history \w.
en.ro.HelpBrowserMenu5-2:\Rmanage your cookies.
de.ro.HelpBrowserMenu5-2:Cookies bearbeiten.
fr.ro.HelpBrowserMenu5-2:\Rgérer vos favoris.
it.ro.HelpBrowserMenu5-2:\Rgestisci i tuoi cookie
nl.ro.HelpBrowserMenu5-2:\Rmanage your cookies.
en.ro.HelpBrowserMenu5-2-0:\Sopen the cookie management \w.
de.ro.HelpBrowserMenu5-2-0:Anklicken um die gespeicherten Cookies anzusehen und zu bearbeiten.
fr.ro.HelpBrowserMenu5-2-0:\Souvrir la fenêtre de gestion des cookies.
it.ro.HelpBrowserMenu5-2-0:\Sapri ila finestra del gestore dei cookie
nl.ro.HelpBrowserMenu5-2-0:\Sopen the cookie management \w.
en.ro.HelpBrowserMenu6:\Rsee the help resources available.
de.ro.HelpBrowserMenu6:Untermenü Hilfe.|MZeigt Informationen zu und über NetSurf.
fr.ro.HelpBrowserMenu6:\Rvoir l'aide disponible.
it.ro.HelpBrowserMenu6:\Rmostra la documentazione disponibile
nl.ro.HelpBrowserMenu6:\Rsee the help resources available.
en.ro.HelpBrowserMenu6-0:\Sopen the documentation contents page in a new \w.
de.ro.HelpBrowserMenu6-0:Öffnet die NetSurf Dokumentation in einem neuen Browserfenster.
fr.ro.HelpBrowserMenu6-0:\Souvrir la page de documentation dans une nouvelle fenêtre.
it.ro.HelpBrowserMenu6-0:\Sapri i contenuti della documentazione in una nuova finestra
nl.ro.HelpBrowserMenu6-0:\Sopen the documentation contents page in a new \w.
en.ro.HelpBrowserMenu6-1:\Sopen the user guide in a new \w.
de.ro.HelpBrowserMenu6-1:Öffnet das NetSurf Handbuch in einem neuen Browserfenster.
fr.ro.HelpBrowserMenu6-1:\Souvrir le guide de l'utilisateur dans une nouvelle fenêtre.
it.ro.HelpBrowserMenu6-1:\Sapri la guida in linea in una nuova finestra
nl.ro.HelpBrowserMenu6-1:\Sopen the user guide in a new \w.
en.ro.HelpBrowserMenu6-2:\Sopen the user information page in a new \w.
de.ro.HelpBrowserMenu6-2:Öffnet eine Seite mit allgemeinen Informationen zu NetSurf in einem neuen Browserfenster.
fr.ro.HelpBrowserMenu6-2:\Souvrir la page d'information de l'utilisateur dans une nouvelle fenêtre.
it.ro.HelpBrowserMenu6-2:\Sapri la pagina delle informazioni utente in una nuova finestra
nl.ro.HelpBrowserMenu6-2:\Sopen the user information page in a new \w.
en.ro.HelpBrowserMenu6-3:\Sopen the about:credits page in a new \w.
de.ro.HelpBrowserMenu6-3:\Sopen the about:credits page in a new \w.
fr.ro.HelpBrowserMenu6-3:\Sopen the about:credits page in a new \w.
it.ro.HelpBrowserMenu6-3:\Sapri la pagina about:credits in una nuova finestra
nl.ro.HelpBrowserMenu6-3:\Sopen the about:credits page in a new \w.
en.ro.HelpBrowserMenu6-4:\Sopen the about:licence page in a new \w.
de.ro.HelpBrowserMenu6-4:\Sopen the about:licence page in a new \w.
fr.ro.HelpBrowserMenu6-4:\Sopen the about:licence page in a new \w.
it.ro.HelpBrowserMenu6-4:\Sapri la pagina about:licence in una nuova finestra
nl.ro.HelpBrowserMenu6-4:\Sopen the about:licence page in a new \w.
en.ro.HelpBrowserMenu6-5:\Srun Help.
de.ro.HelpBrowserMenu6-5:Lädt die interaktive Hilfe.
fr.ro.HelpBrowserMenu6-5:\Slancer Help.
it.ro.HelpBrowserMenu6-5:\Savvia la guida in linea
nl.ro.HelpBrowserMenu6-5:\Srun Help.
 
en.ro.HelpBrowser-1:Click \s on a link to follow it.|MClick \a on a link to open it in a new \w.|MShift+\s click on a link to download the link target contents.|MShift+\a click to save the link target address.
de.ro.HelpBrowser-1:Das ist ein Browserfenster.|MEinen Link mit AUSWAHL anklicken, um ihm zu folgen.|MEinen Link mit SPEZIAL anklicken, um ihn in einem neuen Fenster zu öffnen.|MShift+AUSWAHL über einem Verweis lädt den verlinkten Inhalt herunter.|MShift+SPEZIAL über einem Link klicken zum Speichern der Adresse des Verweises.
fr.ro.HelpBrowser-1:Cliquer \s sur un lien pour le suivre.|MCliquer \a sur un lien pour l'ouvrir dans une nouvelle \w.|MShift+\s click on a link to download the link target contents.|MShift+\a click to save the link target address.
it.ro.HelpBrowser-1:Clicca \s sul link per procedere.|MClicca \a in un link per aprirlo in una nuova finestra|MShift+\s clicca sul link per scaricarne i contenuti.|MShift+\a clicca per salvare l'indirizzo del link.
nl.ro.HelpBrowser-1:Click \s on a link to follow it.|MClick \a on a link to open it in a new \w.|MShift+\s click on a link to download the link target contents.|MShift+\a click to save the link target address.
 
en.ro.HelpIconbar:\TNetSurf icon.|M\Sopen a new browser \w.|M\Aopen the hotlist management \w.
de.ro.HelpIconbar:Das ist das NetSurf Icon.|MKlicken mit AUSWAHL öffnet ein neues Browserfenster.|MKlicken mit SPEZIAL öffnet die Hotlist.
fr.ro.HelpIconbar:\Tl'icône de NetSurf.|M\Souvrir une nouvelle \w de navigateur.|M\Aouvrir la fenêtre de gestion des favoris.
it.ro.HelpIconbar:\TIcona di NetSurf.|M\Sapri una nuova finestra|M\Aapri la finestra del gestore dei segnalibri
nl.ro.HelpIconbar:\TNetSurf icon.|M\Sopen a new browser \w.|M\Aopen the hotlist management \w.
en.ro.HelpHistory:Use this \w to navigate around the local history tree.|M\Son a thumbnail to return to that page.
de.ro.HelpHistory:Die History zeigt alle in dieser Sitzung besuchten Seiten.|MKlicken mit AUSWAHL auf eine Symbolgrafik kehrt zurück zur jeweiligen Seite.
fr.ro.HelpHistory:Utiliser cette \w pour naviguer dans l'historique arborescent local.|M\Ssur une vignette pour revenir à cette page.
it.ro.HelpHistory:Usa questa finestra per navigare all'interno dell'albero della cronologia locale.|M\Ssulla miniatura per tornare a quella pagina.
nl.ro.HelpHistory:Use this \w to navigate around the local history tree.|M\Son a thumbnail to return to that page.
 
en.ro.HelpPrint:Use this \w to print the page.
de.ro.HelpPrint:Ãœber dieses Fenster kann die Seite gedruckt werden.
fr.ro.HelpPrint:Utiliser cette fenêtre pour imprimer cette page.
it.ro.HelpPrint:Usa questa finestra per le funzionalità di stampa della pagina.
nl.ro.HelpPrint:Use this \w to print the page.
 
en.ro.HelpSaveAs0:Drag SELECT this icon to the directory in which you want to save the file.
de.ro.HelpSaveAs0:Symbol mit AUSWAHL festhalten und in ein Verzeichnisfenster ziehen, um die Datei zu speichern.
fr.ro.HelpSaveAs0:Déposer cette icône dans le repertoire où vous voulez sauver le fichier.
it.ro.HelpSaveAs0:Seleziona e sposta questa icona nella directory nella quale si desidera salvare il file.
nl.ro.HelpSaveAs0:Drag SELECT this icon to the directory in which you want to save the file.
en.ro.HelpSaveAs1:This is the filename under which this document will be saved.
de.ro.HelpSaveAs1:Das ist der Name unter dem die Datei gespeichert wird.
fr.ro.HelpSaveAs1:Ceci est le nom de fichier sous lequel le document sera sauvé.
it.ro.HelpSaveAs1:Questo è il nome del file con il quale il documento verrà salvato.
nl.ro.HelpSaveAs1:This is the filename under which this document will be saved.
en.ro.HelpSaveAs2:\Ssave the file with the current filename.|MIf a full path is not set, you must drag the icon to a directory.
de.ro.HelpSaveAs2:Klicken mit AUSWAHL speichert die Datei unter angezeigtem Pfad und Namen.|MWird kein voller Dateipfad angezeigt, muß die Datei per Drag & Drop gespeichert werden.
fr.ro.HelpSaveAs2:\Ssauver le fichier avec le nom de fichier en cours.|MSi le nom de chemin n'est pas complet, il vous faudra déposer l'icône dans un répertoire.
it.ro.HelpSaveAs2:\Ssalva il file usando il suo nome corrente.|MNel caso il percorso completo non sia impostato sposta l'icona nella directory.
nl.ro.HelpSaveAs2:\Ssave the file with the current filename.|MIf a full path is not set, you must drag the icon to a directory.
en.ro.HelpSaveAs3:\Sclose this \w without saving.
de.ro.HelpSaveAs3:Klicken mit AUSWAHL um nicht zu speichern.
fr.ro.HelpSaveAs3:\Sfermer cette \w sans sauvegarder.
it.ro.HelpSaveAs3:\Schiudi questa finestra senza salvare.
nl.ro.HelpSaveAs3:\Sclose this \w without saving.
 
en.ro.HelpScaleView:Use this \w to change the scale the page is displayed at.
de.ro.HelpScaleView:Mit diesem Dialog kann die Darstellung der Seite vergrößert oder verkleinert werden.
fr.ro.HelpScaleView:Utiliser cette \w pour changer l'échelle d'affichage.
it.ro.HelpScaleView:Usa questa finestra per modificare la scala di visualizzazione della pagina.
nl.ro.HelpScaleView:Use this \w to change the scale the page is displayed at.
en.ro.HelpScaleView1:Enter the scale you wish the page to be displayed at.
de.ro.HelpScaleView1:Gewünschte Skalierung hier eingeben.
fr.ro.HelpScaleView1:Saisissez l'échelle à laquelle vous voulez afficher cette page.
it.ro.HelpScaleView1:Inserisci la scala di visualizzazione preferita.
nl.ro.HelpScaleView1:Enter the scale you wish the page to be displayed at.
en.ro.HelpScaleView2:\Sreduce the scale, 10% at a time.
de.ro.HelpScaleView2:Klicken mit AUSWAHL um die Skalierung um 10% zu verringern.
fr.ro.HelpScaleView2:\Sréduire l'échelle, par pas de 10%.
it.ro.HelpScaleView2:\Sdecrementa la scala di un 10% alla volta.
nl.ro.HelpScaleView2:\Sreduce the scale, 10% at a time.
en.ro.HelpScaleView3:\Sincrease the scale, 10% at a time.
de.ro.HelpScaleView3:Klicken mit AUSWAHL um die Skalierung um 10% zu erhöhen.
fr.ro.HelpScaleView3:\Saugmenter l'échelle, par pas de 10%.
it.ro.HelpScaleView3:\Sincrementa la scala di un 10% alla volta.
nl.ro.HelpScaleView3:\Sincrease the scale, 10% at a time.
en.ro.HelpScaleView5:\Sautomatically choose a scale of 75%.
de.ro.HelpScaleView5:Stellt einen Skalierungswert von 75% ein.
fr.ro.HelpScaleView5:\Sdirectement choisir une échelle de 75%.
it.ro.HelpScaleView5:\Sscegli una scala automatica del 75%.
nl.ro.HelpScaleView5:\Sautomatically choose a scale of 75%.
en.ro.HelpScaleView6:\Sautomatically choose a scale of 100%.
de.ro.HelpScaleView6:Stellt einen Skalierungswert von 100% ein.
fr.ro.HelpScaleView6:\Sdirectement choisir une échelle de 100%.
it.ro.HelpScaleView6:\Sscegli una scala automatica del 100%.
nl.ro.HelpScaleView6:\Sautomatically choose a scale of 100%.
en.ro.HelpScaleView7:\Sautomatically choose a scale of 150%.
de.ro.HelpScaleView7:Stellt einen Skalierungswert von 150% ein.
fr.ro.HelpScaleView7:\Sdirectement choisir une échelle de 150%.
it.ro.HelpScaleView7:\Sscegli una scala automatica del 150%.
nl.ro.HelpScaleView7:\Sautomatically choose a scale of 150%.
en.ro.HelpScaleView8:\Sautomatically choose a scale of 200%.
de.ro.HelpScaleView8:Stellt einen Skalierungswert von 200% ein.
fr.ro.HelpScaleView8:\Sdirectement choisir une échelle de 200%.
it.ro.HelpScaleView8:\Sscegli una scala automatica del 200%.
nl.ro.HelpScaleView8:\Sautomatically choose a scale of 200%.
en.ro.HelpScaleView9:\Scancel changes.|MThe current scale will not be changed.
de.ro.HelpScaleView9:Klicken mit AUSWAHL um die Skalierung nicht durchzuführen.|MDas Dialogfenster wird geschlossen.|MDie Darstellung der Seite wird unverändert beibehalten.
fr.ro.HelpScaleView9:\Sannuler les changements.|ML'échelle en cours ne sera pas modifiée.
it.ro.HelpScaleView9:\Sannulla tutte le modifiche.|MLa corrente scala non verrà modificata.
nl.ro.HelpScaleView9:\Scancel changes.|MThe current scale will not be changed.
en.ro.HelpScaleView10:\Schange the view to the scale you have chosen.
de.ro.HelpScaleView10:Klicken mit AUSWAHL um die Seite skaliert darzustellen.|MDie Seite wird in der gewählten Vergrößerung angezeigt.
fr.ro.HelpScaleView10:\Svalider le changement d'échelle.
it.ro.HelpScaleView10:\Smodifica la visualizzazione della scala prescelta.
nl.ro.HelpScaleView10:\Schange the view to the scale you have chosen.
 
en.ro.HelpSearch:Use this \w to search for text within the page.
de.ro.HelpSearch:Dialogfenster zum Suchen von Text innerhalb der dargestellten Seite.
fr.ro.HelpSearch:Utiliser cette fenêtre pour faire une recherche textuelle sur cette page.
it.ro.HelpSearch:Use this \w to search for text within the page.
nl.ro.HelpSearch:Use this \w to search for text within the page.
en.ro.HelpSearch0:Enter the search text. # matches any single character, * matches 0 or more characters.
de.ro.HelpSearch0:Suchtext hier eingeben. # steht für exakt ein beliebiges Zeichen. * steht für 0 oder mehrere Zeichen.
fr.ro.HelpSearch0:Entrer la chaîne de recherche. # remplace n'importe quel caractère, * correspond à 0 ou plus caractères.
it.ro.HelpSearch0:Enter the search text. # matches any single character, * matches 0 or more characters.
nl.ro.HelpSearch0:Enter the search text. # matches any single character, * matches 0 or more characters.
en.ro.HelpSearch1:Choose whether the search should regard upper and lower case characters as different.
de.ro.HelpSearch1:Wählt ob nach Groß- und Kleinschreibung unterschieden werden soll.
fr.ro.HelpSearch1:Choisir si la recherche accorde de l'importance à la casse (minuscules/MAJUSCULES).
it.ro.HelpSearch1:Choose whether the search should regard upper and lower case characters as different.
nl.ro.HelpSearch1:Choose whether the search should regard upper and lower case characters as different.
en.ro.HelpSearch2:\Smove to the next match.
de.ro.HelpSearch2:Klicken mit AUSWAHL findet den nächsten Treffer.
fr.ro.HelpSearch2:\Schercher l'occurence suivante.
it.ro.HelpSearch2:\Smove to the next match.
nl.ro.HelpSearch2:\Smove to the next match.
en.ro.HelpSearch3:\Smove to the previous match.
de.ro.HelpSearch3:Klicken mit AUSWAHL sucht rückwärts im Text.
fr.ro.HelpSearch3:\Schercher l'occurence précédente.
it.ro.HelpSearch3:\Smove to the previous match.
nl.ro.HelpSearch3:\Smove to the previous match.
en.ro.HelpSearch4:\Sstop searching and close this \w.
de.ro.HelpSearch4:Klicken mit AUSWAHL bricht die Suche ab und schließt das Fenster.
fr.ro.HelpSearch4:\Sarrêter la recherche et fermer cette fenêtre.
it.ro.HelpSearch4:\Sstop searching and close this \w.
nl.ro.HelpSearch4:\Sstop searching and close this \w.
 
en.ro.HelpHotFolder:Use this \w to set the directory name.
de.ro.HelpHotFolder:Dieses Fenster verwenden, um den Verzeichnis-Namen festzulegen.
fr.ro.HelpHotFolder:Utiliser cette \w pour définir le nom de répertoire.
it.ro.HelpHotFolder:Use this \w to set the directory name.
nl.ro.HelpHotFolder:Use this \w to set the directory name.
en.ro.HelpHotEntry:Use this \w to set the entry details.
de.ro.HelpHotEntry:Dieses Fenster verwenden, um die Details des Eintrages festzulegen.
fr.ro.HelpHotEntry:Utiliser cette \w pour définir les détails de cette entrée.
it.ro.HelpHotEntry:Use this \w to set the entry details.
nl.ro.HelpHotEntry:Use this \w to set the entry details.
en.ro.HelpHotlist:\Thotlist management window.
de.ro.HelpHotlist:Das ist das Hotlist Fenster.
fr.ro.HelpHotlist:\Tla fenêtre de gestion des favoris.
it.ro.HelpHotlist:\Thotlist management window.
nl.ro.HelpHotlist:\Thotlist management window.
en.ro.HelpHotlist0:\Sopen this directory.
de.ro.HelpHotlist0:Klicken mit AUSWAHL öffnet das Verzeichnis.
fr.ro.HelpHotlist0:\Souvrir ce répertoire.
it.ro.HelpHotlist0:\Sopen this directory.
nl.ro.HelpHotlist0:\Sopen this directory.
en.ro.HelpHotlist1:\Sclose this directory.
de.ro.HelpHotlist1:Klicken mit AUSWAHL schließt das Verzeichnis.
fr.ro.HelpHotlist1:\Sfermer ce répertoire.
it.ro.HelpHotlist1:\Sclose this directory.
nl.ro.HelpHotlist1:\Sclose this directory.
en.ro.HelpHotlist2:\Sshow the entry details.
de.ro.HelpHotlist2:Klicken mit AUSWAHL zeigt die Zusatzinformationen zu diesem Eintrag.
fr.ro.HelpHotlist2:\Smontrer les détails de cette entrée.
it.ro.HelpHotlist2:\Sshow the entry details.
nl.ro.HelpHotlist2:\Sshow the entry details.
en.ro.HelpHotlist3:\Shide the entry details.
de.ro.HelpHotlist3:Klicken mit AUSWAHL schließt die Zusatzanzeige.
fr.ro.HelpHotlist3:\Scacher les détails de cette entrée.
it.ro.HelpHotlist3:\Shide the entry details.
nl.ro.HelpHotlist3:\Shide the entry details.
en.ro.HelpHotlist4:\Sselect this directory.|MDouble-click \s to open this directory.
de.ro.HelpHotlist4:Klicken mit AUSWAHL markiert dieses Verzeichnis.|MDoppelklicken um das Verzeichnis zu öffnen.
fr.ro.HelpHotlist4:\Ssélectionner ce répertoire.|MDouble-cliquer \s pour ouvrir ce répertoire.
it.ro.HelpHotlist4:\Sselect this directory.|MDouble-click \s to open this directory.
nl.ro.HelpHotlist4:\Sselect this directory.|MDouble-click \s to open this directory.
en.ro.HelpHotlist5:\Sselect this entry.|MDouble-click \s to launch this URL.
de.ro.HelpHotlist5:Klicken mit AUSWAHL markiert diesen Eintrag.|MDoppelklicken öffnet diesen Eintrag in einem neuen Browserfenster.
fr.ro.HelpHotlist5:\Ssélectionner cette entrée.|MDouble-cliquer \s pour lancer cette URL.
it.ro.HelpHotlist5:\Sselect this entry.|MDouble-click \s to launch this URL.
nl.ro.HelpHotlist5:\Sselect this entry.|MDouble-click \s to launch this URL.
en.ro.HelpHotlist6:Release the mouse buttons to complete your selection.
de.ro.HelpHotlist6:Maustasten loslassen, um die Auswahl abzuschließen.
fr.ro.HelpHotlist6:Lâcher les boutons de souris pour terminer votre sélection.
it.ro.HelpHotlist6:Release the mouse buttons to complete your selection.
nl.ro.HelpHotlist6:Release the mouse buttons to complete your selection.
en.ro.HelpHotlist7:Release the mouse buttons to move the selection.
de.ro.HelpHotlist7:Maustasten loslassen, um das Verschieben auszuführen.
fr.ro.HelpHotlist7:Lâcher les boutons de souris pour déplacer votre sélection.
it.ro.HelpHotlist7:Release the mouse buttons to move the selection.
nl.ro.HelpHotlist7:Release the mouse buttons to move the selection.
 
en.ro.HelpHotToolbar0:\Tdelete button.|M\Sdelete the current selection.
de.ro.HelpHotToolbar0:Löscht die markierten Einträge und Verzeichnisse.
fr.ro.HelpHotToolbar0:\Tle bouton Supprimer.|M\Ssupprimer la sélection courante.
it.ro.HelpHotToolbar0:\Tdelete button.|M\Sdelete the current selection.
nl.ro.HelpHotToolbar0:\Tdelete button.|M\Sdelete the current selection.
en.ro.HelpHotToolbar1:\Texpand entries button.|M\Sexpand all addresses in the hotlist.|M\Acollapse all addresses in the hotlist.|MExpanded addresses show additional details, such as a visit counter.
de.ro.HelpHotToolbar1:Expandiert Einträge.|MKlicken mit AUSWAHL expandiert alle / alle markierten Einträge.|MKlicken mit SPEZIAL faltet alle / alle markierten Einträge zusammen.|MBei expandierten Einträgen werden zusätzliche Informationen angezeigt.
fr.ro.HelpHotToolbar1:\Tle bouton de déploiement des entrées.|M\Sdéployer toutes les entrées ou seulement celle de la sélection courante.|M\ARegrouper toutes les entrées ou seulement celles de la sélection courante.|MLes entrées déployées affichent des infos supplémentaires, comme un compteur de visite.
it.ro.HelpHotToolbar1:\Texpand entries button.|M\Sexpand all addresses in the hotlist.|M\Acollapse all addresses in the hotlist.|MExpanded addresses show additional details, such as a visit counter.
nl.ro.HelpHotToolbar1:\Texpand entries button.|M\Sexpand all addresses in the hotlist.|M\Acollapse all addresses in the hotlist.|MExpanded addresses show additional details, such as a visit counter.
en.ro.HelpHotToolbar2:\Topen directories button.|M\Sopen all directories in the hotlist.|M\Aclose all directories in the hotlist.
de.ro.HelpHotToolbar2:Öffnet Verzeichnisse.|MKlicken mit AUSWAHL öffnet alle / alle markierten Verzeichnisse.|MKlicken mit SPEZIAL schließt alle / alle markierten Verzeichnisse.
fr.ro.HelpHotToolbar2:\Tle bouton d'ouverture de répertoires.|M\Souvrir tous les répertoires ou seulement ceux de la sélection courante.|M\Afermer tous les répertoires ou seulement ceux de la sélection courante.
it.ro.HelpHotToolbar2:\Topen directories button.|M\Sopen all directories in the hotlist.|M\Aclose all directories in the hotlist.
nl.ro.HelpHotToolbar2:\Topen directories button.|M\Sopen all directories in the hotlist.|M\Aclose all directories in the hotlist.
en.ro.HelpHotToolbar3:\Tlaunch button.|M\Slaunch the current selection.
de.ro.HelpHotToolbar3:Lädt alle markierten Einträge in jeweils ein neues Browserfenster.
fr.ro.HelpHotToolbar3:\Tle bouton de lancement.|M\Slancer (ouvrir) la sélection en cours.
it.ro.HelpHotToolbar3:\Tlaunch button.|M\Slaunch the current selection.
nl.ro.HelpHotToolbar3:\Tlaunch button.|M\Slaunch the current selection.
en.ro.HelpHotToolbar4:\Tcreate button.|M\Screate a new directory.
de.ro.HelpHotToolbar4:Erzeugt neue Einträge oder Verzeichnisse.|MKlicken mit AUSWAHL erstellt ein neues Verzeichnis.
fr.ro.HelpHotToolbar4:\Tle bouton Créer.|M\Scréer un nouveau répertoire.
it.ro.HelpHotToolbar4:\Tcreate button.|M\Screate a new directory.
nl.ro.HelpHotToolbar4:\Tcreate button.|M\Screate a new directory.
 
en.ro.HelpHotlistMenu0:\Rperform an operation on the hotlist.
de.ro.HelpHotlistMenu0:Untermenü Hotlist. Bearbeiten der Hotlist.
fr.ro.HelpHotlistMenu0:\Raccomplir une opération sur les favoris.
it.ro.HelpHotlistMenu0:\Rperform an operation on the hotlist.
nl.ro.HelpHotlistMenu0:\Rperform an operation on the hotlist.
en.ro.HelpHotlistMenu0-0:\Rcreate a new item.
de.ro.HelpHotlistMenu0-0:Neues Element in die Hotlist einfügen.
fr.ro.HelpHotlistMenu0-0:\Rcréer un nouvel item.
it.ro.HelpHotlistMenu0-0:\Rcreate a new item.
nl.ro.HelpHotlistMenu0-0:\Rcreate a new item.
en.ro.HelpHotlistMenu0-0-0:\Rcreate a new directory.
de.ro.HelpHotlistMenu0-0-0:Neues Verzeichnis anlegen.
fr.ro.HelpHotlistMenu0-0-0:\Rcréer un nouveau répertoire.
it.ro.HelpHotlistMenu0-0-0:\Rcrea una nuova directory.
nl.ro.HelpHotlistMenu0-0-0:\Rcreate a new directory.
en.ro.HelpHotlistMenu0-0-1:\Rcreate a new address.
de.ro.HelpHotlistMenu0-0-1:Neuen Eintrag erstellen.
fr.ro.HelpHotlistMenu0-0-1:\Rcréer une nouvelle adresse.
it.ro.HelpHotlistMenu0-0-1:\Rcrea un nuovo indirizzo.
nl.ro.HelpHotlistMenu0-0-1:\Rcreate a new address.
en.ro.HelpHotlistMenu0-1:\Rexport the hotlist as an HTML file.
de.ro.HelpHotlistMenu0-1:Die gesamte Hotlist als HTML Datei speichern.
fr.ro.HelpHotlistMenu0-1:\Rexporter les favoris en fichier HTML.
it.ro.HelpHotlistMenu0-1:\Rexport the hotlist as an HTML file.
nl.ro.HelpHotlistMenu0-1:\Rexport the hotlist as an HTML file.
en.ro.HelpHotlistMenu0-2:\Rexpand items within the hotlist.
de.ro.HelpHotlistMenu0-2:Öffnen von Verzeichnissen und Anzeigen von Zusatzinformationen.
fr.ro.HelpHotlistMenu0-2:\Rdéployer les items dans la liste des favoris.
it.ro.HelpHotlistMenu0-2:\Rexpand items within the hotlist.
nl.ro.HelpHotlistMenu0-2:\Rexpand items within the hotlist.
en.ro.HelpHotlistMenu0-2-0:\Sopen all directories and show all entry details.
de.ro.HelpHotlistMenu0-2-0:Öffnet alle Verzeichnisse und zeigt zu Einträgen die Zusatzinformationen an.
fr.ro.HelpHotlistMenu0-2-0:\Souvrir tous les répertoires et afficher tous les détails connus sur les entrées.
it.ro.HelpHotlistMenu0-2-0:\Sopen all directories and show all entry details.
nl.ro.HelpHotlistMenu0-2-0:\Sopen all directories and show all entry details.
en.ro.HelpHotlistMenu0-2-1:\Sopen all directories.
de.ro.HelpHotlistMenu0-2-1:Öffnet alle Verzeichnisse.
fr.ro.HelpHotlistMenu0-2-1:\Souvrir tous les répertoires.
it.ro.HelpHotlistMenu0-2-1:\Sapri tutte le directory.
nl.ro.HelpHotlistMenu0-2-1:\Sopen all directories.
en.ro.HelpHotlistMenu0-2-2:\Sshow all entry details.
de.ro.HelpHotlistMenu0-2-2:Zeigt die Zusatzinformationen zu den Einträgen an.
fr.ro.HelpHotlistMenu0-2-2:\Smontrer tous les détails sur les entrées.
it.ro.HelpHotlistMenu0-2-2:\Sshow all entry details.
nl.ro.HelpHotlistMenu0-2-2:\Sshow all entry details.
en.ro.HelpHotlistMenu0-3:\Rcollapse items within the hotlist.
de.ro.HelpHotlistMenu0-3:Schließen von Verzeichnissen und Ausblenden der Zusatzinformationen.
fr.ro.HelpHotlistMenu0-3:\Rregrouper les items dans la liste des favoris.
it.ro.HelpHotlistMenu0-3:\Rcollapse items within the hotlist.
nl.ro.HelpHotlistMenu0-3:\Rcollapse items within the hotlist.
en.ro.HelpHotlistMenu0-3-0:\Sclose all directories and hide all entry details.
de.ro.HelpHotlistMenu0-3-0:Schließt alle Verzeichnisse und versteckt die Zusatzinformationen bei Einträgen.
fr.ro.HelpHotlistMenu0-3-0:\Sfermer tous les répertoires et cacher les détails sur les entrées.
it.ro.HelpHotlistMenu0-3-0:\Sclose all directories and hide all entry details.
nl.ro.HelpHotlistMenu0-3-0:\Sclose all directories and hide all entry details.
en.ro.HelpHotlistMenu0-3-1:\Sclose all directories.
de.ro.HelpHotlistMenu0-3-1:Schließt alle Verzeichnisse.
fr.ro.HelpHotlistMenu0-3-1:\Sfermer tous les répertoires.
it.ro.HelpHotlistMenu0-3-1:\Schiudi tutte le directory.
nl.ro.HelpHotlistMenu0-3-1:\Sclose all directories.
en.ro.HelpHotlistMenu0-3-2:\Shide all entry details.
de.ro.HelpHotlistMenu0-3-2:Versteckt die Zusatzinformationen der Einträge.
fr.ro.HelpHotlistMenu0-3-2:\Scacher tous les détails sur les entrées.
it.ro.HelpHotlistMenu0-3-2:\Shide all entry details.
nl.ro.HelpHotlistMenu0-3-2:\Shide all entry details.
en.ro.HelpHotlistMenu0-4:\Rcontrol the display of NetSurf's toolbars.
de.ro.HelpHotlistMenu0-4:Knopfleisteneinstellungen vornehmen.
fr.ro.HelpHotlistMenu0-4:\Rcontroler l'affichage des barres d'outils de Netsurf.
it.ro.HelpHotlistMenu0-4:\Rcontrol the display of NetSurf's toolbars.
nl.ro.HelpHotlistMenu0-4:\Rcontrol the display of NetSurf's toolbars.
en.ro.HelpHotlistMenu0-4-0:\Stoggle the display of the toolbar buttons.
de.ro.HelpHotlistMenu0-4-0:Anklicken um die Knopfleiste ein- bzw. auszuschalten.
fr.ro.HelpHotlistMenu0-4-0:\Sbasculer l'affichage des boutons de la barre d'outils.
it.ro.HelpHotlistMenu0-4-0:\Stoggle the display of the toolbar buttons.
nl.ro.HelpHotlistMenu0-4-0:\Stoggle the display of the toolbar buttons.
en.ro.HelpHotlistMenu0-4-1:\Stoggle toolbar edit mode.
de.ro.HelpHotlistMenu0-4-1:Anklicken zum Bearbeiten der Knopfleiste.
fr.ro.HelpHotlistMenu0-4-1:\Sbasculer le mode d'édition de barre d'outils.
it.ro.HelpHotlistMenu0-4-1:\Stoggle toolbar edit mode.
nl.ro.HelpHotlistMenu0-4-1:\Stoggle toolbar edit mode.
en.ro.HelpHotlistMenu1:\Roperate on the current selection.
de.ro.HelpHotlistMenu1:Untermenü Auswahl. Bearbeiten der markierten Hotlist Elemente.
fr.ro.HelpHotlistMenu1:\Ragir sur la sélection en cours.
it.ro.HelpHotlistMenu1:\Roperate on the current selection.
nl.ro.HelpHotlistMenu1:\Roperate on the current selection.
en.ro.HelpHotlistMenu1-0:\Redit the current item.
de.ro.HelpHotlistMenu1-0:Ändern des markierten Elementes in der Hotlist.
fr.ro.HelpHotlistMenu1-0:\Rééditer l'item en cours.
it.ro.HelpHotlistMenu1-0:\Redit the current item.
nl.ro.HelpHotlistMenu1-0:\Redit the current item.
en.ro.HelpHotlistMenu1-1:\Slaunch the current selection.
de.ro.HelpHotlistMenu1-1:Öffnet markierte Einträge in je einem neuen Browserfenster.
fr.ro.HelpHotlistMenu1-1:\Slancer la sélection courante.
it.ro.HelpHotlistMenu1-1:\Slaunch the current selection.
nl.ro.HelpHotlistMenu1-1:\Slaunch the current selection.
en.ro.HelpHotlistMenu1-2:\Sdelete the current selection from the hotlist.
de.ro.HelpHotlistMenu1-2:Löscht markierte Elemente aus der Hotlist.|MAchtung: Verzeichnisse werden mit allen in ihnen enthaltenen Einträgen gelöscht.
fr.ro.HelpHotlistMenu1-2:\Ssupprimer la sélection courante de la liste des favoris.
it.ro.HelpHotlistMenu1-2:\Sdelete the current selection from the hotlist.
nl.ro.HelpHotlistMenu1-2:\Sdelete the current selection from the hotlist.
en.ro.HelpHotlistMenu1-3:\Sreset statistics, such as visit count, for selected items.
de.ro.HelpHotlistMenu1-3:Setzt für die markierten Einträge die Statistik, z.B. Anzahl der Seitenbesuche, zurück.
fr.ro.HelpHotlistMenu1-3:\Sremettre à zéro les statistiques, comme le compteur de visite, pour les items sélectionnés.
it.ro.HelpHotlistMenu1-3:\Sreset statistics, such as visit count, for selected items.
nl.ro.HelpHotlistMenu1-3:\Sreset statistics, such as visit count, for selected items.
en.ro.HelpHotlistMenu2:\Sselect all the items in the hotlist.
de.ro.HelpHotlistMenu2:Markiert alle Elemente der Hotlist.
fr.ro.HelpHotlistMenu2:\Ssélectionner tous les items de la liste des favoris.
it.ro.HelpHotlistMenu2:\Sselect all the items in the hotlist.
nl.ro.HelpHotlistMenu2:\Sselect all the items in the hotlist.
en.ro.HelpHotlistMenu3:\Sdeselect all selected items.
de.ro.HelpHotlistMenu3:Deselektiert alle markierten Elemente.
fr.ro.HelpHotlistMenu3:\Sdésélectionner la sélection courante.
it.ro.HelpHotlistMenu3:\Sdeselect all selected items.
nl.ro.HelpHotlistMenu3:\Sdeselect all selected items.
 
en.ro.HelpGHistory:\Tglobal history window.
de.ro.HelpGHistory:Das ist das Fenster der globalen History.
fr.ro.HelpGHistory:\Tla fenêtre d'historique global.
it.ro.HelpGHistory:\Tglobal history window.
nl.ro.HelpGHistory:\Tglobal history window.
en.ro.HelpGHistoryToolbar0:\Tdelete button.|M\Sdelete the current selection.
de.ro.HelpGHistoryToolbar0:Entfernt markierte Bereiche.|MAnklicken mit AUSWAHL löscht die vorher markierten Bereiche aus der History.
fr.ro.HelpGHistoryToolbar0:\Tle bouton de suppression.|M\Ssupprimer la sélection en cours.
it.ro.HelpGHistoryToolbar0:\Tdelete button.|M\Sdelete the current selection.
nl.ro.HelpGHistoryToolbar0:\Tdelete button.|M\Sdelete the current selection.
en.ro.HelpGHistoryToolbar1:\Texpand entries button.|M\Sexpand all entries in the history.|M\Acollapse all entries in the history.|MExpanded entries show additional details, such as a visit counter.
de.ro.HelpGHistoryToolbar1:Expandiert Einträge.|MAnklicken mit AUSWAHL expandiert alle Adressen.|MAnklicken mit SPEZIAL macht die Expansion aller Adressen rückgängig.|MIn expandierten Adressen werden Zusatzinformationen angezeigt.
fr.ro.HelpGHistoryToolbar1:\Tle bouton de déploiement des entrées.|M\Sdéployer toutes les adresses des favoris.|M\Aregrouper toutes les adresses des favoris.|MLes adresses déployées apportent des détails supplémentaires, comme un compteur de visites.
it.ro.HelpGHistoryToolbar1:\Texpand entries button.|M\Sexpand all entries in the history.|M\Acollapse all entries in the history.|MExpanded entries show additional details, such as a visit counter.
nl.ro.HelpGHistoryToolbar1:\Texpand entries button.|M\Sexpand all entries in the history.|M\Acollapse all entries in the history.|MExpanded entries show additional details, such as a visit counter.
en.ro.HelpGHistoryToolbar2:\Topen sections button.|M\Sopen all sections in the global history.|M\Aclose all sections in the global history.
de.ro.HelpGHistoryToolbar2:Öffnet Verzeichnisse.|MAnklicken mit AUSWAHL öffnet alle Verzeichnisse.|MAnklicken mit SPEZIAL schließt alle geöffneten Verzeichnisse.
fr.ro.HelpGHistoryToolbar2:\Tle bouton d'ouverture de répertoires.|M\Souvrir tous les répertoires des favoris.|M\Afermer tous les répertoires des favoris.
it.ro.HelpGHistoryToolbar2:\Topen sections button.|M\Sopen all sections in the global history.|M\Aclose all sections in the global history.
nl.ro.HelpGHistoryToolbar2:\Topen sections button.|M\Sopen all sections in the global history.|M\Aclose all sections in the global history.
en.ro.HelpGHistoryToolbar3:\Tlaunch button.|M\Slaunch the current selection.
de.ro.HelpGHistoryToolbar3:Lädt Webseiten.|MAnklicken mit AUSWAHL öffnet die markierten Webseiten in je einem neuen Browserfenster.
fr.ro.HelpGHistoryToolbar3:\Tle bouton de lancement.|M\Slancer la sélection en cours.
it.ro.HelpGHistoryToolbar3:\Tlaunch button.|M\Slaunch the current selection.
nl.ro.HelpGHistoryToolbar3:\Tlaunch button.|M\Slaunch the current selection.
 
en.ro.HelpGHistoryMenu0:\Rperform an operation on global history.
de.ro.HelpGHistoryMenu0:Die globale History bearbeiten.
fr.ro.HelpGHistoryMenu0:\Reffectuer une opération sur l'historique global.
it.ro.HelpGHistoryMenu0:\Rperform an operation on global history.
nl.ro.HelpGHistoryMenu0:\Rperform an operation on global history.
en.ro.HelpGHistoryMenu0-0:\Rexport global history as an HTML file.
de.ro.HelpGHistoryMenu0-0:Speichert die History (global) als HTML Datei.
fr.ro.HelpGHistoryMenu0-0:\Rexporter l'historique global en fichier HTML.
it.ro.HelpGHistoryMenu0-0:\Rexport global history as an HTML file.
nl.ro.HelpGHistoryMenu0-0:\Rexport global history as an HTML file.
en.ro.HelpGHistoryMenu0-1:\Rexpand items within global history.
de.ro.HelpGHistoryMenu0-1:Mehr Information anzeigen
fr.ro.HelpGHistoryMenu0-1:\Rdéployer les items de l'historique global.
it.ro.HelpGHistoryMenu0-1:\Rexpand items within global history.
nl.ro.HelpGHistoryMenu0-1:\Rexpand items within global history.
en.ro.HelpGHistoryMenu0-1-0:\Sopen all directories and show all entry details.
de.ro.HelpGHistoryMenu0-1-0:Öffnet alle Verzeichnisse und zeigt die Details der Einträge an.
fr.ro.HelpGHistoryMenu0-1-0:\Souvrir tous les répertoires et donner le détail de toutes les entrées.
it.ro.HelpGHistoryMenu0-1-0:\Sopen all directories and show all entry details.
nl.ro.HelpGHistoryMenu0-1-0:\Sopen all directories and show all entry details.
en.ro.HelpGHistoryMenu0-1-1:\Sopen all directories.
de.ro.HelpGHistoryMenu0-1-1:Öffnet alle Verzeichnisse.
fr.ro.HelpGHistoryMenu0-1-1:\Souvrir tous les répertoires.
it.ro.HelpGHistoryMenu0-1-1:\Sopen all directories.
nl.ro.HelpGHistoryMenu0-1-1:\Sopen all directories.
en.ro.HelpGHistoryMenu0-1-2:\Sshow all entry details.
de.ro.HelpGHistoryMenu0-1-2:Zeigt die Details der sichtbaren Einträge an.
fr.ro.HelpGHistoryMenu0-1-2:\Smontrer le détail de toutes les entrées.
it.ro.HelpGHistoryMenu0-1-2:\Sshow all entry details.
nl.ro.HelpGHistoryMenu0-1-2:\Sshow all entry details.
en.ro.HelpGHistoryMenu0-2:\Rcollapse items within global history.
de.ro.HelpGHistoryMenu0-2:Weniger Information anzeigen
fr.ro.HelpGHistoryMenu0-2:\Rregrouper les items de l'historique global.
it.ro.HelpGHistoryMenu0-2:\Rcollapse items within global history.
nl.ro.HelpGHistoryMenu0-2:\Rcollapse items within global history.
en.ro.HelpGHistoryMenu0-2-0:\Sclose all directories and hide all entry details.
de.ro.HelpGHistoryMenu0-2-0:Schließt alle Verzeichnisse und versteckt die Details der Einträge.
fr.ro.HelpGHistoryMenu0-2-0:\Sfermer tous les répertoires et cacher le détail de toutes les entrées.
it.ro.HelpGHistoryMenu0-2-0:\Sclose all directories and hide all entry details.
nl.ro.HelpGHistoryMenu0-2-0:\Sclose all directories and hide all entry details.
en.ro.HelpGHistoryMenu0-2-1:\Sclose all directories.
de.ro.HelpGHistoryMenu0-2-1:Schließt alle Verzeichnisse.
fr.ro.HelpGHistoryMenu0-2-1:\Sfermer tous les répertoires.
it.ro.HelpGHistoryMenu0-2-1:\Sclose all directories.
nl.ro.HelpGHistoryMenu0-2-1:\Sclose all directories.
en.ro.HelpGHistoryMenu0-2-2:\Shide all entry details.
de.ro.HelpGHistoryMenu0-2-2:Versteckt die Detailanzeige der Einträge.
fr.ro.HelpGHistoryMenu0-2-2:\Scacher le détail de toutes les entrées.
it.ro.HelpGHistoryMenu0-2-2:\Shide all entry details.
nl.ro.HelpGHistoryMenu0-2-2:\Shide all entry details.
en.ro.HelpGHistoryMenu0-3:\Rcontrol the display of NetSurf's toolbars.
de.ro.HelpGHistoryMenu0-3:Die Iconleiste der globalen History verändern.
fr.ro.HelpGHistoryMenu0-3:\Rcontroler l'affichage des barre d'outils de NetSurf.
it.ro.HelpGHistoryMenu0-3:\Rcontrol the display of NetSurf's toolbars.
nl.ro.HelpGHistoryMenu0-3:\Rcontrol the display of NetSurf's toolbars.
en.ro.HelpGHistoryMenu0-3-0:\Stoggle the display of the toolbar buttons.
de.ro.HelpGHistoryMenu0-3-0:Iconleiste an- oder abschalten.
fr.ro.HelpGHistoryMenu0-3-0:\Sbasculer l'affichage des boutons de la barre d'outils.
it.ro.HelpGHistoryMenu0-3-0:\Stoggle the display of the toolbar buttons.
nl.ro.HelpGHistoryMenu0-3-0:\Stoggle the display of the toolbar buttons.
en.ro.HelpGHistoryMenu0-3-1:\Stoggle toolbar edit mode.
de.ro.HelpGHistoryMenu0-3-1:Iconleiste bearbeiten.
fr.ro.HelpGHistoryMenu0-3-1:\Sbasculer le mode d'édition de la barre d'outils.
it.ro.HelpGHistoryMenu0-3-1:\Stoggle toolbar edit mode.
nl.ro.HelpGHistoryMenu0-3-1:\Stoggle toolbar edit mode.
en.ro.HelpGHistoryMenu1:\Roperate on the current selection.
de.ro.HelpGHistoryMenu1:Die aktuelle Auswahl bearbeiten.
fr.ro.HelpGHistoryMenu1:\Reffectuer une opération sur la sélection courante.
it.ro.HelpGHistoryMenu1:\Roperate on the current selection.
nl.ro.HelpGHistoryMenu1:\Roperate on the current selection.
en.ro.HelpGHistoryMenu1-0:\Slaunch the current selection.
de.ro.HelpGHistoryMenu1-0:Lädt Webseiten.|MAnklicken mit AUSWAHL öffnet die markierten Webseiten in je einem neuen Browserfenster.
fr.ro.HelpGHistoryMenu1-0:\Slancer la sélection courante.
it.ro.HelpGHistoryMenu1-0:\Slaunch the current selection.
nl.ro.HelpGHistoryMenu1-0:\Slaunch the current selection.
en.ro.HelpGHistoryMenu1-1:\Sdelete the current selection from global history.
de.ro.HelpGHistoryMenu1-1:Entfernt markierte Bereiche.|MAnklicken mit AUSWAHL löscht die vorher markierten Bereiche aus der History.
fr.ro.HelpGHistoryMenu1-1:\Ssupprimer la sélection courante de l'historique global.
it.ro.HelpGHistoryMenu1-1:\Sdelete the current selection from global history.
nl.ro.HelpGHistoryMenu1-1:\Sdelete the current selection from global history.
en.ro.HelpGHistoryMenu1-2:\Sreset statistics, such as visit count, for selected items.
de.ro.HelpGHistoryMenu1-2:Setzt die Besuchsstatistik der markierten Einträge zurück.
fr.ro.HelpGHistoryMenu1-2:\Sremettre à zéro les statistiques, comme le compteur de visites, pour les items sélectionnés.
it.ro.HelpGHistoryMenu1-2:\Sreset statistics, such as visit count, for selected items.
nl.ro.HelpGHistoryMenu1-2:\Sreset statistics, such as visit count, for selected items.
en.ro.HelpGHistoryMenu2:\Sselect all the items in the history.
de.ro.HelpGHistoryMenu2:Markiert alle Elemente der globalen History.
fr.ro.HelpGHistoryMenu2:\Ssélectionner tous les items des favoris.
it.ro.HelpGHistoryMenu2:\Sselect all the items in the history.
nl.ro.HelpGHistoryMenu2:\Sselect all the items in the hotlist.
en.ro.HelpGHistoryMenu3:\Sdeselect all selected items.
de.ro.HelpGHistoryMenu3:Deselektiert alle markierten Elemente.
fr.ro.HelpGHistoryMenu3:\Sdéselectionner tous les items sélectionnés.
it.ro.HelpGHistoryMenu3:\Sdeselect all selected items.
nl.ro.HelpGHistoryMenu3:\Sdeselect all selected items.
 
en.ro.HelpCookies:\TCookie management window.
de.ro.HelpCookies:Das ist das Fenster zur Cookie-Verwaltung.
fr.ro.HelpCookies:\TFenêtre de gestion des cookies.
it.ro.HelpCookies:\TCookie management window.
nl.ro.HelpCookies:\TCookie management window.
en.ro.HelpCookiesToolbar0:\Tdelete button.|M\Sdelete the current selection.
de.ro.HelpCookiesToolbar0:Dies ist der Löschschalter.|MAnklicken löscht alle markierten Einträge.
fr.ro.HelpCookiesToolbar0:\Tbouton de suppression.|M\Ssupprimer la sélection en cours.
it.ro.HelpCookiesToolbar0:\Tdelete button.|M\Sdelete the current selection.
nl.ro.HelpCookiesToolbar0:\Tdelete button.|M\Sdelete the current selection.
en.ro.HelpCookiesToolbar1:\Texpand cookies button.|M\Sexpand all cookies in the list.|M\Acollapse all cookies in the list.|MExpanded cookies show additional details.
de.ro.HelpCookiesToolbar1:Dies ist der Schalter zum Expandieren der Einträge.|MKlicken mit AUSWAHL expandiert alle Cookies.|MKlicken mit SPEZIAL versteckt die Zusatzinformationen wieder.|MIn expandierten Cookies werden zusätzliche Informationen angezeigt.
fr.ro.HelpCookiesToolbar1:\Tdéployer le bouton de cookies.|M\Sdéployer tous les cookies de la liste.|M\Aregrouper tous les cookies de la liste.|MDéployer les cookies permet l'affichage d'informations supplémentaires.
it.ro.HelpCookiesToolbar1:\Texpand cookies button.|M\Sexpand all cookies in the list.|M\Acollapse all cookies in the list.|MExpanded cookies show additional details.
nl.ro.HelpCookiesToolbar1:\Texpand cookies button.|M\Sexpand all cookies in the list.|M\Acollapse all cookies in the list.|MExpanded cookies show additional details.
en.ro.HelpCookiesToolbar2:\Topen directories button.|M\Sopen all directories in the list.|M\Aclose all directories in the list.
de.ro.HelpCookiesToolbar2:Öffnet und schließt Verzeichnisse|MKlicken mit AUSWAHL öffnet alle Verzeichnisse der Liste.|MKlicken mit SPEZIAL schließt alle Verzeichnisse.
fr.ro.HelpCookiesToolbar2:\Touvrir le bouton de répertoires.|M\Souvrir tous les répertoires de la liste.|M\Afermer tous les répertoires de la liste.
it.ro.HelpCookiesToolbar2:\Topen directories button.|M\Sopen all directories in the list.|M\Aclose all directories in the list.
nl.ro.HelpCookiesToolbar2:\Topen directories button.|M\Sopen all directories in the list.|M\Aclose all directories in the list.
 
en.ro.HelpCookiesMenu0:\Rperform an operation on the cookie list.
de.ro.HelpCookiesMenu0:Die gesamte Liste bearbeiten.
fr.ro.HelpCookiesMenu0:\Raccomplir une opération sur la liste de cookies.
it.ro.HelpCookiesMenu0:\Rperform an operation on the cookie list.
nl.ro.HelpCookiesMenu0:\Rperform an operation on the cookie list.
en.ro.HelpCookiesMenu0-0:\Rexpand items within the cookie list.
de.ro.HelpCookiesMenu0-0:Menü zum Expandieren der Einträge der Liste.
fr.ro.HelpCookiesMenu0-0:\Rdéployer les items dans la liste de cookies.
it.ro.HelpCookiesMenu0-0:\Rexpand items within the cookie list.
nl.ro.HelpCookiesMenu0-0:\Rexpand items within the cookie list.
en.ro.HelpCookiesMenu0-0-0:\Sopen all directories and show all cookie details.
de.ro.HelpCookiesMenu0-0-0:Klicken mit AUSWAHL öffnet alle Verzeichnisse und zeigt Details zu allen angezeigten Cookies.
fr.ro.HelpCookiesMenu0-0-0:\Souvrir tous les répertoires et montrer le détail de tous les cookies.
it.ro.HelpCookiesMenu0-0-0:\Sopen all directories and show all cookie details.
nl.ro.HelpCookiesMenu0-0-0:\Sopen all directories and show all cookie details.
en.ro.HelpCookiesMenu0-0-1:\Sopen all directories.
de.ro.HelpCookiesMenu0-0-1:Klicken mit AUSWAHL öffnet alle Verzeichnisse.
fr.ro.HelpCookiesMenu0-0-1:\Souvrir tous les répertoires.
it.ro.HelpCookiesMenu0-0-1:\Sapri tutte le directory.
nl.ro.HelpCookiesMenu0-0-1:\Sopen all directories.
en.ro.HelpCookiesMenu0-0-2:\Sshow all cookie details.
de.ro.HelpCookiesMenu0-0-2:Klicken mit AUSWAHL zeigt Details zu allen angezeigten Cookies.
fr.ro.HelpCookiesMenu0-0-2:\Smontrer le détail de tous les cookies.
it.ro.HelpCookiesMenu0-0-2:\Smostra tutti i cookie in dettaglio.
nl.ro.HelpCookiesMenu0-0-2:\Sshow all cookie details.
en.ro.HelpCookiesMenu0-1:\Rcollapse items within the cookie list.
de.ro.HelpCookiesMenu0-1:Menü zum Schließen der Einträge der Liste.
fr.ro.HelpCookiesMenu0-1:\Rregrouper les items dans la liste de cookies.
it.ro.HelpCookiesMenu0-1:\Rcollapse items within the cookie list.
nl.ro.HelpCookiesMenu0-1:\Rcollapse items within the cookie list.
en.ro.HelpCookiesMenu0-1-0:\Sclose all directories and hide all cookie details.
de.ro.HelpCookiesMenu0-1-0:Klicken mit AUSWAHL schließt alle Verzeichnisse und versteckt die Cookiedetails.
fr.ro.HelpCookiesMenu0-1-0:\Sfermer tous les répertoires et cacher le détail de tous les cookies.
it.ro.HelpCookiesMenu0-1-0:\Sclose all directories and hide all cookie details.
nl.ro.HelpCookiesMenu0-1-0:\Sclose all directories and hide all cookie details.
en.ro.HelpCookiesMenu0-1-1:\Sclose all directories.
de.ro.HelpCookiesMenu0-1-1:Klicken mit AUSWAHL schließt alle Verzeichnisse.
fr.ro.HelpCookiesMenu0-1-1:\Sfermer tous les répertoires.
it.ro.HelpCookiesMenu0-1-1:\Schiudi le directory.
nl.ro.HelpCookiesMenu0-1-1:\Sclose all directories.
en.ro.HelpCookiesMenu0-1-2:\Shide all cookie details.
de.ro.HelpCookiesMenu0-1-2:Klicken mit AUSWAHL versteckt alle Cookiedetails.
fr.ro.HelpCookiesMenu0-1-2:\Scacher le détail de tous les cookies.
it.ro.HelpCookiesMenu0-1-2:\Shide all cookie details.
nl.ro.HelpCookiesMenu0-1-2:\Shide all cookie details.
en.ro.HelpCookiesMenu0-2:\Rcontrol the display of NetSurf's toolbars.
de.ro.HelpCookiesMenu0-2:Die Iconleiste verändern.
fr.ro.HelpCookiesMenu0-2:\Rcontroler l'affichage des barres d'outils de Netsurf.
it.ro.HelpCookiesMenu0-2:\Rcontrol the display of NetSurf's toolbars.
nl.ro.HelpCookiesMenu0-2:\Rcontrol the display of NetSurf's toolbars.
en.ro.HelpCookiesMenu0-2-0:\Stoggle the display of the toolbar buttons.
de.ro.HelpCookiesMenu0-2-0:Klicken mit AUSWAHL um die Iconleiste an- oder abzuschalten.
fr.ro.HelpCookiesMenu0-2-0:\Sbasculer l'affichage des boutons de la barre d'outils.
it.ro.HelpCookiesMenu0-2-0:\Stoggle the display of the toolbar buttons.
nl.ro.HelpCookiesMenu0-2-0:\Stoggle the display of the toolbar buttons.
en.ro.HelpCookiesMenu0-2-1:\Stoggle toolbar edit mode.
de.ro.HelpCookiesMenu0-2-1:Klicken mit AUSWAHL um die Iconleiste zu bearbeiten.
fr.ro.HelpCookiesMenu0-2-1:\Sbasculer le mode d'édition de la barre d'outils.
it.ro.HelpCookiesMenu0-2-1:\Stoggle toolbar edit mode.
nl.ro.HelpCookiesMenu0-2-1:\Stoggle toolbar edit mode.
en.ro.HelpCookiesMenu1:\Roperate on the current selection.
de.ro.HelpCookiesMenu1:Die ausgewählten Einträge bearbeiten.
fr.ro.HelpCookiesMenu1:\Rfaire une opération sur la sélection courante.
it.ro.HelpCookiesMenu1:\Roperate on the current selection.
nl.ro.HelpCookiesMenu1:\Roperate on the current selection.
en.ro.HelpCookiesMenu1-0:\Sdelete any selected cookies.
de.ro.HelpCookiesMenu1-0:Klicken mit AUSWAHL löscht alle markierten Cookies.
fr.ro.HelpCookiesMenu1-0:\Ssupprimer tous les cookies sélectionnés.
it.ro.HelpCookiesMenu1-0:\Scancella tutti i cookie selezionati.
nl.ro.HelpCookiesMenu1-0:\Sdelete any selected cookies.
en.ro.HelpCookiesMenu2:\Sselect all the items in the cookie list.
de.ro.HelpCookiesMenu2:Klicken mit AUSWAHL markiert alle Cookies als gewählt.
fr.ro.HelpCookiesMenu2:\Ssélectionner tous les items dans la liste de cookies.
it.ro.HelpCookiesMenu2:\Sseleziona tutti gli oggetti nella lista dei cookie.
nl.ro.HelpCookiesMenu2:\Sselect all the items in the cookie list.
en.ro.HelpCookiesMenu3:\Sdeselect all selected items.
de.ro.HelpCookiesMenu3:Klicken mit AUSWAHL macht alle Markierungen rückgängig.
fr.ro.HelpCookiesMenu3:\Sdéselectionner tous les items.
it.ro.HelpCookiesMenu3:\Sdeseleziona tutti gli oggetti selezionati.
nl.ro.HelpCookiesMenu3:\Sdeselect all selected items.
 
en.ro.HelpAppInfo:\TNetSurf information \w.|MSee the about page for the contributor list and credits.
de.ro.HelpAppInfo:Das ist das Info-Fenster zu NetSurf.|MGenauere Angaben zu den Autoren, Grafikern, Übersetzern, genutzten Libraries etc. gibt es bei "Über NetSurf" im Untermenü Hilfe eines Browserfensters.
fr.ro.HelpAppInfo:\Tla \w d'information de NetSurf.|MVoir la page "À propos de" pour une liste des contributeurs et les remerciements.
it.ro.HelpAppInfo:\TNetSurf information \w.|MSee the about page for the contributor list and credits.
nl.ro.HelpAppInfo:\TNetSurf information \w.|MSee the about page for the contributor list and credits.
 
 
en.ro.HelpConfigure:\Tconfiguration \w for NetSurf
de.ro.HelpConfigure:Dies ist das Konfigurationsfenster von NetSurf.
fr.ro.HelpConfigure:\Tla fenêtre de configuration pour Netsurf
it.ro.HelpConfigure:\Tconfiguration \w for NetSurf
nl.ro.HelpConfigure:\Tconfiguration \w for NetSurf
en.ro.HelpConfigure0:Cache configuration tool
de.ro.HelpConfigure0:Cachespeicher konfigurieren
fr.ro.HelpConfigure0:Outil de configuration de cache
it.ro.HelpConfigure0:Cache configuration tool
nl.ro.HelpConfigure0:Cache configuration tool
en.ro.HelpConfigure1:Connection configuration tool
de.ro.HelpConfigure1:Verbindungen konfigurieren
fr.ro.HelpConfigure1:Outil de configuration de connexion
it.ro.HelpConfigure1:Connection configuration tool
nl.ro.HelpConfigure1:Connection configuration tool
en.ro.HelpConfigure2:Content configuration tool
de.ro.HelpConfigure2:Bestimmte Seiteninhalte zulassen oder abschalten
fr.ro.HelpConfigure2:Outil de configuration de contenu
it.ro.HelpConfigure2:Content configuration tool
nl.ro.HelpConfigure2:Content configuration tool
en.ro.HelpConfigure3:Font configuration tool
de.ro.HelpConfigure3:Zeichensätze konfigurieren
fr.ro.HelpConfigure3:Outil de configuration de fontes
it.ro.HelpConfigure3:Strumento di configurazione dei font
nl.ro.HelpConfigure3:Font configuration tool
en.ro.HelpConfigure4:Home page configuration tool
de.ro.HelpConfigure4:Homepage einstellen
fr.ro.HelpConfigure4:Outil de configuration de la page d'accueil
it.ro.HelpConfigure4:Home page configuration tool
nl.ro.HelpConfigure4:Home page configuration tool
en.ro.HelpConfigure5:Image configuration tool
de.ro.HelpConfigure5:Bilderdarstellung konfigurieren
fr.ro.HelpConfigure5:Outil de configuration d'image
it.ro.HelpConfigure5:Image configuration tool
nl.ro.HelpConfigure5:Image configuration tool
en.ro.HelpConfigure6:Interface configuration tool
de.ro.HelpConfigure6:Programmverhalten für besondere Situationen einstellen
fr.ro.HelpConfigure6:Outil de configuration d'interface
it.ro.HelpConfigure6:Interface configuration tool
nl.ro.HelpConfigure6:Interface configuration tool
en.ro.HelpConfigure7:Language configuration tool
de.ro.HelpConfigure7:Sprachen einstellen
fr.ro.HelpConfigure7:Outil de configuration de langue
it.ro.HelpConfigure7:Language configuration tool
nl.ro.HelpConfigure7:Language configuration tool
en.ro.HelpConfigure8:Memory configuration tool
de.ro.HelpConfigure8:Arbeitsspeicher konfigurieren
fr.ro.HelpConfigure8:Outil de configuration de la mémoire
it.ro.HelpConfigure8:Memory configuration tool
nl.ro.HelpConfigure8:Memory configuration tool
en.ro.HelpConfigure9:Theme configuration tool
de.ro.HelpConfigure9:Themenauswahl
fr.ro.HelpConfigure9:Outil de configuration de thème
it.ro.HelpConfigure9:Theme configuration tool
nl.ro.HelpConfigure9:Theme configuration tool
en.ro.HelpConfigure10:Security and Privacy configuration tool
de.ro.HelpConfigure10:Sicherheitseinstellungen und Privatsphäre
fr.ro.HelpConfigure10:Outil de configuration de la sécurité et de la confidentialité
it.ro.HelpConfigure10:Security and Privacy configuration tool
nl.ro.HelpConfigure10:Security and Privacy configuration tool
 
en.ro.HelpCacheConfig:\Tcache configuration \w.
de.ro.HelpCacheConfig:Das ist das Fenster der Cache-Konfiguration.
fr.ro.HelpCacheConfig:\Tla fenêtre de configuration du cache.
it.ro.HelpCacheConfig:\Tcache configuration \w.
nl.ro.HelpCacheConfig:\Tcache configuration \w.
en.ro.HelpCacheConfig3:\Tamount of memory to be used for caching content.
de.ro.HelpCacheConfig3:Speichergröße, die verwendet wird um Inhalte zwischenzuspeichern.
fr.ro.HelpCacheConfig3:\Tla quantité de mémoire à utiliser pour le contenu du cache.
it.ro.HelpCacheConfig3:\Tamount of memory to be used for caching content.
nl.ro.HelpCacheConfig3:\Tamount of memory to be used for caching content.
en.ro.HelpCacheConfig4:\Sreduce the amount of memory.
de.ro.HelpCacheConfig4:Klicken mit AUSWAHL verringert die Größe des Cachespeichers.
fr.ro.HelpCacheConfig4:\Sréduire la quantité de mémoire.
it.ro.HelpCacheConfig4:\Sreduce the amount of memory.
nl.ro.HelpCacheConfig4:\Sreduce the amount of memory.
en.ro.HelpCacheConfig5:\Sincrease the amount of memory.
de.ro.HelpCacheConfig5:Klicken mit AUSWAHL vergrößert die Größe des Cachespeichers.
fr.ro.HelpCacheConfig5:\Saugmenter la quantité de mémoire.
it.ro.HelpCacheConfig5:\Sincrease the amount of memory.
nl.ro.HelpCacheConfig5:\Sincrease the amount of memory.
en.ro.HelpCacheConfig7:\Sreset the Cache options back to their default values.
de.ro.HelpCacheConfig7:Stellt die Standardeinstellungen wieder her.
fr.ro.HelpCacheConfig7:\Srevenir aux valeurs par défaut des options du Cache.
it.ro.HelpCacheConfig7:\Sreset the Cache options back to their default values.
nl.ro.HelpCacheConfig7:\Sreset the Cache options back to their default values.
en.ro.HelpCacheConfig8:\Sclose this \w without saving changes.|M\Areturn the cache options to the last saved configuration.
de.ro.HelpCacheConfig8:Klicken mit AUSWAHL schließt das Fenster ohne die Änderungen zu speichern.|MKlicken mit SPEZIAL stellt die zuletzt abgespeicherten Einstellungen wieder her.
fr.ro.HelpCacheConfig8:\Sfermer cette fenêtre sans sauver les changements.|M\Arevenir aux options de Cache précédemment sauvegardées.
it.ro.HelpCacheConfig8:\Sclose this \w without saving changes.|M\Areturn the cache options to the last saved configuration.
nl.ro.HelpCacheConfig8:\Sclose this \w without saving changes.|M\Areturn the cache options to the last saved configuration.
en.ro.HelpCacheConfig9:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
de.ro.HelpCacheConfig9:Klicken mit AUSWAHL speichert die Einstellungen und schließt das Fenster.|MKlicken mit SPEZIAL speichert die Einstellungen ohne das Fenster zu schließen.
fr.ro.HelpCacheConfig9:\Ssauver ces réglages et fermer la fenêtre.|M\Asauver ces réglages sans fermer la fenêtre.
it.ro.HelpCacheConfig9:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
nl.ro.HelpCacheConfig9:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
 
en.ro.HelpConnectConfig:\Tconnection configuration \w
de.ro.HelpConnectConfig:Das ist das Fenster zur Einstellung der Parameter für die Netzanbindung.
fr.ro.HelpConnectConfig:\Tla fenêtre de configuration de connexion.
it.ro.HelpConnectConfig:\Tconnection configuration \w
nl.ro.HelpConnectConfig:\Tconnection configuration \w
en.ro.HelpConnectConfig3:\Tcurrently selected proxy type.|MUse the menu to select a proxy type.
de.ro.HelpConnectConfig3:Aktuell gewählter Proxytyp.|MMit dem Menü kann ein anderer Typ eingestellt werden.
fr.ro.HelpConnectConfig3:\Tle type de proxy sélectionné en ce moment.|MUtiliser le menu pour choisir un type de proxy.
it.ro.HelpConnectConfig3:\Tcurrently selected proxy type.|MUse the menu to select a proxy type.
nl.ro.HelpConnectConfig3:\Tcurrently selected proxy type.|MUse the menu to select a proxy type.
en.ro.HelpConnectConfig4:\Sselect a proxy type.
de.ro.HelpConnectConfig4:Klicken mit AUSWAHL um einen anderen Proxytyp auszuwählen.
fr.ro.HelpConnectConfig4:\Schoisir un type de proxy.
it.ro.HelpConnectConfig4:\Sselect a proxy type.
nl.ro.HelpConnectConfig4:\Sselect a proxy type.
en.ro.HelpConnectConfig6:You can enter the proxy's host name here.
de.ro.HelpConnectConfig6:Hier kann der Hostname des Proxys eingegeben werden.
fr.ro.HelpConnectConfig6:Vous pouvez entrer ici le nom d'hôte du proxy.
it.ro.HelpConnectConfig6:You can enter the proxy's host name here.
nl.ro.HelpConnectConfig6:You can enter the proxy's host name here.
en.ro.HelpConnectConfig8:You can enter the proxy's port number here.
de.ro.HelpConnectConfig8:Hier kann die zugehörige Portnummer eingestellt werden.
fr.ro.HelpConnectConfig8:Vous pouvez entrer ici le numéro de port du proxy.
it.ro.HelpConnectConfig8:You can enter the proxy's port number here.
nl.ro.HelpConnectConfig8:You can enter the proxy's port number here.
en.ro.HelpConnectConfig10:You can enter a username for proxies that require authentication here.
de.ro.HelpConnectConfig10:Hier kann ein Username eingegeben werden, wenn der Proxy das erfordert.
fr.ro.HelpConnectConfig10:Vous pouvez entrer ici un nom d'utilisateur pour les proxies nécessitant une authentification.
it.ro.HelpConnectConfig10:You can enter a username for proxies that require authentication here.
nl.ro.HelpConnectConfig10:You can enter a username for proxies that require authentication here.
en.ro.HelpConnectConfig12:You can enter a password for proxies that require authentication here.
de.ro.HelpConnectConfig12:Hier kann das zum Usernamen gehörige Passwort eingegeben werden.
fr.ro.HelpConnectConfig12:Vous pouvez entrer ici un mot de passe pour les proxies nécessitant une authentification.
it.ro.HelpConnectConfig12:You can enter a password for proxies that require authentication here.
nl.ro.HelpConnectConfig12:You can enter a password for proxies that require authentication here.
en.ro.HelpConnectConfig16:\Tmaximum number of simultaneous fetches that NetSurf will perform.
de.ro.HelpConnectConfig16:Das ist die Maximalzahl simultaner Fetches, die NetSurf verwenden soll.
fr.ro.HelpConnectConfig16:\Tle nombre maximum de télechargements simultanés que NetSurf peut effectuer.
it.ro.HelpConnectConfig16:\Tmaximum number of simultaneous fetches that NetSurf will perform.
nl.ro.HelpConnectConfig16:\Tmaximum number of simultanious fetches that NetSurf will perform.
en.ro.HelpConnectConfig17:\Sreduce the maximum number of simultaneous fetches.
de.ro.HelpConnectConfig17:Klicken mit AUSWAHL verringert die Maximalzahl simultaner Fetches.
fr.ro.HelpConnectConfig17:\Sréduire le nombre de téléchargements simultanés.
it.ro.HelpConnectConfig17:\Sreduce the maximum number of simultaneous fetches.
nl.ro.HelpConnectConfig17:\Sreduce the maximum number of simultanious fetches.
en.ro.HelpConnectConfig18:\Sincrease the maximum number of simultaneous fetches.
de.ro.HelpConnectConfig18:Klicken mit AUSWAHL vergrößert die Maximalzahl simultaner Fetches.
fr.ro.HelpConnectConfig18:\Saugmenter le nombre de téléchargements simultanés.
it.ro.HelpConnectConfig18:\Sincrease the maximum number of simultaneous fetches.
nl.ro.HelpConnectConfig18:\Sincrease the maximum number of simultanious fetches.
en.ro.HelpConnectConfig20:\Tmaximum number of simultaneous fetches that NetSurf will perform per host.
de.ro.HelpConnectConfig20:Das ist die Maximalzahl simultaner Fetches, die je Host von NetSurf verwendet werden.
fr.ro.HelpConnectConfig20:\Tle nombre maximum de téléchargements simultanés que Netsurf peut effectuer par hôte.
it.ro.HelpConnectConfig20:\Tmaximum number of simultaneous fetches that NetSurf will perform per host.
nl.ro.HelpConnectConfig20:\Tmaximum number of simultanious fetches that NetSurf will perform per host.
en.ro.HelpConnectConfig21:\Sreduce the maximum number of simultaneous fetches per host.
de.ro.HelpConnectConfig21:Klicken mit AUSWAHL verringert die Maximalzahl simultaner Fetches je Host.
fr.ro.HelpConnectConfig21:\Sréduire le nombre maximum de téléchargements simultanés par hôte.
it.ro.HelpConnectConfig21:\Sreduce the maximum number of simultaneous fetches per host.
nl.ro.HelpConnectConfig21:\Sreduce the maximum number of simultanious fetches per host.
en.ro.HelpConnectConfig22:\Sincrease the maximum number of simultaneous fetches per host.
de.ro.HelpConnectConfig22:Klicken mit AUSWAHL vergrößert die Maximalzahl simultaner Fetches je Host.
fr.ro.HelpConnectConfig22:\Saugmenter le nombre maximum de téléchargements simultanés par hôte.
it.ro.HelpConnectConfig22:\Sincrease the maximum number of simultaneous fetches per host.
nl.ro.HelpConnectConfig22:\Sincrease the maximum number of simultanious fetches per host.
en.ro.HelpConnectConfig24:\Tmaximum number of persistent connections.
de.ro.HelpConnectConfig24:Das ist die Maximalzahl aufrechtzuerhaltender Verbindungen.
fr.ro.HelpConnectConfig24:\Tle nombre maximum de connexions persistantes.
it.ro.HelpConnectConfig24:\Tmaximum number of persistent connections.
nl.ro.HelpConnectConfig24:\Tmaximum number of persistent connections.
en.ro.HelpConnectConfig25:\Sreduce the maximum number of persistent connections.
de.ro.HelpConnectConfig25:Klicken mit AUSWAHL verringert die Maximalzahl offengehaltener Verbindungen.
fr.ro.HelpConnectConfig25:\Sréduire le nombre maximum de connexions persistantes.
it.ro.HelpConnectConfig25:\Sreduce the maximum number of persistent connections.
nl.ro.HelpConnectConfig25:\Sreduce the maximum number of persistent connections.
en.ro.HelpConnectConfig26:\Sincrease the maximum number of persistent connections.
de.ro.HelpConnectConfig26:Klicken mit AUSWAHL vergrößert die Maximalzahl offengehaltener Verbindungen.
fr.ro.HelpConnectConfig26:\Saugmenter le nombre maximum de connexions persistantes.
it.ro.HelpConnectConfig26:\Sincrease the maximum number of persistent connections.
nl.ro.HelpConnectConfig26:\Sincrease the maximum number of persistent connections.
en.ro.HelpConnectConfig27:\Sreset the Connection options back to their default values.
de.ro.HelpConnectConfig27:Stellt die Standardeinstellungen wieder her.
fr.ro.HelpConnectConfig27:\Srevenir aux valeurs par défaut des options de Connexion.
it.ro.HelpConnectConfig27:\Sreset the Connection options back to their default values.
nl.ro.HelpConnectConfig27:\Sreset the Connection options back to their default values.
en.ro.HelpConnectConfig28:\Sclose this \w without saving changes.|M\Areturn the connection options to the last saved configuration.
de.ro.HelpConnectConfig28:Klicken mit AUSWAHL schließt das Fenster ohne die Änderungen zu speichern.|MKlicken mit SPEZIAL stellt die zuletzt abgespeicherten Einstellungen wieder her.
fr.ro.HelpConnectConfig28:\Sfermer cette fenêtre sans sauvegarder les changements.|M\Arevenir aux options de Connexion précédemment sauvegardées.
it.ro.HelpConnectConfig28:\Sclose this \w without saving changes.|M\Areturn the connection options to the last saved configuration.
nl.ro.HelpConnectConfig28:\Sclose this \w without saving changes.|M\Areturn the cache options to the last saved configuration.
en.ro.HelpConnectConfig29:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
de.ro.HelpConnectConfig29:Klicken mit AUSWAHL speichert die Einstellungen und schließt das Fenster.|MKlicken mit SPEZIAL speichert die Einstellungen ohne das Fenster zu schließen.
fr.ro.HelpConnectConfig29:\Ssauver ces réglages et fermer la fenêtre.|M\Asauver ces réglages sans fermer la fenêtre.
it.ro.HelpConnectConfig29:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
nl.ro.HelpConnectConfig29:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
 
en.ro.HelpContentConfig:\Tcontent configuration \w
de.ro.HelpContentConfig:Fenster zur Einstellung des Browserverhaltens bei bestimmten Seiteninhalten
fr.ro.HelpContentConfig:\Tla fenêtre de configuration du Contenu
it.ro.HelpContentConfig:\Tcontent configuration \w
nl.ro.HelpContentConfig:\Tcontent configuration \w
en.ro.HelpContentConfig2:This indicates whether NetSurf will attempt to block advertisements on web pages|MIn rare circumstances, this option may cause valid content to be blocked too.
de.ro.HelpContentConfig2:Stellt ein, ob NetSurf versuchen soll, die auf Webseiten eingeblendete Werbung automatisch zu unterdrücken.|MIn seltenen Fällen wird dadurch jedoch auch 'echter' Seiteninhalt geblockt.
fr.ro.HelpContentConfig2:Ceci indique si Netsurf doit essayer de bloquer les pubs sur les pages web.|MEn de rares circonstances, cette option peut également bloquer du contenu valide.
it.ro.HelpContentConfig2:This indicates whether NetSurf will attempt to block advertisements on web pages|MIn rare circumstances, this option may cause valid content to be blocked too.
nl.ro.HelpContentConfig2:This indicates whether NetSurf will atempt to block advertisements on web pages|MIn rare circumstances, this option may cause valid content to be blocked too.
en.ro.HelpContentConfig3:This indicates whether NetSurf will stop web sites from automatically opening new windows on your desktop.
de.ro.HelpContentConfig3:Stellt ein, ob NetSurf das automatische Öffnen neuer Fenster auf dem Desktop unterbinden soll.
fr.ro.HelpContentConfig3:Ceci indique si Netsurf doit empêcher les sites web d'ouvrir automatiquement de nouvelles fenêtres sur votre Bureau.
it.ro.HelpContentConfig3:This indicates whether NetSurf will stop web sites from automatically opening new windows on your desktop.
nl.ro.HelpContentConfig3:This indicates whether NetSurf will stop web sites from automatically opening new windows on your desktop.
en.ro.HelpContentConfig4:This indicates whether NetSurf will allow external plug-ins to handle additional types of content, such as Flash.
de.ro.HelpContentConfig4:Stellt ein, ob externe Pluginroutinen genutzt werden dürfen, um Zusatzinhalte darzustellen (z.B. Flash).
fr.ro.HelpContentConfig4:Ceci indique si Netsurf doit autoriser les plug-ins externes à manipuler des types de contenu supplémentaires, comme le Flash.
it.ro.HelpContentConfig4:This indicates whether NetSurf will allow external plug-ins to handle additional types of content, such as Flash.
nl.ro.HelpContentConfig4:This indicates whether NetSurf will allow external plug-ins to handle additional types of content, such as Flash.
en.ro.HelpContentConfig7:This indicates whether NetSurf will allow links to open in new windows.
de.ro.HelpContentConfig7:Stellt ein, ob NetSurf erlaubt, daß Links beim Aufruf neue Browserfenster öffnen dürfen.
fr.ro.HelpContentConfig7:This indicates whether NetSurf will allow links to open in new windows.
it.ro.HelpContentConfig7:This indicates whether NetSurf will allow links to open in new windows.
nl.ro.HelpContentConfig7:This indicates whether NetSurf will allow links to open in new windows.
en.ro.HelpContentConfig8:\Sreset the Content options back to their default values.
de.ro.HelpContentConfig8:Stellt die Standardeinstellungen wieder her.
fr.ro.HelpContentConfig8:\Srevenir aux valeurs par défaut des options du Contenu.
it.ro.HelpContentConfig8:\Sreset the Content options back to their default values.
nl.ro.HelpContentConfig8:\Sreset the Content options back to their default values.
en.ro.HelpContentConfig9:\Sclose this \w without saving changes.|M\Areturn the content options to the last saved configuration.
de.ro.HelpContentConfig9:Klicken mit AUSWAHL schließt das Fenster ohne die Änderungen zu speichern.|MKlicken mit SPEZIAL stellt die zuletzt abgespeicherten Einstellungen wieder her.
fr.ro.HelpContentConfig9:\Sfermer cette fenêtre sans sauver les changements|M\Arevenir aux options de Contenu précédemment sauvegardées.
it.ro.HelpContentConfig9:\Sclose this \w without saving changes.|M\Areturn the content options to the last saved configuration.
nl.ro.HelpContentConfig9:\Sclose this \w without saving changes.|M\Areturn the cache options to the last saved configuration.
en.ro.HelpContentConfig10:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
de.ro.HelpContentConfig10:Klicken mit AUSWAHL speichert die Einstellungen und schließt das Fenster.|MKlicken mit SPEZIAL speichert die Einstellungen ohne das Fenster zu schließen.
fr.ro.HelpContentConfig10:\Ssauver ces réglages et fermer la fenêtre.|M\Asauver ces réglages sans fermer la fenêtre.
it.ro.HelpContentConfig10:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
nl.ro.HelpContentConfig10:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
 
en.ro.HelpFontConfig:\Tfont configuration \w
de.ro.HelpFontConfig:Konfigurationsfenster zur Einstellung der verwendeten Schriftarten
fr.ro.HelpFontConfig:\Tla fenêtre de configuration de Fontes
it.ro.HelpFontConfig:\Tfont configuration \w
nl.ro.HelpFontConfig:\font configuration \w
en.ro.HelpFontConfig3:\Tcurrently selected sans-serif font.|MNetSurf will use this font wherever a web page specifies a sans-serif typeface.
de.ro.HelpFontConfig3:Das ist die aktuell gewählte Schriftart für Sans-serif.|MNetSurf wird diese Schriftart überall dort verwenden, wo von der Webseite ein Schriftbild in Sans-serif vorgegeben wird.
fr.ro.HelpFontConfig3:\Tla fonte sans-sérif actuellement sélectionnée.|MNetsurf utilisera cette fonte à chaque fois qu'une page web spécifiera une police sans-sérif.
it.ro.HelpFontConfig3:\Tcurrently selected sans-serif font.|MNetSurf will use this font wherever a web page specifies a sans-serif typeface.
nl.ro.HelpFontConfig3:\Tcurrently selected sans-serif font.|MNetSurf will use this font wherever a web page specifies a sans-serif typeface.
en.ro.HelpFontConfig4:\Sselect a sans-serif font.
de.ro.HelpFontConfig4:Klicken mit AUSWAHL, um eine Schriftart auszuwählen.
fr.ro.HelpFontConfig4:\Ssélectionner une fonte sans-sérif.
it.ro.HelpFontConfig4:\Sseleziona un font sans-serif
nl.ro.HelpFontConfig4:\Sselect a sans-serif font.
en.ro.HelpFontConfig6:\Tcurrently selected serif font.|MNetSurf will use this font wherever a web page specifies a serif typeface.
de.ro.HelpFontConfig6:Das ist die aktuell gewählte Schriftart für Serif.|MNetSurf wird diese Schriftart überall dort verwenden, wo von der Webseite ein Schriftbild in Serif vorgegeben wird.
fr.ro.HelpFontConfig6:\Tla fonte sérif actuellement sélectionnée.|MNetsurf utilisera cette fonte à chaque fois qu'une page web spécifiera une police sérif.
it.ro.HelpFontConfig6:\Tcurrently selected serif font.|MNetSurf will use this font wherever a web page specifies a serif typeface.
nl.ro.HelpFontConfig6:\Tcurrently selected serif font.|MNetSurf will use this font wherever a web page specifies a serif typeface.
en.ro.HelpFontConfig7:\Sselect a sans-serif font.
de.ro.HelpFontConfig7:Klicken mit AUSWAHL, um eine Schriftart auszuwählen.
fr.ro.HelpFontConfig7:\Ssélectionner une fonte sérif.
it.ro.HelpFontConfig7:\Sseleziona un font sans-serif
nl.ro.HelpFontConfig7:\Sselect a sans-serif font.
en.ro.HelpFontConfig9:\Tcurrently selected monospace font.|MNetSurf will use this font wherever a web page specifies a monospace typeface.
de.ro.HelpFontConfig9:Das ist die aktuell gewählte Schriftart für Monospace.|MNetSurf wird diese Schriftart überall dort verwenden, wo von der Webseite ein Schriftbild in Monospace vorgegeben wird.
fr.ro.HelpFontConfig9:\Tla fonte sérif actuellement sélectionnée.|MNetsurf utilisera cette fonte à chaque fois qu'une page web spécifiera une police monospace.
it.ro.HelpFontConfig9:\Tcurrently selected monospace font.|MNetSurf will use this font wherever a web page specifies a monospace typeface.
nl.ro.HelpFontConfig9:\Tcurrently selected monospace font.|MNetSurf will use this font wherever a web page specifies a monospace typeface.
en.ro.HelpFontConfig10:\Sselect a monospace font.
de.ro.HelpFontConfig10:Klicken mit AUSWAHL, um eine Schriftart auszuwählen.
fr.ro.HelpFontConfig10:\Ssélectionner une fonte monospace.
it.ro.HelpFontConfig10:\Sseleziona un font monospaziato
nl.ro.HelpFontConfig10:\Sselect a monospace font.
en.ro.HelpFontConfig12:\Tcurrently selected cursive font.|MNetSurf will use this font wherever a web page specifies a cursive typeface.
de.ro.HelpFontConfig12:Das ist die aktuell gewählte Schriftart für Kursiv.|MNetSurf wird diese Schriftart überall dort verwenden, wo von der Webseite ein Schriftbild in Kursiv vorgegeben wird.
fr.ro.HelpFontConfig12:\Tla fonte cursive actuellement sélectionnée.|MNetsurf utilisera cette fonte à chaque fois qu'une page web spécifiera une police cursive.
it.ro.HelpFontConfig12:\Tcurrently selected cursive font.|MNetSurf will use this font wherever a web page specifies a cursive typeface.
nl.ro.HelpFontConfig12:\Tcurrently selected cursive font.|MNetSurf will use this font wherever a web page specifies a cursive typeface.
en.ro.HelpFontConfig13:\Sselect a cursive font.
de.ro.HelpFontConfig13:Klicken mit AUSWAHL, um eine Schriftart auszuwählen.
fr.ro.HelpFontConfig13:\Ssélectionner une fonte cursive.
it.ro.HelpFontConfig13:\Sseleziona un font corsivo
nl.ro.HelpFontConfig13:\Sselect a cursive font.
en.ro.HelpFontConfig15:\Tcurrently selected fantasy font.|MNetSurf will use this font wherever a web page specifies a fantasy typeface.
de.ro.HelpFontConfig15:Das ist die aktuell gewählte Schriftart für Fantasy.|MNetSurf wird diese Schriftart überall dort verwenden, wo von der Webseite ein Schriftbild in Fantasy vorgegeben wird.
fr.ro.HelpFontConfig15:\Tla fonte fantaisie actuellement sélectionnée.|MNetsurf utilisera cette fonte à chaque fois qu'une page web spécifiera une police fantaisie.
it.ro.HelpFontConfig15:\Tcurrently selected fantasy font.|MNetSurf will use this font wherever a web page specifies a fantasy typeface.
nl.ro.HelpFontConfig15:\Tcurrently selected fantasy font.|MNetSurf will use this font wherever a web page specifies a fantasy typeface.
en.ro.HelpFontConfig16:\Sselect a fantasy font.
de.ro.HelpFontConfig16:Klicken mit AUSWAHL, um eine Schriftart auszuwählen.
fr.ro.HelpFontConfig16:\Ssélectionner une fonte fantaisie.
it.ro.HelpFontConfig16:\Sseleziona un font fantasia
nl.ro.HelpFontConfig16:\Sselect a fantasy font.
en.ro.HelpFontConfig18:\Tcurrently selected font family.|MNetSurf will use this wherever a web page does not specify a typeface.
de.ro.HelpFontConfig18:Das ist die aktuell gewählte Schriftart für die Standardtextanzeige.|MNetSurf wird diese Schriftart überall dort verwenden, wo von der Webseite KEIN bestimmtes Schriftbild vorgegeben wird.
fr.ro.HelpFontConfig18:\Tla famille de fontes actuellement sélectionnée.|MNetsurf utilisera cette fonte à chaque fois qu'une page web ne spécifiera aucune police.
it.ro.HelpFontConfig18:\Tcurrently selected font family.|MNetSurf will use this wherever a web page does not specify a typeface.
nl.ro.HelpFontConfig18:\Tcurrently selected font family.|MNetSurf will use this wherever a web page does not specify a typeface.
en.ro.HelpFontConfig19:\Sselect a default font family.
de.ro.HelpFontConfig19:Klicken mit AUSWAHL, um eine Schriftart auszuwählen.
fr.ro.HelpFontConfig19:\Ssélectionner une famille de fontes par défaut.
it.ro.HelpFontConfig19:\Sseleziona una famiglia font predefinita
nl.ro.HelpFontConfig19:\Sselect a default font family.
en.ro.HelpFontConfig23:You can enter a default font size here.|MNetSurf will use this wherever a web page does not specify a font size of its own.
de.ro.HelpFontConfig23:Hier kann eine Standarfontgröße gewählt werden.|MNetSurf wird diese Größe immer dann verwenden, wenn von der Webseite keine eigene Schriftgröße eingestellt wird.
fr.ro.HelpFontConfig23:Vous pouvez entrer ici une taille par défaut.|MNetsurf l'utilisera chaque fois qu'une page web ne spécifiera pas de taille de fonte.
it.ro.HelpFontConfig23:You can enter a default font size here.|MNetSurf will use this wherever a web page does not specify a font size of its own.
nl.ro.HelpFontConfig23:You can enter a default font size here.|MNetSurf will use this wherever a web page does not specify a font size of its own.
en.ro.HelpFontConfig24:\Sreduce the default font size.
de.ro.HelpFontConfig24:Klicken mit AUSWAHL verkleinert die Standardfontgröße.
fr.ro.HelpFontConfig24:\Sréduire la taille de fonte.
it.ro.HelpFontConfig24:\Sriduce la dimensione del font predefinito
nl.ro.HelpFontConfig24:\Sreduce the default font size.
en.ro.HelpFontConfig25:\Sincrease the default font size.
de.ro.HelpFontConfig25:Klicken mit AUSWAHL vergrößert die Standardfontgröße.
fr.ro.HelpFontConfig25:\Saugmenter la taille de fonte.
it.ro.HelpFontConfig25:\Saumenta la dimensione del font predefinito
nl.ro.HelpFontConfig25:\Sincrease the default font size.
en.ro.HelpFontConfig28:You can enter a minimum font size here.|MNetSurf will not allow web pages to display smaller text than this.
de.ro.HelpFontConfig28:Hier kann eine minimale Schriftgröße eingestellt werden.|MNetSurf wird keine Darstellung von noch kleineren Schriften zulassen.
fr.ro.HelpFontConfig28:Vous pouvez entrer ici une taille de fonte minimum.|MNetsurf ne permettra pas aux pages web d'afficher un texte ayant une taille plus petite.
it.ro.HelpFontConfig28:You can enter a minimum font size here.|MNetSurf will not allow web pages to display smaller text than this.
nl.ro.HelpFontConfig28:You can enter a minimum font size here.|MNetSurf will not allow web pages to display smaller text than this.
en.ro.HelpFontConfig29:\Sreduce the minimum font size.
de.ro.HelpFontConfig29:Klicken mit AUSWAHL verkleinert die minimal zugelassene Schriftgröße.
fr.ro.HelpFontConfig29:\Sréduire la taille de fonte minimum.
it.ro.HelpFontConfig29:\Sriduce la dimensione minima del font
nl.ro.HelpFontConfig29:\Sreduce the minimum font size.
en.ro.HelpFontConfig30:\Sincrease the minimum font size.
de.ro.HelpFontConfig30:Klicken mit AUSWAHL vergrößert die minimal zugelassene Schriftgröße.
fr.ro.HelpFontConfig30:\Saugmenter la taille de fonte minimum.
it.ro.HelpFontConfig30:\Saumenta la dimensione minima del font
nl.ro.HelpFontConfig30:\Sincrease the minimum font size.
en.ro.HelpFontConfig32:\Sreset the Font options back to their default values.
de.ro.HelpFontConfig32:Stellt die Standardeinstellungen wieder her.
fr.ro.HelpFontConfig32:\Srevenir aux valeurs par défaut des options de Fontes.
it.ro.HelpFontConfig32:\Sripristina le impostazioni dei font ai loro valori originali
nl.ro.HelpFontConfig32:\Sreset the Font options back to their default values.
en.ro.HelpFontConfig33:\Sclose this \w without saving changes.|M\Areturn the font options to the last saved configuration.
de.ro.HelpFontConfig33:Klicken mit AUSWAHL schließt das Fenster ohne die Änderungen zu speichern.|MKlicken mit SPEZIAL stellt die zuletzt abgespeicherten Einstellungen wieder her.
fr.ro.HelpFontConfig33:\Sfermer cette fenêtre sans sauver les changements|M\Arevenir aux options de Fontes précédemment sauvegardées.
it.ro.HelpFontConfig33:\Sclose this \w without saving changes.|M\Areturn the font options to the last saved configuration.
nl.ro.HelpFontConfig33:\Sclose this \w without saving changes.|M\Areturn the cache options to the last saved configuration.
en.ro.HelpFontConfig34:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
de.ro.HelpFontConfig34:Klicken mit AUSWAHL speichert die Einstellungen und schließt das Fenster.|MKlicken mit SPEZIAL speichert die Einstellungen ohne das Fenster zu schließen.
fr.ro.HelpFontConfig34:\Ssauver ces réglages et fermer la fenêtre.|M\Asauver ces réglages sans fermer la fenêtre.
it.ro.HelpFontConfig34:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
nl.ro.HelpFontConfig34:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
 
en.ro.HelpHomeConfig:\Thome page configuration \w
de.ro.HelpHomeConfig:Homepage Konfiguration
fr.ro.HelpHomeConfig:\Tla fenêtre de configuration de Page d'accueil
it.ro.HelpHomeConfig:\Thome page configuration \w
nl.ro.HelpHomeConfig:\Thome page configuration \w
en.ro.HelpHomeConfig3:You can enter a default home page address here.
de.ro.HelpHomeConfig3:Hier kann die Webadresse der Homepage eingegeben werden.
fr.ro.HelpHomeConfig3:Vous pouvez entrer ici une page d'accueil par défaut.
it.ro.HelpHomeConfig3:You can enter a default home page address here.
nl.ro.HelpHomeConfig3:You can enter a default home page address here.
en.ro.HelpHomeConfig4:\Sselect a recently typed URL.|MThese addresses have recently been typed into a NetSurf browser \w's URL bar.
de.ro.HelpHomeConfig4:Klicken mit AUSWAHL zur schnellen Auswahl einer Adresse.|MDie angezeigten Adressen wurden in letzter Zeit in die Adressleiste eines Browserfensters eingegeben.
fr.ro.HelpHomeConfig4:\Ssélectionner une URL récemment tapée.|MCes adresses ont été récemment tapées dans la barre d'URL du navigateur Netsurf.
it.ro.HelpHomeConfig4:\Sselect a recently typed URL.|MThese addresses have recently been typed into a NetSurf browser \w's URL bar.
nl.ro.HelpHomeConfig4:\Sselect a recently typed URL.|MThese addresses have recently been typed into a NetSurf browser \w's URL bar.
en.ro.HelpHomeConfig5:This indicates whether NetSurf will open a browser \w on start-up.
de.ro.HelpHomeConfig5:Stellt ein, ob NetSurf beim Starten automatisch ein Browserfenster öffnet.
fr.ro.HelpHomeConfig5:Ceci indique si Netsurf doit ouvrir une fenêtre de navigation au démarrage.
it.ro.HelpHomeConfig5:This indicates whether NetSurf will open a browser \w on start-up.
nl.ro.HelpHomeConfig5:This indicates whether NetSurf will open a browser \w on start-up.
en.ro.HelpHomeConfig6:\Sreset the Home page options back to their default values.
de.ro.HelpHomeConfig6:Stellt die Standardeinstellungen wieder her.
fr.ro.HelpHomeConfig6:\Srevenir aux valeurs par défaut des options de Page d'accueil.
it.ro.HelpHomeConfig6:\Sreset the Home page options back to their default values.
nl.ro.HelpHomeConfig6:\Sreset the Home page options back to their default values.
en.ro.HelpHomeConfig7:\Sclose this \w without saving changes.|M\Areturn the home options to the last saved configuration.
de.ro.HelpHomeConfig7:Klicken mit AUSWAHL schließt das Fenster ohne die Änderungen zu speichern.|MKlicken mit SPEZIAL stellt die zuletzt abgespeicherten Einstellungen wieder her.
fr.ro.HelpHomeConfig7:\Sfermer cette fenêtre sans sauver les changements|M\Arevenir aux options de Page d'accueil précédemment sauvegardées.
it.ro.HelpHomeConfig7:\Sclose this \w without saving changes.|M\Areturn the home options to the last saved configuration.
nl.ro.HelpHomeConfig7:\Sclose this \w without saving changes.|M\Areturn the cache options to the last saved configuration.
en.ro.HelpHomeConfig8:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
de.ro.HelpHomeConfig8:Klicken mit AUSWAHL speichert die Einstellungen und schließt das Fenster.|MKlicken mit SPEZIAL speichert die Einstellungen ohne das Fenster zu schließen.
fr.ro.HelpHomeConfig8:\Ssauver ces réglages et fermer la fenêtre.|M\Asauver ces réglages sans fermer la fenêtre.
it.ro.HelpHomeConfig8:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
nl.ro.HelpHomeConfig8:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
 
en.ro.HelpImageConfig:\Timage configuration \w
de.ro.HelpImageConfig:Das ist das Fenster zur Konfiguration der Bilddarstellungsoptionen.
fr.ro.HelpImageConfig:\Tla fenêtre de configuration d'Image
it.ro.HelpImageConfig:\Timage configuration \w
nl.ro.HelpImageConfig:\Timage configuration \w
en.ro.HelpImageConfig3:\Tcurrently selected foreground image quality.
de.ro.HelpImageConfig3:Das ist die aktuell gewählte Qualität für die Darstellung der Vordergrundbilder.
fr.ro.HelpImageConfig3:\Tla qualité d'image de premier plan sélectionnée actuellement.
it.ro.HelpImageConfig3:\Tcurrently selected foreground image quality.
nl.ro.HelpImageConfig3:\Tcurrently selected foreground image quality.
en.ro.HelpImageConfig4:\Sselect a foreground image quality setting.|MError diffused provides the highest quality.
de.ro.HelpImageConfig4:Klicken mit AUSWAHL zur Wahl der Anzeigequalität für Vordergrundbilder.|MError-Diffusion bietet die beste Qualität.
fr.ro.HelpImageConfig4:\Schoisir un réglage de qualité pour les images de premier plan.|MAvec diffusion d'erreur correspond à la meilleure qualité.
it.ro.HelpImageConfig4:\Sselect a foreground image quality setting.|MError diffused provides the highest quality.
nl.ro.HelpImageConfig4:\Sselect a foreground image quality setting.|MError diffused provides the highest quality.
en.ro.HelpImageConfig6:\Tcurrently selected background image quality.
de.ro.HelpImageConfig6:Das ist die aktuell gewählte Qualität für die Darstellung der Hintergrundbilder.
fr.ro.HelpImageConfig6:\Tla qualité d'image de fond sélectionnée actuellement.
it.ro.HelpImageConfig6:\Tcurrently selected background image quality.
nl.ro.HelpImageConfig6:\Tcurrently selected background image quality.
en.ro.HelpImageConfig7:\Sselect a background image quality setting.|MError diffused provides the highest quality.
de.ro.HelpImageConfig7:Klicken mit AUSWAHL zur Wahl der Anzeigequalität für Hintergrundbilder.|MError-Diffusion bietet die beste Qualität.
fr.ro.HelpImageConfig7:\Schoisir un réglage de qualité pour les images de fond.|MAvec diffusion d'erreur correspond à la meilleure qualité.
it.ro.HelpImageConfig7:\Sselect a background image quality setting.|MError diffused provides the highest quality.
nl.ro.HelpImageConfig7:\Sselect a background image quality setting.|MError diffused provides the highest quality.
en.ro.HelpImageConfig8:\Timage quality preview image.|MThe optimum results are achived with both foreground and background image quality set to error diffused.|MThe user guide provides more information on the implications of these options.
de.ro.HelpImageConfig8:Das ist das Vorschaubild.|MDie qualitativ besten Anzeigeresultate werden erzielt, wenn Vorder- und Hintergrundbilder per Error-Diffusion dargestellt werden.|MGenauere Informationen gibt es in der Dokumentation.
fr.ro.HelpImageConfig8:\Timage de prévisualisation de qualité d'image.|MLes résultats optimaux sont obtenus avec des images de premier plan et de fond avec diffusion d'erreur.|MLe guide utilisateur fournit plus d'informations quant aux implications de cette option.
it.ro.HelpImageConfig8:\Timage quality preview image.|MThe optimum results are achived with both foreground and background image quality set to error diffused.|MThe user guide provides more information on the implications of these options.
nl.ro.HelpImageConfig8:\Timage quality preview image.|MThe optimum results are achived with both foreground and background image quality set to error diffused.|MThe user guide provides more information on the implications of these options.
en.ro.HelpImageConfig12:You can enter the minimum time between animation frames here.|MA very low setting can cause your computer to slow down when rapid animations are displayed and is not suitable for slow computers.
de.ro.HelpImageConfig12:Hier kann die minimale Zeitverzögerung zwischen den Frames einer Animation vorgegeben werden.|MSehr niedrige Werte können bei raschen Animationen hohe Rechenleistungen erfordern und sind darum nicht geeignet für langsamere Computer.
fr.ro.HelpImageConfig12:Vous pouvez entrer ici le temps minimum entre deux images d'animation.|MUn réglage trop bas peut ralentir les animations affichées et ne convient pas à des ordinateurs lents.
it.ro.HelpImageConfig12:You can enter the minimum time between animation frames here.|MA very low setting can cause your computer to slow down when rapid animations are displayed and is not suitable for slow computers.
nl.ro.HelpImageConfig12:You can enter the minimum time between animation frames here.|MA very low setting can cause your computer to slow down when rapid animations are displayed and is not suitable for slow computers.
en.ro.HelpImageConfig13:\Sreduce the minimum time between animation frames.
de.ro.HelpImageConfig13:Klicken mit AUSWAHL verkleinert die minimale Wartezeit zwischen aufeinanderfolgenden Einzelbildern einer Animation.
fr.ro.HelpImageConfig13:\Sréduire le temps minimum entre deux images d'animation.
it.ro.HelpImageConfig13:\Sreduce the minimum time between animation frames.
nl.ro.HelpImageConfig13:\Sreduce the minimum time between animation frames.
en.ro.HelpImageConfig14:\Sincrease the minimum time between animation frames.
de.ro.HelpImageConfig14:Klicken mit AUSWAHL vergrößert die minimale Wartezeit zwischen aufeinanderfolgenden Einzelbildern einer Animation.
fr.ro.HelpImageConfig14:\Saugmenter le temps minimum entre deux images d'animation.
it.ro.HelpImageConfig14:\Sincrease the minimum time between animation frames.
nl.ro.HelpImageConfig14:\Sincrease the minimum time between animation frames.
en.ro.HelpImageConfig16:This indicates whether NetSurf will disable animations on web pages.|MWhen animations are disabled, NetSurf will show the first frame as a static image.
de.ro.HelpImageConfig16:Erlaubt das Abschalten der Animationsdarstellung auf Webseiten.|MSind die Animationen abgeschaltet, wird von NetSurf lediglich das erste Einzelbild der Animationsfolge als einfaches Bild angezeigt.
fr.ro.HelpImageConfig16:Ceci indique si Netsurf doit annuler les animations des pages web.|MLorsque les animations sont désactivées, Netsurf utilisera la première image comme image statique.
it.ro.HelpImageConfig16:This indicates whether NetSurf will disable animations on web pages.|MWhen animations are disabled, NetSurf will show the first frame as a static image.
nl.ro.HelpImageConfig16:This indicates whether NetSurf will disable animations on web pages.|MWhen animations are disabled, NetSurf will show the first frame as a static image.
en.ro.HelpImageConfig17:\Sreset the Image options back to their default values.
de.ro.HelpImageConfig17:Stellt die Bildoptionen zurück auf die Standardwerte.
fr.ro.HelpImageConfig17:\Srevenir aux valeurs par défaut des options d'Image.
it.ro.HelpImageConfig17:\Sreset the Image options back to their default values.
nl.ro.HelpImageConfig17:\Sreset the Image options back to their default values.
en.ro.HelpImageConfig18:\Sclose this \w without saving changes.|M\Areturn the image options to the last saved configuration.
de.ro.HelpImageConfig18:Klicken mit AUSWAHL schließt das Fenster ohne die Änderungen zu speichern.|MKlicken mit SPEZIAL stellt die zuletzt abgespeicherten Einstellungen wieder her.
fr.ro.HelpImageConfig18:\Sfermer cette fenêtre sans sauver les changements|M\Arevenir aux options d'Image précédemment sauvegardées.
it.ro.HelpImageConfig18:\Sclose this \w without saving changes.|M\Areturn the image options to the last saved configuration.
nl.ro.HelpImageConfig18:\Sclose this \w without saving changes.|M\Areturn the cache options to the last saved configuration.
en.ro.HelpImageConfig19:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
de.ro.HelpImageConfig19:Klicken mit AUSWAHL speichert die Einstellungen und schließt das Fenster.|MKlicken mit SPEZIAL speichert die Einstellungen ohne das Fenster zu schließen.
fr.ro.HelpImageConfig19:\Ssauver ces réglages et fermer la fenêtre.|M\Asauver ces réglages sans fermer la fenêtre.
it.ro.HelpImageConfig19:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
nl.ro.HelpImageConfig19:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
 
en.ro.HelpInterfaceConfig:\Tinterface configuration \w
de.ro.HelpInterfaceConfig:Fenster zur Einstellung des Programmverhaltens in ausgewählten Situationen
fr.ro.HelpInterfaceConfig:\Tla fenêtre de configuration d'interface
it.ro.HelpInterfaceConfig:\Tinterface configuration \w
nl.ro.HelpInterfaceConfig:\Tinterface configuration \w
en.ro.HelpInterfaceConfig2:This indicates whether NetSurf will strip file extensions when saving files to disc.
de.ro.HelpInterfaceConfig2:Beim Abspeichern von Dateien auf einen Datenträger werden die Dateinamenserweiterungen (Extensions) aus dem Dateinamen entfernt.
fr.ro.HelpInterfaceConfig2:Ceci indique si Netsurf supprime les extensions de fichiers lors d'une sauvegarde sur disque.
it.ro.HelpInterfaceConfig2:This indicates whether NetSurf will strip file extensions when saving files to disc.
nl.ro.HelpInterfaceConfig2:This indicates whether NetSurf will strip file extensions when saving files to disc.
en.ro.HelpInterfaceConfig3:This indicates whether NetSurf will ask for confirmation before overwriting files of the same name.
de.ro.HelpInterfaceConfig3:Beim Abspeichern wird vor dem Ãœberschreiben namensgleicher Dateien von NetSurf nachgefragt, ob dies so erfolgen soll.
fr.ro.HelpInterfaceConfig3:Ceci indique si Netsurf doit demander confirmation avant d'écraser des fichiers portant le même nom.
it.ro.HelpInterfaceConfig3:This indicates whether NetSurf will ask for confirmation before overwriting files of the same name.
nl.ro.HelpInterfaceConfig3:This indicates whether NetSurf will ask for confirmation before overwriting files of the same name.
en.ro.HelpInterfaceConfig6:This indicates whether NetSurf's URL suggestion feature is enabled.|MURL suggestion shows options for completing URLs as you type into NetSurf's URL bar.
de.ro.HelpInterfaceConfig6:Fantastisches Feature zum automatischen Vorschlagen von URL Adressen bei deren Eingabe.|MDiese Funktion zeigt bei der Eingabe von Webadressen in die Adressleiste mögliche sinnvolle Adressvorschläge während des Eintippens an.
fr.ro.HelpInterfaceConfig6:Ceci indique si la fontion de suggestion d'URL de Netsurf est activée.|MLa suggestion d'URL montre les possibilités de complétion d'URL au fur et à mesure où elles sont tapées dans la barre.
it.ro.HelpInterfaceConfig6:This indicates whether NetSurf's URL suggestion feature is enabled.|MURL suggestion shows options for completing URLs as you type into NetSurf's URL bar.
nl.ro.HelpInterfaceConfig6:This indicates whether NetSurf's URL suggestion feature is enabled.|MURL suggestion shows options for completing URLs as you type into NetSurf's URL bar.
en.ro.HelpInterfaceConfig7:This indicates whether the URL for the item under the pointer in NetSurf's local history \w will be displayed.
de.ro.HelpInterfaceConfig7:In der lokalen History werden die Adressen der besuchten Webseiten schwebend über den zugehörigen Bildern eingeblendet.
fr.ro.HelpInterfaceConfig7:Ceci indique si l'URL de l'item sous le pointeur dans la fenêtre d'historique local doit être affiché.
it.ro.HelpInterfaceConfig7:This indicates whether the URL for the item under the pointer in NetSurf's local history \w will be displayed.
nl.ro.HelpInterfaceConfig7:This indicates whether the URL for the item under the pointer in NetSurf's local history \w will be displayed.
en.ro.HelpInterfaceConfig10:This indicates whether NetSurf will use a thumbnail when iconising windows to the Pinboard.
de.ro.HelpInterfaceConfig10:Beim verkleinernden Ablegen eines Browserfensters auf dem Desktophintergrund (Iconisieren) wird von NetSurf ein fensterspezifisches Icon erzeugt, welches den aktuellen Seiteninhalt wiedergibt.
fr.ro.HelpInterfaceConfig10:Ceci indique si Netsurf doit utiliser une miniature lors de l'iconisation vers le Punaiseur (Pinboard).
it.ro.HelpInterfaceConfig10:This indicates whether NetSurf will use a thumbnail when iconising windows to the Pinboard.
nl.ro.HelpInterfaceConfig10:This indicates whether NetSurf will use a thumbnail when iconising windows to the Pinboard.
en.ro.HelpInterfaceConfig11:\Sreset the Interface options back to their default values.
de.ro.HelpInterfaceConfig11:Stellt die Standardeinstellungen wieder her.
fr.ro.HelpInterfaceConfig11:\Srevenir aux valeurs par défaut des options d'Interface.
it.ro.HelpInterfaceConfig11:\Sreset the Interface options back to their default values.
nl.ro.HelpInterfaceConfig11:\Sreset the Interface options back to their default values.
en.ro.HelpInterfaceConfig12:\Sclose this \w without saving changes.|M\Areturn the interface options to the last saved configuration.
de.ro.HelpInterfaceConfig12:Klicken mit AUSWAHL schließt das Fenster ohne die Änderungen zu speichern.|MKlicken mit SPEZIAL stellt die zuletzt abgespeicherten Einstellungen wieder her.
fr.ro.HelpInterfaceConfig12:\Sfermer cette fenêtre sans sauver les changements|M\Arevenir aux options d'Interface précédemment sauvegardées.
it.ro.HelpInterfaceConfig12:\Sclose this \w without saving changes.|M\Areturn the interface options to the last saved configuration.
nl.ro.HelpInterfaceConfig12:\Sclose this \w without saving changes.|M\Areturn the cache options to the last saved configuration.
en.ro.HelpInterfaceConfig13:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
de.ro.HelpInterfaceConfig13:Klicken mit AUSWAHL speichert die Einstellungen und schließt das Fenster.|MKlicken mit SPEZIAL speichert die Einstellungen ohne das Fenster zu schließen.
fr.ro.HelpInterfaceConfig13:\Ssauver ces réglages et fermer la fenêtre.|M\Asauver ces réglages sans fermer la fenêtre.
it.ro.HelpInterfaceConfig13:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
nl.ro.HelpInterfaceConfig13:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
en.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
de.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
fr.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
it.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
nl.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
en.ro.HelpInterfaceConfig18:\Tthe path to a hotlist application which will be used to display the hotlist.
de.ro.HelpInterfaceConfig18:\Tthe path to a hotlist application which will be used to display the hotlist.
fr.ro.HelpInterfaceConfig18:\Tthe path to a hotlist application which will be used to display the hotlist.
it.ro.HelpInterfaceConfig18:\Tthe path to a hotlist application which will be used to display the hotlist.
nl.ro.HelpInterfaceConfig18:\Tthe path to a hotlist application which will be used to display the hotlist.
 
en.ro.HelpLanguageConfig:\Tlanguage configuration \w
de.ro.HelpLanguageConfig:Konfigurationsfenster für die Spracheinstellungen
fr.ro.HelpLanguageConfig:\Tfenêtre de configuration de langue.
it.ro.HelpLanguageConfig:\Tlanguage configuration \w
nl.ro.HelpLanguageConfig:\Tlanguage configuration \w
en.ro.HelpLanguageConfig3:\Tcurrently selected interface language.|MThe interface language is the language used for NetSurf's messages and dialogue boxes.
de.ro.HelpLanguageConfig3:Das ist die aktuell eingestellte Sprache für die Bedienoberfläche.|MDiese Sprache wird genutzt, um NetSurf's Meldungen und die Texte der Dialogboxen und Menüs darzustellen.
fr.ro.HelpLanguageConfig3:\Tla langue d'interface sélectionnée actuellement.|MLa langue d'interface est la langue utilisée pour les messages et les boîtes de dialogue de Netsurf.
it.ro.HelpLanguageConfig3:\Tcurrently selected interface language.|MThe interface language is the language used for NetSurf's messages and dialogue boxes.
nl.ro.HelpLanguageConfig3:\Tcurrently selected interface language.|MThe interface language is the language used for NetSurf's messages and dialogue boxes.
en.ro.HelpLanguageConfig4:\Sselect an interface language.
de.ro.HelpLanguageConfig4:Klicken mit AUSWAHL zum Auswählen einer Oberflächensprache.
fr.ro.HelpLanguageConfig4:\Schoisir une langue d'interface.
it.ro.HelpLanguageConfig4:\Sselect an interface language.
nl.ro.HelpLanguageConfig4:\Sselect an interface language.
en.ro.HelpLanguageConfig6:\Tcurrently selected web page language.|MIf a web site provides a choice of languages, NetSurf will request the page in your preferred language.
de.ro.HelpLanguageConfig6:Das ist die aktuelle Sprache zur Anzeige auf Webseiten.|MWenn eine Webseite die Darstellung in verschiedenen Sprachen anbietet, wird NetSurf die Webseite in der hier eingestellten bevorzugten Sprache abrufen.
fr.ro.HelpLanguageConfig6:\Tla langue de page web sélectionnée actuellement.|MSi un site web fournit un choix de langues, Netsurf demandera la page dans votre langue favorite.
it.ro.HelpLanguageConfig6:\Tcurrently selected web page language.|MIf a web site provides a choice of languages, NetSurf will request the page in your preferred language.
nl.ro.HelpLanguageConfig6:\Tcurrently selected web page language.|MIf a web site provides a choice of languages, NetSurf will request the page in your preferred language.
en.ro.HelpLanguageConfig7:\Sselect a preferred web page language.
de.ro.HelpLanguageConfig7:Klicken mit AUSWAHL zum Auswählen einer Webseitensprache.
fr.ro.HelpLanguageConfig7:\Schoisir une langue de page web préférée.
it.ro.HelpLanguageConfig7:\Sselect a preferred web page language.
nl.ro.HelpLanguageConfig7:\Sselect a preferred web page language.
en.ro.HelpLanguageConfig8:\Sreset the Language options back to their default values.
de.ro.HelpLanguageConfig8:Stellt die Standardeinstellungen wieder her.
fr.ro.HelpLanguageConfig8:\Srevenir aux valeurs par défaut des options de Langue.
it.ro.HelpLanguageConfig8:\Sreset the Language options back to their default values.
nl.ro.HelpLanguageConfig8:\Sreset the Language options back to their default values.
en.ro.HelpLanguageConfig9:\Sclose this \w without saving changes.|M\Areturn the language options to the last saved configuration.
de.ro.HelpLanguageConfig9:Klicken mit AUSWAHL schließt das Fenster ohne die Änderungen zu speichern.|MKlicken mit SPEZIAL stellt die zuletzt abgespeicherten Einstellungen wieder her.
fr.ro.HelpLanguageConfig9:\Sfermer cette fenêtre sans sauver les changements|M\Arevenir aux options de Langue précédemment sauvegardées.
it.ro.HelpLanguageConfig9:\Sclose this \w without saving changes.|M\Areturn the language options to the last saved configuration.
nl.ro.HelpLanguageConfig9:\Sclose this \w without saving changes.|M\Areturn the cache options to the last saved configuration.
en.ro.HelpLanguageConfig10:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
de.ro.HelpLanguageConfig10:Klicken mit AUSWAHL speichert die Einstellungen und schließt das Fenster.|MKlicken mit SPEZIAL speichert die Einstellungen ohne das Fenster zu schließen.
fr.ro.HelpLanguageConfig10:\Ssauver ces réglages et fermer la fenêtre.|M\Asauver ces réglages sans fermer la fenêtre.
it.ro.HelpLanguageConfig10:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
nl.ro.HelpLanguageConfig10:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
 
en.ro.HelpMemoryConfig:\Tmemory configuration \w
de.ro.HelpMemoryConfig:Fenster zur Konfiguration des nutzbaren Arbeitsspeichers
fr.ro.HelpMemoryConfig:\Tla fenêtre de configuration de mémoire
it.ro.HelpMemoryConfig:\Tmemory configuration \w
nl.ro.HelpMemoryConfig:\Tmemory configuration \w
en.ro.HelpMemoryConfig3:You can enter the maximum amount of memory NetSurf will use for storing uncompressed images here.
de.ro.HelpMemoryConfig3:Hier kann die Maximalgröße des von NetSurf für nichtkomprimierte Bilder genutzten Speichers angegeben werden.
fr.ro.HelpMemoryConfig3:Vous pouvez entrer ici la quantité maximum de mémoire que Netsurf utilisera pour stocker les images non-compressées.
it.ro.HelpMemoryConfig3:You can enter the maximum amount of memory NetSurf will use for storing uncompressed images here.
nl.ro.HelpMemoryConfig3:You can enter the maximum amount of memory NetSurf will use for storing uncompressed images here.
en.ro.HelpMemoryConfig4:\Sreduce the amount of memory used for storing uncompressed images.
de.ro.HelpMemoryConfig4:Klicken mit AUSWAHL verkleinert den Arbeitsspeicher zum Ablegen nichtkomprimierter Bilder.
fr.ro.HelpMemoryConfig4:\Sréduire la quantité de mémoire utilisée pour stocker les images non-compressées.
it.ro.HelpMemoryConfig4:\Sreduce the amount of memory used for storing uncompressed images.
nl.ro.HelpMemoryConfig4:\Sreduce the amount of memory used for storing uncompressed images.
en.ro.HelpMemoryConfig5:\Sincrease the amount of memory used for storing uncompressed images.
de.ro.HelpMemoryConfig5:Klicken mit AUSWAHL vergrößert den Arbeitsspeicher zum Ablegen nichtkomprimierter Bilder.
fr.ro.HelpMemoryConfig5:\Saugmenter la quantité de mémoire utilisée pour stocker les images non-compressées.
it.ro.HelpMemoryConfig5:\Sincrease the amount of memory used for storing uncompressed images.
nl.ro.HelpMemoryConfig5:\Sincrease the amount of memory used for storing uncompressed images.
en.ro.HelpMemoryConfig7:This indicates whether NetSurf will try to make an intelligent guess at the most suitable amount of memory to use for storing uncompressed images.
de.ro.HelpMemoryConfig7:NetSurf nimmt eine automatische intelligente Abschätzung der notwendigen Größe des Arbeitsspeichers zum Ablegen nichtkomprimierter Bilddaten vor.
fr.ro.HelpMemoryConfig7:Ceci indiquera si Netsurf doit essayer de deviner intelligemment la quantité de mémoire la plus appropriée à utiliser pour le stockage d'images non-compressées.
it.ro.HelpMemoryConfig7:This indicates whether NetSurf will try to make an intelligent guess at the most suitable amount of memory to use for storing uncompressed images.
nl.ro.HelpMemoryConfig7:This indicates whether NetSurf will try to make an intelligent guess at the most suitable amount of memory to use for storing uncompressed images.
en.ro.HelpMemoryConfig9:You can enter the maximum amount of memory NetSurf will use for storing compressed images here.
de.ro.HelpMemoryConfig9:Hier kann die Maximalgröße des von NetSurf für komprimierte Bilder genutzten Speichers angegeben werden.
fr.ro.HelpMemoryConfig9:Vous pouvez entrer ici la quantité de mémoire maximum que Netsurf utilisera pour le stockage d'images compressées.
it.ro.HelpMemoryConfig9:You can enter the maximum amount of memory NetSurf will use for storing compressed images here.
nl.ro.HelpMemoryConfig9:You can enter the maximum amount of memory NetSurf will use for storing compressed images here.
en.ro.HelpMemoryConfig10:\Sreduce the amount of memory used for storing compressed images.
de.ro.HelpMemoryConfig10:Klicken mit AUSWAHL verkleinert den Arbeitsspeicher zum Ablegen komprimierter Bilder.
fr.ro.HelpMemoryConfig10:\Sréduire la quantité de mémoire utilisée pour le stockage d'images compressées.
it.ro.HelpMemoryConfig10:\Sreduce the amount of memory used for storing compressed images.
nl.ro.HelpMemoryConfig10:\Sreduce the amount of memory used for storing compressed images.
en.ro.HelpMemoryConfig11:\Sincrease the amount of memory used for storing compressed images.
de.ro.HelpMemoryConfig11:Klicken mit AUSWAHL vergrößert den Arbeitsspeicher zum Ablegen komprimierter Bilder.
fr.ro.HelpMemoryConfig11:\Saugmenter la quantité de mémoire utilisée pour le stockage d'images compressées.
it.ro.HelpMemoryConfig11:\Sincrease the amount of memory used for storing compressed images.
nl.ro.HelpMemoryConfig11:\Sincrease the amount of memory used for storing compressed images.
en.ro.HelpMemoryConfig13:This indicates whether NetSurf will try to make an intelligent guess at the most suitable amount of memory to use for storing uncompressed images.
de.ro.HelpMemoryConfig13:NetSurf nimmt eine automatische intelligente Abschätzung der notwendigen Größe des Arbeitsspeichers zum Ablegen komprimierter Bilddaten vor.
fr.ro.HelpMemoryConfig13:Ceci indiquera si Netsurf doit essayer de deviner intelligemment la quantité de mémoire la plus appropriée à utiliser pour le stockage d'images compressées.
it.ro.HelpMemoryConfig13:This indicates whether NetSurf will try to make an intelligent guess at the most suitable amount of memory to use for storing uncompressed images.
nl.ro.HelpMemoryConfig13:This indicates whether NetSurf will try to make an intelligent guess at the most suitable amount of memory to use for storing uncompressed images.
en.ro.HelpMemoryConfig14:\Sreset the Memory options back to their default values.
de.ro.HelpMemoryConfig14:Stellt die Standardeinstellungen wieder her.
fr.ro.HelpMemoryConfig14:\Srevenir aux valeurs par défaut des options de Mémoire.
it.ro.HelpMemoryConfig14:\Sreset the Memory options back to their default values.
nl.ro.HelpMemoryConfig14:\Sreset the Memory options back to their default values.
en.ro.HelpMemoryConfig15:\Sclose this \w without saving changes.|M\Areturn the memory options to the last saved configuration.
de.ro.HelpMemoryConfig15:Klicken mit AUSWAHL schließt das Fenster ohne die Änderungen zu speichern.|MKlicken mit SPEZIAL stellt die zuletzt abgespeicherten Einstellungen wieder her.
fr.ro.HelpMemoryConfig15:\Sfermer cette fenêtre sans sauver les changements|M\Arevenir aux options de Mémoire précédemment sauvegardées.
it.ro.HelpMemoryConfig15:\Sclose this \w without saving changes.|M\Areturn the memory options to the last saved configuration.
nl.ro.HelpMemoryConfig15:\Sclose this \w without saving changes.|M\Areturn the cache options to the last saved configuration.
en.ro.HelpMemoryConfig16:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
de.ro.HelpMemoryConfig16:Klicken mit AUSWAHL speichert die Einstellungen und schließt das Fenster.|MKlicken mit SPEZIAL speichert die Einstellungen ohne das Fenster zu schließen.
fr.ro.HelpMemoryConfig16:\Ssauver ces réglages et fermer la fenêtre.|M\Asauver ces réglages sans fermer la fenêtre.
it.ro.HelpMemoryConfig16:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
nl.ro.HelpMemoryConfig16:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
 
en.ro.HelpSecurityConfig:\Tsecurity configuration \w
de.ro.HelpSecurityConfig:Fenster zur Konfiguration der Sicherheitseinstellungen
fr.ro.HelpSecurityConfig:\Tla fenêtre de configuration de sécurité
it.ro.HelpSecurityConfig:\Tsecurity configuration \w
nl.ro.HelpSecurityConfig:\Tsecurity configuration \w
en.ro.HelpSecurityConfig2:This indicates whether NetSurf will send site referral information to web servers.|MWhen this is enabled NetSurf will tell the web server of a new page the address of the site you came from, after following a link.
de.ro.HelpSecurityConfig2:NetSurf sendet Seitenreferenzinformationen an Webserver.|MIst diese Option gewählt, schickt NetSurf an den Server einer neuen Webseite die Adresse der Seite von der aus die aktuelle über einen Link aufgerufen wurde.
fr.ro.HelpSecurityConfig2:Ceci indique si Netsurf doit envoyer l'information de renvoi de site aux serveurs web.|MLorsque ceci est activé Netsurf signalera au serveur web d'une nouvelle page l'adresse du site d'où vous venez, après avoir suivi un lien.
it.ro.HelpSecurityConfig2:This indicates whether NetSurf will send site referral information to web servers.|MWhen this is enabled NetSurf will tell the web server of a new page the address of the site you came from, after following a link.
nl.ro.HelpSecurityConfig2:This indicates whether NetSurf will send site referral information to web servers.|MWhen this is enabled NetSurf will tell the web server of a new page the address of the site you came from, after following a link.
en.ro.HelpSecurityConfig6:You can enter the length of time that items are stored in global history here.
de.ro.HelpSecurityConfig6:Hier kann die Zeitdauer in Tagen angegeben werden, bis zu deren Ablauf Objekte in der globalen History gespeichert bleiben.
fr.ro.HelpSecurityConfig6:Vous pouvez entrer ici la durée de stockage des items dans l'historique global.
it.ro.HelpSecurityConfig6:You can enter the length of time that items are stored in global history here.
nl.ro.HelpSecurityConfig6:You can enter the length of time that items are stored in global history here.
en.ro.HelpSecurityConfig7:\Sreduce the global history duration.
de.ro.HelpSecurityConfig7:Klicken mit AUSWAHL verkürzt die Aufbewahrungszeit von Seiten in der globalen History.
fr.ro.HelpSecurityConfig7:\Sréduire la durée de l'historique global.
it.ro.HelpSecurityConfig7:\Sreduce the global history duration.
nl.ro.HelpSecurityConfig7:\Sreduce the global history duration.
en.ro.HelpSecurityConfig8:\Sincrease the global history duration.
de.ro.HelpSecurityConfig8:Klicken mit AUSWAHL verlängert die Aufbewahrungszeit von Seiten in der globalen History.
fr.ro.HelpSecurityConfig8:\Saugmenter la durée de l'historique global.
it.ro.HelpSecurityConfig8:\Sincrease the global history duration.
nl.ro.HelpSecurityConfig8:\Sincrease the global history duration.
en.ro.HelpSecurityConfig10:\Sreset the Security options back to their default values.
de.ro.HelpSecurityConfig10:Stellt die Standardeinstellungen wieder her.
fr.ro.HelpSecurityConfig10:\Srevenir aux valeurs par défaut des options de Sécurité.
it.ro.HelpSecurityConfig10:\Sreset the Security options back to their default values.
nl.ro.HelpSecurityConfig10:\Sreset the Security options back to their default values.
en.ro.HelpSecurityConfig11:\Sclose this \w without saving changes.|M\Areturn the security options to the last saved configuration.
de.ro.HelpSecurityConfig11:Klicken mit AUSWAHL schließt das Fenster ohne die Änderungen zu speichern.|MKlicken mit SPEZIAL stellt die zuletzt abgespeicherten Einstellungen wieder her.
fr.ro.HelpSecurityConfig11:\Sfermer cette fenêtre sans sauver les changements|M\Arevenir aux options de Sécurité précédemment sauvegardées.
it.ro.HelpSecurityConfig11:\Sclose this \w without saving changes.|M\Areturn the security options to the last saved configuration.
nl.ro.HelpSecurityConfig11:\Sclose this \w without saving changes.|M\Areturn the cache options to the last saved configuration.
en.ro.HelpSecurityConfig12:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
de.ro.HelpSecurityConfig12:Klicken mit AUSWAHL speichert die Einstellungen und schließt das Fenster.|MKlicken mit SPEZIAL speichert die Einstellungen ohne das Fenster zu schließen.
fr.ro.HelpSecurityConfig12:\Ssauver ces réglages et fermer la fenêtre.|M\Asauver ces réglages sans fermer la fenêtre.
it.ro.HelpSecurityConfig12:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
nl.ro.HelpSecurityConfig12:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
 
en.ro.HelpThemeConfig:\Ttheme configuration \w
de.ro.HelpThemeConfig:Fenster zur Auswahl des Anzeigethemas
fr.ro.HelpThemeConfig:\Tla fenêtre de configuration de thème
it.ro.HelpThemeConfig:\Ttheme configuration \w
nl.ro.HelpThemeConfig:\Ttheme configuration \w
en.ro.HelpThemeConfig2:\Sreset the Theme options back to their default values.
de.ro.HelpThemeConfig2:Stellt die Standardeinstellungen wieder her.
fr.ro.HelpThemeConfig2:\Srevenir aux valeurs par défaut des options de Thème.
it.ro.HelpThemeConfig2:\Sreset the Theme options back to their default values.
nl.ro.HelpThemeConfig2:\Sreset the Theme options back to their default values.
en.ro.HelpThemeConfig3:\Sclose this \w without saving changes.|M\Areturn the theme options to the last saved configuration.
de.ro.HelpThemeConfig3:Klicken mit AUSWAHL schließt das Fenster ohne die Änderungen zu speichern.|MKlicken mit SPEZIAL stellt die zuletzt abgespeicherten Einstellungen wieder her.
fr.ro.HelpThemeConfig3:\Sfermer cette fenêtre sans sauver les changements|M\Arevenir aux options de Thème précédemment sauvegardées.
it.ro.HelpThemeConfig3:\Sclose this \w without saving changes.|M\Areturn the theme options to the last saved configuration.
nl.ro.HelpThemeConfig3:\Sclose this \w without saving changes.|M\Areturn the cache options to the last saved configuration.
en.ro.HelpThemeConfig4:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
de.ro.HelpThemeConfig4:Klicken mit AUSWAHL speichert die Einstellungen und schließt das Fenster.|MKlicken mit SPEZIAL speichert die Einstellungen ohne das Fenster zu schließen.
fr.ro.HelpThemeConfig4:\Ssauver ces réglages et fermer la fenêtre.|M\Asauver ces réglages sans fermer la fenêtre.
it.ro.HelpThemeConfig4:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
nl.ro.HelpThemeConfig4:\Ssave these settings and close the \w.|M\Asave these settings without closing the \w.
 
en.ro.HelpThemePConfig:This pane shows the available themes.|MThe selected icon theme is used for NetSurf browser \ws, the hotlist, global history and cookie management.
de.ro.HelpThemePConfig:Dieser Dialog zeigt die verfügbaren Themen.|MDas ausgewählte Thema wird bei der Anzeige von Browserfenster, Cookieverwaltung, Hotlist und History eingesetzt.
fr.ro.HelpThemePConfig:Cette fenêtre indique les thèmes disponibles.|MLe thème de l'icône sélectionnée est utilisée pour les fenêtres de navigation de Netsurf, la liste des favoris et l'historique global.
it.ro.HelpThemePConfig:This pane shows the available themes.|MThe selected icon theme is used for NetSurf browser \ws, the hotlist, global history and cookie management.
nl.ro.HelpThemePConfig:This pane shows the available themes.|MThe selected icon theme is used for NetSurf browser \ws, the hotlist and global history.
 
# Amiga HelpHint (tooltip) text
#
 
en.ami.HelpToolbarBack:Back\nLMB: Steps back one page\nRMB: Display a menu of recent pages
de.ami.HelpToolbarBack:Back\nLMB: Steps back one page\nRMB: Display a menu of recent pages
fr.ami.HelpToolbarBack:Back\nLMB: Steps back one page\nRMB: Display a menu of recent pages
it.ami.HelpToolbarBack:Indietro
nl.ami.HelpToolbarBack:Back\nLMB: Steps back one page\nRMB: Display a menu of recent pages
en.ami.HelpToolbarForward:Forward\nLMB: Steps forward one page
de.ami.HelpToolbarForward:Forward\nLMB: Steps forward one page
fr.ami.HelpToolbarForward:Forward\nLMB: Steps forward one page
it.ami.HelpToolbarForward:Avanti
nl.ami.HelpToolbarForward:Forward\nLMB: Steps forward one page
en.ami.HelpToolbarStop:Stop\nLMB: Stops loading the page
de.ami.HelpToolbarStop:Stop\nLMB: Stops loading the page
fr.ami.HelpToolbarStop:Stop\nLMB: Stops loading the page
it.ami.HelpToolbarStop:Stop
nl.ami.HelpToolbarStop:Stop\nLMB: Stops loading the page
en.ami.HelpToolbarReload:Reload\nLMB: Reloads the page\nShift+LMB: Reloads the page and all objects
de.ami.HelpToolbarReload:Reload\nLMB: Reloads the page\nShift+LMB: Reloads the page and all objects
fr.ami.HelpToolbarReload:Reload\nLMB: Reloads the page\nShift+LMB: Reloads the page and all objects
it.ami.HelpToolbarReload:Ricarica
nl.ami.HelpToolbarReload:Reload\nLMB: Reloads the page\nShift+LMB: Reloads the page and all objects
en.ami.HelpToolbarHome:Home\nLMB: Goes to the homepage
de.ami.HelpToolbarHome:Home\nLMB: Goes to the homepage
fr.ami.HelpToolbarHome:Home\nLMB: Goes to the homepage
it.ami.HelpToolbarHome:Pagina iniziale
nl.ami.HelpToolbarHome:Home\nLMB: Goes to the homepage
en.ami.HelpToolbarURL:URL bar\nType a URL and press Return\nSuggestions can be selected with up/down
de.ami.HelpToolbarURL:URL bar\nType a URL and press Return\nSuggestions can be selected with up/down
fr.ami.HelpToolbarURL:URL bar\nType a URL and press Return\nSuggestions can be selected with up/down
it.ami.HelpToolbarURL:Barra indirizzi
nl.ami.HelpToolbarURL:URL bar\nType a URL and press Return\nSuggestions can be selected with up/down
en.ami.HelpToolbarWebSearch:Web search bar\nType text and press Return to search using your default search provider
de.ami.HelpToolbarWebSearch:Websuchleiste\nText eingeben und Enter drücken um mit der Standardsuchmaschine zu suchen
fr.ami.HelpToolbarWebSearch:Web search bar\nType text and press Return to search using your default search provider
it.ami.HelpToolbarWebSearch:Digita una voce in base al provider scelto e premi invio
nl.ami.HelpToolbarWebSearch:Web search bar\nType text and press Return to search using your default search provider
en.ami.HelpToolbarAddTab:Add tab\nLMB: Adds a new blank tab
de.ami.HelpToolbarAddTab:Tab hinzufügen.
fr.ami.HelpToolbarAddTab:Add tab\nLMB: Adds a new blank tab
it.ami.HelpToolbarAddTab:Apri una nuova scheda
nl.ami.HelpToolbarAddTab:Add tab\nLMB: Adds a new blank tab
 
 
# Configuration tokens
# ====================
#
# These tokens are used for the configuration icon text.
#
 
en.all.con_cache:Cache
de.all.con_cache:Cache
fr.all.con_cache:Cache
it.all.con_cache:Cache
nl.all.con_cache:Voorraad
en.all.con_connect:Connection
de.all.con_connect:Verbindung
fr.all.con_connect:Connexion
it.all.con_connect:Connessione
nl.all.con_connect:Connectie
en.all.con_content:Content
de.all.con_content:Inhalte
fr.all.con_content:Contenu
it.all.con_content:Contenuto
nl.all.con_content:Inhoud
en.all.con_fonts:Fonts
de.all.con_fonts:Schriftarten
fr.all.con_fonts:Fontes
it.all.con_fonts:Font
nl.all.con_fonts:Lettertypen
en.all.con_home:Home page
de.all.con_home:Homepage
fr.all.con_home:Page d'accueil
it.all.con_home:Home Page
nl.all.con_home:Thuispagina
en.all.con_image:Images
de.all.con_image:Bilder
fr.all.con_image:Images
it.all.con_image:Immagini
nl.all.con_image:Beelden
en.all.con_inter:Interface
de.all.con_inter:Nützliches
fr.all.con_inter:Interface
it.all.con_inter:Interfaccia
nl.all.con_inter:Interface
en.all.con_lang:Language
de.all.con_lang:Sprachen
fr.all.con_lang:Langue
it.all.con_lang:Lingua
nl.all.con_lang:Taal
en.all.con_memory:Memory
de.all.con_memory:Speicher
fr.all.con_memory:Mémoire
it.all.con_memory:Memoria
nl.all.con_memory:Geheugen
en.all.con_secure:Security
de.all.con_secure:Sicherheit
fr.all.con_secure:Sécurité
it.all.con_secure:Sicurezza
nl.all.con_secure:Veiligheid
en.all.con_theme:Themes
de.all.con_theme:Themen
fr.all.con_theme:Thèmes
it.all.con_theme:Temi
nl.all.con_theme:Thema's
en.all.con_general:General
de.all.con_general:Allgemeines
fr.all.con_general:General
it.all.con_general:Generale
nl.all.con_general:General
en.all.con_rendering:Rendering
de.all.con_rendering:Rendern
fr.all.con_rendering:Rendu
it.all.con_rendering:Rendering
nl.all.con_rendering:Rendering
en.all.con_advanced:Advanced
de.all.con_advanced:Erweitertes
fr.all.con_advanced:Avancé
it.all.con_advanced:Avanzate
nl.all.con_advanced:Advanced
 
# General tab
#
 
en.all.Preferences:Preferences
de.all.Preferences:Einstellungen
fr.all.Preferences:Preferences
it.all.Preferences:Preferenze di NetSurf
nl.all.Preferences:Preferences
en.all.Use:Use
de.all.Use:Benutzen
fr.all.Use:Use
it.all.Use:Usa
nl.all.Use:Use
 
en.all.HomePageURL:URL
de.all.HomePageURL:URL
fr.all.HomePageURL:URL
it.all.HomePageURL:URL
nl.all.HomePageURL:URL
en.all.HomePageDefault:Use default page
de.all.HomePageDefault:Standardseite
fr.all.HomePageDefault:Use default page
it.all.HomePageDefault:Usa pagina predefinita
nl.all.HomePageDefault:Use default page
en.all.HomePageCurrent:Use current page
de.all.HomePageCurrent:Aktuelle Seite
fr.all.HomePageCurrent:Use current page
it.all.HomePageCurrent:Usa pagina corrente
nl.all.HomePageCurrent:Use current page
en.all.HomePageBlank:Use blank page
de.all.HomePageBlank:Use blank page
fr.all.HomePageBlank:Use blank page
it.all.HomePageBlank:Usa pagina vuota
nl.all.HomePageBlank:Use blank page
en.all.ContentBlocking:Content blocking
de.all.ContentBlocking:Inhalte blockieren
fr.all.ContentBlocking:blocage de contenu
it.all.ContentBlocking:Blocca contenuti (AdBlock)
nl.all.ContentBlocking:Content blocking
en.all.BlockAds:Hide advertisements
de.all.BlockAds:Werbung unterdrücken
fr.all.BlockAds:Hide advertisements
it.all.BlockAds:Nascondi messaggi/banner
nl.all.BlockAds:Hide advertisements
en.all.ContentLanguage:Content language
de.all.ContentLanguage:Sprache
fr.all.ContentLanguage:Content language
it.all.ContentLanguage:Lingua contenuti
nl.all.ContentLanguage:Content language
en.ami.LocaleLang:Get from Locale prefs
de.ami.LocaleLang:Rechnervorgabe nutzen
fr.ami.LocaleLang:Get from Locale prefs
it.ami.LocaleLang:Ottieni da preferenze localizzazione
nl.ami.LocaleLang:Get from Locale prefs
en.all.HistoryAge:Keep history for
de.all.HistoryAge:History behalten für
fr.all.HistoryAge:Keep history for
it.all.HistoryAge:Conserva cronologia per
nl.all.HistoryAge:Keep history for
en.all.Days:days
de.all.Days:Tage
fr.all.Days:days
it.all.Days:giorni
nl.all.Days:days
en.all.Scripting:Scripting
de.all.Scripting:Scripting
fr.all.Scripting:Scripting
it.all.Scripting:Scripting
nl.all.Scripting:Scripting
en.all.EnableJS:Enable JavaScript
de.all.EnableJS:Enable JavaScript
fr.all.EnableJS:Enable JavaScript
it.all.EnableJS:Attiva JavaScript
nl.all.EnableJS:Enable JavaScript
en.all.Miscellaneous:Miscellaneous
de.all.Miscellaneous:Verschiedenes
fr.all.Miscellaneous:Miscellaneous
it.all.Miscellaneous:Impostazioni varie
nl.all.Miscellaneous:Miscellaneous
en.ami.Privacy:Privacy
de.ami.Privacy:Privacy
fr.ami.Privacy:Privacy
it.ami.Privacy:Privacy
nl.ami.Privacy:Privacy
en.all.SendReferer:Send site referral information
de.all.SendReferer:Seitenreferenzen senden
fr.all.SendReferer:Send site referral information
it.all.SendReferer:Invia informazioni sul referral del sito
nl.all.SendReferer:Send site referral information
en.ami.DoNotTrack:Send header to tell websites not to track
de.ami.DoNotTrack:Send header to tell websites not to track
fr.ami.DoNotTrack:Send header to tell websites not to track
it.ami.DoNotTrack:Invia header al sito per la richiesta di non tracciamento
nl.ami.DoNotTrack:Send header to tell websites not to track
en.all.FastScrolling:Fast scrolling
de.all.FastScrolling:Schnelles Scrollen
fr.all.FastScrolling:Fast scrolling
it.all.FastScrolling:Scrolling veloce
nl.all.FastScrolling:Fast scrolling
 
# Display tab
#
 
en.all.Screen:Screen
de.all.Screen:Ausgabe
fr.all.Screen:Screen
it.all.Screen:Gestione schermi
nl.all.Screen:Screen
en.all.ScreenOwn:Own screen
de.all.ScreenOwn:Eigener Screen
fr.all.ScreenOwn:Own screen
it.all.ScreenOwn:Schermo proprietario
nl.all.ScreenOwn:Own screen
en.ami.ScreenWB:Workbench
de.ami.ScreenWB:Workbench
fr.ami.ScreenWB:Workbench
it.ami.ScreenWB:Schermo Workbench
nl.ami.ScreenWB:Workbench
en.ami.ScreenPublic:Public screen
de.ami.ScreenPublic:Public Screen
fr.ami.ScreenPublic:Public screen
it.ami.ScreenPublic:Schermo pubblico
nl.ami.ScreenPublic:Public screen
en.ami.SimpleRefresh:Simple refresh
de.ami.SimpleRefresh:Simple refresh
fr.ami.SimpleRefresh:Simple refresh
it.ami.SimpleRefresh:Refresh semplice
nl.ami.SimpleRefresh:Simple refresh
en.all.Theme:Theme
de.all.Theme:Thema
fr.all.Theme:Theme
it.all.Theme:Tema grafico
nl.all.Theme:Theme
en.all.MousePointers:Mouse pointers
de.all.MousePointers:Mauszeiger
fr.all.MousePointers:Mouse pointers
it.all.MousePointers:Puntatori del mouse
nl.all.MousePointers:Mouse pointers
en.all.TrueColour:True colour
de.all.TrueColour:TrueColour
fr.all.TrueColour:True colour
it.all.TrueColour:True color
nl.all.TrueColour:True colour
en.all.OSPointers:Use OS mouse pointers when possible
de.all.OSPointers:Mauszeiger vom OS nutzen, wenn möglich
fr.all.OSPointers:Use OS mouse pointers when possible
it.all.OSPointers:Se possibile usa i puntatori del mouse di sistema
nl.all.OSPointers:Use OS mouse pointers when possible
en.all.NeedRestart:These options will not take effect until the next time NetSurf is started
de.all.NeedRestart:Diese Optionen werden erst nach einem Neustart von NetSurf aktiviert.
fr.all.NeedRestart:These options will not take effect until the next time NetSurf is started
it.all.NeedRestart:Queste modifiche avranno effetto al prossimo riavvio di NetSurf
nl.all.NeedRestart:These options will not take effect until the next time NetSurf is started
 
# Connection tab
#
 
en.all.Proxy:HTTP proxy
de.all.Proxy:HTTP Proxy
fr.all.Proxy:HTTP Proxy
it.all.Proxy:Proxy HTTP
nl.all.Proxy:HTTP Proxy
en.all.Fetching:Fetching
de.all.Fetching:Fetching
fr.all.Fetching:Fetching
it.all.Fetching:Ricezione
nl.all.Fetching:Fetching
en.all.FetchesMax:Maximum fetches
de.all.FetchesMax:Maximale Anzahl an Ladevorgängen
fr.all.FetchesMax:Maximum fetches
it.all.FetchesMax:Massima
nl.all.FetchesMax:Maximum fetches
en.all.FetchesHost:Fetches per host
de.all.FetchesHost:Ladevorgänge pro Host
fr.all.FetchesHost:Fetches per host
it.all.FetchesHost:Per host
nl.all.FetchesHost:Fetches per host
en.all.FetchesCached:Cached connections
de.all.FetchesCached:Gehaltene Verbindungen
fr.all.FetchesCached:Cached connections
it.all.FetchesCached:Su cache
nl.all.FetchesCached:Cached connections
 
# Rendering tab
#
 
en.all.CacheNative:Cache native versions
de.all.CacheNative:Originale zwischenspeichern
fr.all.CacheNative:Cache native versions
it.all.CacheNative:Versioni cache native
nl.all.CacheNative:Cache native versions
en.all.ScaleQuality:Higher quality scaling
de.all.ScaleQuality:Skalieren hoher Qualität
fr.all.ScaleQuality:Higher quality scaling
it.all.ScaleQuality:Massima qualità di visualizzazione
nl.all.ScaleQuality:Higher quality scaling
en.ami.DitherQuality:Dither quality (<= 8-bit modes only)
de.ami.DitherQuality:Dither quality (<= 8-bit modes only)
fr.ami.DitherQuality:Dither quality (<= 8-bit modes only)
it.ami.DitherQuality:Qualità dither (<= solo modi a 8-bit)
nl.ami.DitherQuality:Dither quality (<= 8-bit modes only)
en.ami.Low:Low
de.ami.Low:Low
fr.ami.Low:Low
it.ami.Low:Bassa
nl.ami.Low:Low
en.ami.Medium:Medium
de.ami.Medium:Medium
fr.ami.Medium:Medium
it.ami.Medium:Media
nl.ami.Medium:Medium
en.ami.High:High
de.ami.High:High
fr.ami.High:High
it.ami.High:Alta
nl.ami.High:High
en.all.Animations:Animations
de.all.Animations:Animationen
fr.all.Animations:Animations
it.all.Animations:Animazioni
nl.all.Animations:Animations
en.all.AnimSpeedLimit:Limit speed to
de.all.AnimSpeedLimit:Geschwindigkeit begrenzen
fr.all.AnimSpeedLimit:Limit speed to
it.all.AnimSpeedLimit:Limita velocità a
nl.all.AnimSpeedLimit:Limit speed to
en.all.AnimSpeedFrames:seconds between frames
de.all.AnimSpeedFrames:Bildintervall (Sekunden)
fr.all.AnimSpeedFrames:seconds between frames
it.all.AnimSpeedFrames:fotogrammi al secondo
nl.all.AnimSpeedFrames:seconds between frames
en.all.AnimDisable:Disable animations
de.all.AnimDisable:Animationen abschalten
fr.all.AnimDisable:Disable animations
it.all.AnimDisable:Disattiva animazioni
nl.all.AnimDisable:Disable animations
 
en.all.None:None
de.all.None:Keine
fr.all.None:None
it.all.None:Nessuna
nl.all.None:None
en.all.Scaled:Scaled
de.all.Scaled:Skaliert
fr.all.Scaled:Scaled
it.all.Scaled:Scalate
nl.all.Scaled:Scaled
 
en.all.Resolution:Resolution
de.all.Resolution:Auflösung
fr.all.Resolution:Resolution
it.all.Resolution:Risoluzione
nl.all.Resolution:Resolution
en.all.ResolutionY:Vertical resolution
de.all.ResolutionY:Vertikale Auflösung
fr.all.ResolutionY:Vertical resolution
it.all.ResolutionY:Verticale
nl.all.ResolutionY:Vertical resolution
en.all.ResolutionX:Horizontal resolution
de.all.ResolutionX:Horizontale Auflösung
fr.all.ResolutionX:Horizontal resolution
it.all.ResolutionX:Orizzontale
nl.all.ResolutionX:Horizontal resolution
en.all.DPI:DPI
de.all.DPI:DPI
fr.all.DPI:DPI
it.all.DPI:DPI
nl.all.DPI:DPI
 
# Fonts tab
#
 
en.all.FontFamilies:Font families
de.all.FontFamilies:Schriftfamilien
fr.all.FontFamilies:Font families
it.all.FontFamilies:Famiglia Font
nl.all.FontFamilies:Font families
en.all.FontSans:Sans-serif
de.all.FontSans:Sans-serif
fr.all.FontSans:Sans-serif
it.all.FontSans:Sans-serif
nl.all.FontSans:Sans-serif
en.all.FontSerif:Serif
de.all.FontSerif:Serif
fr.all.FontSerif:Serif
it.all.FontSerif:Serif
nl.all.FontSerif:Serif
en.all.FontMono:Monospaced
de.all.FontMono:Monospace
fr.all.FontMono:Monospaced
it.all.FontMono:Monospaziato
nl.all.FontMono:Monospaced
en.all.FontCursive:Cursive
de.all.FontCursive:Kursiv
fr.all.FontCursive:Cursive
it.all.FontCursive:Corsivo
nl.all.FontCursive:Cursive
en.all.FontFantasy:Fantasy
de.all.FontFantasy:Fantasy
fr.all.FontFantasy:Fantasy
it.all.FontFantasy:Fantasia
nl.all.FontFantasy:Fantasy
en.ami.FontFallback:Preferred fallback
de.ami.FontFallback:Preferred fallback
fr.ami.FontFallback:Preferred fallback
it.ami.FontFallback:Fallback preferito
nl.ami.FontFallback:Preferred fallback
en.all.Default:Default
de.all.Default:Standard
fr.all.Default:Default
it.all.Default:Predefinito
nl.all.Default:Default
en.all.FontSize:Font size
de.all.FontSize:Schriftgröße
fr.all.FontSize:Font size
it.all.FontSize:Dimensione Font
nl.all.FontSize:Font size
en.all.Minimum:Minimum
de.all.Minimum:Minimum
fr.all.Minimum:Minimum
it.all.Minimum:Minimo
nl.all.Minimum:Minimum
en.all.Pt:pt
de.all.Pt:pt
fr.all.Pt:pt
it.all.Pt:pt
nl.all.Pt:pt
en.ami.FontAntialiasing:Use anti-aliasing (when possible)
de.ami.FontAntialiasing:Use anti-aliasing (when possible)
fr.ami.FontAntialiasing:Use anti-aliasing (when possible)
it.ami.FontAntialiasing:Usa anti-aliasing (quando possibile)
nl.ami.FontAntialiasing:Use anti-aliasing (when possible)
 
# Font scanning
en.ami.FontScanning:Scanning fonts...
de.ami.FontScanning:Scanning fonts...
fr.ami.FontScanning:Scanning fonts...
it.ami.FontScanning:Scansione dei font in corso...
nl.ami.FontScanning:Scanning fonts...
en.ami.FontGlyphs:%ld unique glyphs found
de.ami.FontGlyphs:%ld unique glyphs found
fr.ami.FontGlyphs:%ld unique glyphs found
it.ami.FontGlyphs:%ld glifi unici trovati
nl.ami.FontGlyphs:%ld unique glyphs found
 
# Cache tab
#
 
en.all.CacheMemory:Memory cache
de.all.CacheMemory:Arbeitsspeicher Cache
fr.all.CacheMemory:Memory cache
it.all.CacheMemory:Memoria cache
nl.all.CacheMemory:Memory cache
en.all.CacheDisc:Disc cache
de.all.CacheDisc:Festplatten Cache
fr.all.CacheDisc:Disc cache
it.all.CacheDisc:Cache su disco
nl.all.CacheDisc:Disc cache
en.all.Size:Size
de.all.Size:Größe
fr.all.Size:Size
it.all.Size:Dimensione
nl.all.Size:Size
en.all.Duration:Duration
de.all.Duration:Dauer
fr.all.Duration:Duration
it.all.Duration:Durata
nl.all.Duration:Duration
 
# Tabs
#
 
en.ami.Tabs:Tabs
de.ami.Tabs:Tabs
fr.ami.Tabs:Tabs
it.ami.Tabs:Schede
nl.ami.Tabs:Tabs
en.all.TabbedBrowsing:Tabbed browsing
de.all.TabbedBrowsing:Registernavigation (Tabs)
fr.all.TabbedBrowsing:Tabbed browsing
it.all.TabbedBrowsing:Navigazione a schede
nl.all.TabbedBrowsing:Tabbed browsing
en.all.TabActive:Open new tabs in background
de.all.TabActive:Neuen Tab im Hintergrund öffnen
fr.all.TabActive:Open new tabs in background
it.all.TabActive:Apri le nuove schede in sottofondo
nl.all.TabActive:Open new tabs in background
en.all.TabMiddle:Middle mouse button opens tabs
de.all.TabMiddle:Mittlere Maustaste öffnet Tab
fr.all.TabMiddle:Middle mouse button opens tabs
it.all.TabMiddle:Usa tasto centrale del mouse per aprire le schede
nl.all.TabMiddle:Middle mouse button opens tabs
en.all.TabLast:Open new tabs after all existing tabs
de.all.TabLast:Open new tabs after all existing tabs
fr.all.TabLast:Open new tabs after all existing tabs
it.all.TabLast:Apri le nuove schede dopo quella corrente
nl.all.TabLast:Open new tabs after all existing tabs
en.ami.TabClose:Warn when closing multiple tabs
de.ami.TabClose:Warn when closing multiple tabs
fr.ami.TabClose:Warn when closing multiple tabs
it.ami.TabClose:Avvisa quando si chiudono più schede
nl.ami.TabClose:Warn when closing multiple tabs
en.ami.TabAlways:Always show tabs
de.ami.TabAlways:Always show tabs
fr.ami.TabAlways:Always show tabs
it.ami.TabAlways:Mostra sempre la barra delle schede
nl.ami.TabAlways:Always show tabs
 
# Advanced
#
 
en.all.Downloads:Downloads
de.all.Downloads:Downloads
fr.all.Downloads:Downloads
it.all.Downloads:Trasferimenti
nl.all.Downloads:Downloads
en.all.ConfirmOverwrite:Request confirmation when overwriting
de.all.ConfirmOverwrite:vor Ãœberschreiben nachfragen
fr.all.ConfirmOverwrite:Request confirmation when overwriting
it.all.ConfirmOverwrite:Richiedi conferma prima di sovrascrivere
nl.all.ConfirmOverwrite:Request confirmation when overwriting
en.all.DownloadDir:Initial download location
de.all.DownloadDir:Downloadverzeichnis
fr.all.DownloadDir:Initial download location
it.all.DownloadDir:Percorso predefinito
nl.all.DownloadDir:Initial download location
en.all.DownloadNotify:Notify on completion
de.all.DownloadNotify:Downloadende melden
fr.all.DownloadNotify:Notify on completion
it.all.DownloadNotify:Notifica al completamento (Ringhio)
nl.all.DownloadNotify:Notify on completion
en.all.SearchWeb:Web search
de.all.SearchWeb:Websuche
fr.all.SearchWeb:Web search
it.all.SearchWeb:Ricerca nel Web
nl.all.SearchWeb:Web search
en.all.SearchURL:Search from URL bar
de.all.SearchURL:Suche über URL Leiste
fr.all.SearchURL:Search from URL bar
it.all.SearchURL:Ricerca da barra URL
nl.all.SearchURL:Search from URL bar
en.all.SearchProvider:Search provider
de.all.SearchProvider:Suchmaschine
fr.all.SearchProvider:Search provider
it.all.SearchProvider:Ricerca su provider
nl.all.SearchProvider:Search provider
en.ami.OptionDocky:Show in AmiDock
de.ami.OptionDocky:In AmiDock zeigen
fr.ami.OptionDocky:Show in AmiDock
it.ami.OptionDocky:Mostra icona su AmiDock
nl.ami.OptionDocky:Show in AmiDock
en.all.Clipboard:Clipboard
de.all.Clipboard:Clipboard
fr.all.Clipboard:Clipboard
it.all.Clipboard:Clipboard
nl.all.Clipboard:Clipboard
en.all.ClipboardUTF8:Write text as UTF-8
de.all.ClipboardUTF8:Text als UTF-8
fr.all.ClipboardUTF8:Write text as UTF-8
it.all.ClipboardUTF8:Scrivi testo come UTF-8
nl.all.ClipboardUTF8:Write text as UTF-8
en.all.ContextMenu:Context menu
de.all.ContextMenu:Kontextmenu
fr.all.ContextMenu:Context menu
it.all.ContextMenu:Menu contestuali
nl.all.ContextMenu:Context menu
en.all.Enable:Enable
de.all.Enable:Erlauben
fr.all.Enable:Enable
it.all.Enable:Attivi
nl.all.Enable:Enable
en.all.Sticky:Sticky
de.all.Sticky:Klebrig
fr.all.Sticky:Sticky
it.all.Sticky:Fissi
nl.all.Sticky:Sticky
en.all.Behaviour:Behaviour
de.all.Behaviour:Verhalten
fr.all.Behaviour:Behaviour
it.all.Behaviour:Comportamento generale
nl.all.Behaviour:Behaviour
en.all.OptionNoWindow:Do not open window on startup
de.all.OptionNoWindow:Kein Fenster beim Start öffnen
fr.all.OptionNoWindow:Do not open window on startup
it.all.OptionNoWindow:Non aprire la finestra all'avvio (avvio da AmiDock)
nl.all.OptionNoWindow:Do not open window on startup
en.all.OptionNoQuit:Do not quit when last window closed
de.all.OptionNoQuit:Nicht beenden beim Schließen des letzten Fensters
fr.all.OptionNoQuit:Do not quit when last window closed
it.all.OptionNoQuit:Iconifica su AmiDock alla chiusura di NetSurf
nl.all.OptionNoQuit:Do not quit when last window closed
 
# Export
#
 
en.all.Margins:Margins
de.all.Margins:Ränder
fr.all.Margins:Margins
it.all.Margins:Margini
nl.all.Margins:Margins
en.all.Top:Top
de.all.Top:Oben
fr.all.Top:Top
it.all.Top:Superiore
nl.all.Top:Top
en.all.Left:Left
de.all.Left:Links
fr.all.Left:Left
it.all.Left:Sinistro
nl.all.Left:Left
en.all.Right:Right
de.all.Right:Rechts
fr.all.Right:Right
it.all.Right:Destro
nl.all.Right:Right
en.all.Bottom:Bottom
de.all.Bottom:Unten
fr.all.Bottom:Bottom
it.all.Bottom:Inferiore
nl.all.Bottom:Bottom
en.all.MM:mm
de.all.MM:mm
fr.all.MM:mm
it.all.MM:mm
nl.all.MM:mm
en.all.Scaling:Scaling
de.all.Scaling:Skalierung
fr.all.Scaling:Scaling
it.all.Scaling:Scala
nl.all.Scaling:Scaling
en.all.Scale:Scale
de.all.Scale:Skalieren
fr.all.Scale:Scale
it.all.Scale:Scalati
nl.all.Scale:Scale
en.all.Appearance:Appearance
de.all.Appearance:Aussehen
fr.all.Appearance:Appearance
it.all.Appearance:Aspetto
nl.all.Appearance:Appearance
en.all.SuppressImages:Suppress images
de.all.SuppressImages:Bilder unterbinden
fr.all.SuppressImages:Suppress images
it.all.SuppressImages:Sopprimi immagini
nl.all.SuppressImages:Suppress images
en.all.RemoveBackground:Remove background
de.all.RemoveBackground:Hintergrund entfernen
fr.all.RemoveBackground:Remove background
it.all.RemoveBackground:Rimuovi sfondo
nl.all.RemoveBackground:Remove background
en.all.FitPage:Fit page
de.all.FitPage:Seite einpassen
fr.all.FitPage:Fit page
it.all.FitPage:Adatta pagina
nl.all.FitPage:Fit page
en.all.CompressPDF:Compress PDF
de.all.CompressPDF:PDF komprimieren
fr.all.CompressPDF:Compress PDF
it.all.CompressPDF:Comprimi PDF
nl.all.CompressPDF:Compress PDF
en.all.SetPassword:Set password
de.all.SetPassword:Passwort festlegen
fr.all.SetPassword:Set password
it.all.SetPassword:Imposta Password
nl.all.SetPassword:Set password
 
 
# Unused tokens
# =============
#
# These tokens appear to be unused at the current time.
#
 
en.all.TreeHistory:NetSurf history
de.all.TreeHistory:NetSurf Verlauf
fr.all.TreeHistory:Historique de NetSurf
it.all.TreeHistory:Cronologia NetSurf
nl.all.TreeHistory:NetSurf historie
en.all.SaveSelect:Save
de.all.SaveSelect:Sichern
fr.all.SaveSelect:Sauver
it.all.SaveSelect:Salva
nl.all.SaveSelect:Bewaar
en.all.ExportAs:Export as
de.all.ExportAs:Exportieren als
fr.all.ExportAs:Exporter sous
it.all.ExportAs:Esporta come...
nl.all.ExportAs:Exporteer als
en.all.AnimImg:Animations
de.all.AnimImg:Animationen
fr.all.AnimImg:Animations
it.all.AnimImg:Animazioni
nl.all.AnimImg:Animatie
en.all.DitherImg:Dither images
de.all.DitherImg:Bilder dithern
fr.all.DitherImg:Tramage
it.all.DitherImg:Immagini Dither
nl.all.DitherImg:Dither afbeelding
en.all.FilterImg:Smooth images
de.all.FilterImg:Bilder weichzeichnen
fr.all.FilterImg:Adoucir les images
it.all.FilterImg:Immagini Smooth
nl.all.FilterImg:Smooth afbeelding
en.all.RenderText:Blend text to background
de.all.RenderText:Text/Hintergrund Ãœbergang weich
fr.all.RenderText:Panachage du texte sur le fond
it.all.RenderText:Sfuma testo di sfondo
nl.all.RenderText:Tekst met achtergrond mengen
/programs/network/netsurf/netsurf/utils/base64.c
0,0 → 1,441
/* base64.c -- Encode binary data using printable characters.
Copyright (C) 1999, 2000, 2001, 2004, 2005, 2006 Free Software
Foundation, Inc.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
 
/* Written by Simon Josefsson. Partially adapted from GNU MailUtils
* (mailbox/filter_trans.c, as of 2004-11-28). Improved by review
* from Paul Eggert, Bruno Haible, and Stepan Kasal.
*
* See also RFC 3548 <http://www.ietf.org/rfc/rfc3548.txt>.
*
* Be careful with error checking. Here is how you would typically
* use these functions:
*
* bool ok = base64_decode_alloc (in, inlen, &out, &outlen);
* if (!ok)
* FAIL: input was not valid base64
* if (out == NULL)
* FAIL: memory allocation error
* OK: data in OUT/OUTLEN
*
* size_t outlen = base64_encode_alloc (in, inlen, &out);
* if (out == NULL && outlen == 0 && inlen != 0)
* FAIL: input too long
* if (out == NULL)
* FAIL: memory allocation error
* OK: data in OUT/OUTLEN.
*
*/
 
/*#include <config.h>*/
 
/* Get prototype. */
#include "utils/base64.h"
 
/* Get malloc. */
#include <stdlib.h>
 
/* Get UCHAR_MAX. */
#include <limits.h>
 
/* C89 compliant way to cast 'char' to 'unsigned char'. */
static inline unsigned char
to_uchar (char ch)
{
return ch;
}
 
/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as
possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero
terminate the output buffer. */
void
base64_encode (const char * in, size_t inlen,
char * out, size_t outlen)
{
static const char b64str[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
while (inlen && outlen)
{
*out++ = b64str[(to_uchar (in[0]) >> 2) & 0x3f];
if (!--outlen)
break;
*out++ = b64str[((to_uchar (in[0]) << 4)
+ (--inlen ? to_uchar (in[1]) >> 4 : 0))
& 0x3f];
if (!--outlen)
break;
*out++ =
(inlen
? b64str[((to_uchar (in[1]) << 2)
+ (--inlen ? to_uchar (in[2]) >> 6 : 0))
& 0x3f]
: '=');
if (!--outlen)
break;
*out++ = inlen ? b64str[to_uchar (in[2]) & 0x3f] : '=';
if (!--outlen)
break;
if (inlen)
inlen--;
if (inlen)
in += 3;
}
 
if (outlen)
*out = '\0';
}
 
/* Allocate a buffer and store zero terminated base64 encoded data
from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e.,
the length of the encoded data, excluding the terminating zero. On
return, the OUT variable will hold a pointer to newly allocated
memory that must be deallocated by the caller. If output string
length would overflow, 0 is returned and OUT is set to NULL. If
memory allocation failed, OUT is set to NULL, and the return value
indicates length of the requested memory block, i.e.,
BASE64_LENGTH(inlen) + 1. */
size_t
base64_encode_alloc (const char *in, size_t inlen, char **out)
{
size_t outlen = 1 + BASE64_LENGTH (inlen);
 
/* Check for overflow in outlen computation.
*
* If there is no overflow, outlen >= inlen.
*
* If the operation (inlen + 2) overflows then it yields at most +1, so
* outlen is 0.
*
* If the multiplication overflows, we lose at least half of the
* correct value, so the result is < ((inlen + 2) / 3) * 2, which is
* less than (inlen + 2) * 0.66667, which is less than inlen as soon as
* (inlen > 4).
*/
if (inlen > outlen)
{
*out = NULL;
return 0;
}
 
*out = malloc (outlen);
if (!*out)
return outlen;
 
base64_encode (in, inlen, *out, outlen);
 
return outlen - 1;
}
 
/* With this approach this file works independent of the charset used
(think EBCDIC). However, it does assume that the characters in the
Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255. POSIX
1003.1-2001 require that char and unsigned char are 8-bit
quantities, though, taking care of that problem. But this may be a
potential problem on non-POSIX C99 platforms.
 
IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_"
as the formal parameter rather than "x". */
#define B64(_) \
((_) == 'A' ? 0 \
: (_) == 'B' ? 1 \
: (_) == 'C' ? 2 \
: (_) == 'D' ? 3 \
: (_) == 'E' ? 4 \
: (_) == 'F' ? 5 \
: (_) == 'G' ? 6 \
: (_) == 'H' ? 7 \
: (_) == 'I' ? 8 \
: (_) == 'J' ? 9 \
: (_) == 'K' ? 10 \
: (_) == 'L' ? 11 \
: (_) == 'M' ? 12 \
: (_) == 'N' ? 13 \
: (_) == 'O' ? 14 \
: (_) == 'P' ? 15 \
: (_) == 'Q' ? 16 \
: (_) == 'R' ? 17 \
: (_) == 'S' ? 18 \
: (_) == 'T' ? 19 \
: (_) == 'U' ? 20 \
: (_) == 'V' ? 21 \
: (_) == 'W' ? 22 \
: (_) == 'X' ? 23 \
: (_) == 'Y' ? 24 \
: (_) == 'Z' ? 25 \
: (_) == 'a' ? 26 \
: (_) == 'b' ? 27 \
: (_) == 'c' ? 28 \
: (_) == 'd' ? 29 \
: (_) == 'e' ? 30 \
: (_) == 'f' ? 31 \
: (_) == 'g' ? 32 \
: (_) == 'h' ? 33 \
: (_) == 'i' ? 34 \
: (_) == 'j' ? 35 \
: (_) == 'k' ? 36 \
: (_) == 'l' ? 37 \
: (_) == 'm' ? 38 \
: (_) == 'n' ? 39 \
: (_) == 'o' ? 40 \
: (_) == 'p' ? 41 \
: (_) == 'q' ? 42 \
: (_) == 'r' ? 43 \
: (_) == 's' ? 44 \
: (_) == 't' ? 45 \
: (_) == 'u' ? 46 \
: (_) == 'v' ? 47 \
: (_) == 'w' ? 48 \
: (_) == 'x' ? 49 \
: (_) == 'y' ? 50 \
: (_) == 'z' ? 51 \
: (_) == '0' ? 52 \
: (_) == '1' ? 53 \
: (_) == '2' ? 54 \
: (_) == '3' ? 55 \
: (_) == '4' ? 56 \
: (_) == '5' ? 57 \
: (_) == '6' ? 58 \
: (_) == '7' ? 59 \
: (_) == '8' ? 60 \
: (_) == '9' ? 61 \
: (_) == '+' ? 62 \
: (_) == '/' ? 63 \
: -1)
 
static const signed char b64[0x100] = {
B64 (0), B64 (1), B64 (2), B64 (3),
B64 (4), B64 (5), B64 (6), B64 (7),
B64 (8), B64 (9), B64 (10), B64 (11),
B64 (12), B64 (13), B64 (14), B64 (15),
B64 (16), B64 (17), B64 (18), B64 (19),
B64 (20), B64 (21), B64 (22), B64 (23),
B64 (24), B64 (25), B64 (26), B64 (27),
B64 (28), B64 (29), B64 (30), B64 (31),
B64 (32), B64 (33), B64 (34), B64 (35),
B64 (36), B64 (37), B64 (38), B64 (39),
B64 (40), B64 (41), B64 (42), B64 (43),
B64 (44), B64 (45), B64 (46), B64 (47),
B64 (48), B64 (49), B64 (50), B64 (51),
B64 (52), B64 (53), B64 (54), B64 (55),
B64 (56), B64 (57), B64 (58), B64 (59),
B64 (60), B64 (61), B64 (62), B64 (63),
B64 (64), B64 (65), B64 (66), B64 (67),
B64 (68), B64 (69), B64 (70), B64 (71),
B64 (72), B64 (73), B64 (74), B64 (75),
B64 (76), B64 (77), B64 (78), B64 (79),
B64 (80), B64 (81), B64 (82), B64 (83),
B64 (84), B64 (85), B64 (86), B64 (87),
B64 (88), B64 (89), B64 (90), B64 (91),
B64 (92), B64 (93), B64 (94), B64 (95),
B64 (96), B64 (97), B64 (98), B64 (99),
B64 (100), B64 (101), B64 (102), B64 (103),
B64 (104), B64 (105), B64 (106), B64 (107),
B64 (108), B64 (109), B64 (110), B64 (111),
B64 (112), B64 (113), B64 (114), B64 (115),
B64 (116), B64 (117), B64 (118), B64 (119),
B64 (120), B64 (121), B64 (122), B64 (123),
B64 (124), B64 (125), B64 (126), B64 (127),
B64 (128), B64 (129), B64 (130), B64 (131),
B64 (132), B64 (133), B64 (134), B64 (135),
B64 (136), B64 (137), B64 (138), B64 (139),
B64 (140), B64 (141), B64 (142), B64 (143),
B64 (144), B64 (145), B64 (146), B64 (147),
B64 (148), B64 (149), B64 (150), B64 (151),
B64 (152), B64 (153), B64 (154), B64 (155),
B64 (156), B64 (157), B64 (158), B64 (159),
B64 (160), B64 (161), B64 (162), B64 (163),
B64 (164), B64 (165), B64 (166), B64 (167),
B64 (168), B64 (169), B64 (170), B64 (171),
B64 (172), B64 (173), B64 (174), B64 (175),
B64 (176), B64 (177), B64 (178), B64 (179),
B64 (180), B64 (181), B64 (182), B64 (183),
B64 (184), B64 (185), B64 (186), B64 (187),
B64 (188), B64 (189), B64 (190), B64 (191),
B64 (192), B64 (193), B64 (194), B64 (195),
B64 (196), B64 (197), B64 (198), B64 (199),
B64 (200), B64 (201), B64 (202), B64 (203),
B64 (204), B64 (205), B64 (206), B64 (207),
B64 (208), B64 (209), B64 (210), B64 (211),
B64 (212), B64 (213), B64 (214), B64 (215),
B64 (216), B64 (217), B64 (218), B64 (219),
B64 (220), B64 (221), B64 (222), B64 (223),
B64 (224), B64 (225), B64 (226), B64 (227),
B64 (228), B64 (229), B64 (230), B64 (231),
B64 (232), B64 (233), B64 (234), B64 (235),
B64 (236), B64 (237), B64 (238), B64 (239),
B64 (240), B64 (241), B64 (242), B64 (243),
B64 (244), B64 (245), B64 (246), B64 (247),
B64 (248), B64 (249), B64 (250), B64 (251),
B64 (252), B64 (253), B64 (254), B64 (255)
};
 
#if UCHAR_MAX == 255
# define uchar_in_range(c) true
#else
# define uchar_in_range(c) ((c) <= 255)
#endif
 
/* Return true if CH is a character from the Base64 alphabet, and
false otherwise. Note that '=' is padding and not considered to be
part of the alphabet. */
bool
isbase64 (char ch)
{
return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)];
}
 
/* Decode base64 encoded input array IN of length INLEN to output
array OUT that can hold *OUTLEN bytes. Return true if decoding was
successful, i.e. if the input was valid base64 data, false
otherwise. If *OUTLEN is too small, as many bytes as possible will
be written to OUT. On return, *OUTLEN holds the length of decoded
bytes in OUT. Note that as soon as any non-alphabet characters are
encountered, decoding is stopped and false is returned. This means
that, when applicable, you must remove any line terminators that is
part of the data stream before calling this function. */
bool
base64_decode (const char * in, size_t inlen,
char * out, size_t *outlen)
{
size_t outleft = *outlen;
 
while (inlen >= 2)
{
if (!isbase64 (in[0]) || !isbase64 (in[1]))
break;
 
if (outleft)
{
*out++ = ((b64[to_uchar (in[0])] << 2)
| (b64[to_uchar (in[1])] >> 4));
outleft--;
}
 
if (inlen == 2)
break;
 
if (in[2] == '=')
{
if (inlen != 4)
break;
 
if (in[3] != '=')
break;
 
}
else
{
if (!isbase64 (in[2]))
break;
 
if (outleft)
{
*out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0)
| (b64[to_uchar (in[2])] >> 2));
outleft--;
}
 
if (inlen == 3)
break;
 
if (in[3] == '=')
{
if (inlen != 4)
break;
}
else
{
if (!isbase64 (in[3]))
break;
 
if (outleft)
{
*out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0)
| b64[to_uchar (in[3])]);
outleft--;
}
}
}
 
in += 4;
inlen -= 4;
}
 
*outlen -= outleft;
 
if (inlen != 0)
return false;
 
return true;
}
 
/* Allocate an output buffer in *OUT, and decode the base64 encoded
data stored in IN of size INLEN to the *OUT buffer. On return, the
size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL,
if the caller is not interested in the decoded length. *OUT may be
NULL to indicate an out of memory error, in which case *OUTLEN
contains the size of the memory block needed. The function returns
true on successful decoding and memory allocation errors. (Use the
*OUT and *OUTLEN parameters to differentiate between successful
decoding and memory error.) The function returns false if the
input was invalid, in which case *OUT is NULL and *OUTLEN is
undefined. */
bool
base64_decode_alloc (const char *in, size_t inlen, char **out,
size_t *outlen)
{
/* This may allocate a few bytes too much, depending on input,
but it's not worth the extra CPU time to compute the exact amount.
The exact amount is 3 * inlen / 4, minus 1 if the input ends
with "=" and minus another 1 if the input ends with "==".
Dividing before multiplying avoids the possibility of overflow. */
size_t needlen = 3 * (inlen / 4) + 2;
 
*out = malloc (needlen);
if (!*out)
return true;
 
if (!base64_decode (in, inlen, *out, &needlen))
{
free (*out);
*out = NULL;
return false;
}
 
if (outlen)
*outlen = needlen;
 
return true;
}
 
#ifdef TEST_RIG
#include <stdio.h>
int main(int argc, char *argv[])
{
char *out = malloc(strlen(argv[1]));
size_t outz;
fprintf(stderr, "base64_decode output: %d\n",
base64_decode(argv[1], strlen(argv[1]), out, &outz));
fprintf(stderr, "bytes decoded: %d\n", outz);
fwrite(out, outz, 1, stdout);
return 0;
}
#endif
/programs/network/netsurf/netsurf/utils/base64.h
0,0 → 1,45
/* base64.h -- Encode binary data using printable characters.
Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
Written by Simon Josefsson.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
 
#ifndef BASE64_H
# define BASE64_H
 
/* Get size_t. */
# include <stddef.h>
 
/* Get bool. */
# include <stdbool.h>
 
/* This uses that the expression (n+(k-1))/k means the smallest
integer >= n/k, i.e., the ceiling of n/k. */
# define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4)
 
extern bool isbase64 (char ch);
 
extern void base64_encode (const char * in, size_t inlen,
char * out, size_t outlen);
 
extern size_t base64_encode_alloc (const char *in, size_t inlen, char **out);
 
extern bool base64_decode (const char * in, size_t inlen,
char * out, size_t *outlen);
 
extern bool base64_decode_alloc (const char *in, size_t inlen,
char **out, size_t *outlen);
 
#endif /* BASE64_H */
/programs/network/netsurf/netsurf/utils/config.h
0,0 → 1,120
/*
* Copyright 2003-7 John M Bell <jmb202@ecs.soton.ac.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef _NETSURF_UTILS_CONFIG_H_
#define _NETSURF_UTILS_CONFIG_H_
 
#include <stddef.h>
#include <dirent.h>
 
/* Try to detect which features the target OS supports */
 
#if (defined(_GNU_SOURCE) && !defined(__APPLE__) || defined(__HAIKU__))
#define HAVE_STRNDUP
#else
#undef HAVE_STRNDUP
char *strndup(const char *s, size_t n);
#endif
 
#if (defined(_GNU_SOURCE) || defined(__APPLE__) || defined(__HAIKU__))
#define HAVE_STRCASESTR
#else
#undef HAVE_STRCASESTR
char *strcasestr(const char *haystack, const char *needle);
#endif
 
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
 
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
 
 
 
/* For some reason, UnixLib defines this unconditionally.
* Assume we're using UnixLib if building for RISC OS. */
#if ((defined(_GNU_SOURCE) && !defined(__APPLE__)) || defined(riscos))
#define HAVE_STRCHRNUL
#else
#undef HAVE_STRCHRNUL
char *strchrnul(const char *s, int c);
#endif
 
#define HAVE_INETATON
#if (defined(_WIN32))
#undef HAVE_INETATON
#include <winsock2.h>
#define EAFNOSUPPORT WSAEAFNOSUPPORT
int inet_aton(const char *cp, struct in_addr *inp);
#else
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
 
#define HAVE_INETPTON
#if (defined(_WIN32))
#undef HAVE_INETPTON
int inet_pton(int af, const char *src, void *dst);
#endif
 
#define HAVE_UTSNAME
#if (defined(_WIN32))
#undef HAVE_UTSNAME
#endif
 
#define HAVE_REALPATH
#if (defined(_WIN32))
#undef HAVE_REALPATH
char *realpath(const char *path, char *resolved_path);
#endif
 
#define HAVE_MKDIR
#if (defined(_WIN32))
#undef HAVE_MKDIR
#endif
 
#define HAVE_SIGPIPE
//#if (defined(_WIN32))
#undef HAVE_SIGPIPE
//#endif
 
#define HAVE_STDOUT
#if (defined(_WIN32))
#undef HAVE_STDOUT
#endif
 
//#define HAVE_MMAP
//#if (defined(_WIN32) || defined(riscos) || defined(__HAIKU__) || defined(__BEOS__) || defined(__amigaos4__) || defined(__AMIGA__) || defined(__MINT__))
#undef HAVE_MMAP
//#endif
 
/* This section toggles build options on and off.
* Simply undefine a symbol to turn the relevant feature off.
*
* IF ADDING A FEATURE HERE, ADD IT TO Docs/Doxyfile's "PREDEFINED" DEFINITION AS WELL.
*/
 
/* Platform specific features */
#include <inttypes.h>
 
/* gtk */
#define NO_IPV6
 
#endif
/programs/network/netsurf/netsurf/utils/container.c
0,0 → 1,726
/*
* Copyright 2006 Rob Kendrick <rjek@rjek.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/* To build a stand-alone command-line utility to create and dismantal
* these theme files, build this thusly:
*
* gcc -I../ -DNSTHEME -o themetool container.c
*
* [needs a c99 compiler]
*
* then for instance to create a theme file called mythemefilename
* ./themetool --verbose --create -n"My theme name" mythemefilename\
* --author "Myname" /path/to/directory/containing/theme/files/
*/
 
/** \file
* Container format handling for themes etc. */
 
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include "utils/config.h"
#include "utils/container.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
 
#ifdef WITH_MMAP
#include <sys/mman.h>
#endif
 
#ifdef NSTHEME
bool verbose_log = true;
#endif
 
struct container_dirent {
unsigned char filename[64];
u_int32_t startoffset;
u_int32_t len;
u_int32_t flags1;
u_int32_t flags2;
};
 
struct container_header {
u_int32_t magic; /* 0x4d54534e little endian */
u_int32_t parser;
unsigned char name[32];
unsigned char author[64];
u_int32_t diroffset;
};
 
struct container_ctx {
FILE *fh;
bool creating;
bool processed;
struct container_header header;
unsigned int entries;
unsigned char *data;
struct container_dirent *directory;
};
 
inline static size_t container_filelen(FILE *fd)
{
long o = ftell(fd);
long a;
 
fseek(fd, 0, SEEK_END);
a = ftell(fd);
fseek(fd, o, SEEK_SET);
if (a == -1) {
LOG(("could not ascertain size of file in theme container; omitting"));
return 0;
}
if (((unsigned long) a) > SIZE_MAX) {
LOG(("overlarge file in theme container; possible truncation"));
return SIZE_MAX;
}
return (size_t) a;
}
 
static void container_add_to_dir(struct container_ctx *ctx,
const unsigned char *entryname,
const u_int32_t offset,
const u_int32_t length)
{
struct container_dirent *temp;
temp = realloc(ctx->directory, ctx->entries *
sizeof(struct container_dirent));
if (temp == NULL) {
printf("error adding entry for %s to theme container\n", entryname);
return;
}
ctx->entries += 1;
ctx->directory = temp;
 
strncpy((char *)ctx->directory[ctx->entries - 1].filename,
(char *)entryname, sizeof(ctx->directory[
ctx->entries - 1].filename));
ctx->directory[ctx->entries - 1].startoffset = offset;
ctx->directory[ctx->entries - 1].len = length;
ctx->directory[ctx->entries - 1].flags1 = 0;
ctx->directory[ctx->entries - 1].flags2 = 0;
}
 
struct container_ctx *container_open(const char *filename)
{
size_t val;
struct container_ctx *ctx = calloc(sizeof(struct container_ctx), 1);
 
ctx->fh = fopen(filename, "rb");
 
if (ctx->fh == NULL) {
free(ctx);
return NULL;
}
 
/* we don't actually load any of the data (including directory)
* until we need to, such that _get_name and _get_author are as quick
* as possible. When we have, this gets set to true.
*/
ctx->processed = false;
 
val = fread(&ctx->header.magic, 4, 1, ctx->fh);
if (val == 0)
LOG(("empty read magic"));
ctx->header.magic = ntohl(ctx->header.magic);
 
val = fread(&ctx->header.parser, 4, 1, ctx->fh);
if (val == 0)
LOG(("empty read parser"));
ctx->header.parser = ntohl(ctx->header.parser);
 
val = fread(ctx->header.name, 32, 1, ctx->fh);
if (val == 0)
LOG(("empty read name"));
val = fread(ctx->header.author, 64, 1, ctx->fh);
if (val == 0)
LOG(("empty read author"));
 
val = fread(&ctx->header.diroffset, 4, 1, ctx->fh);
if (val == 0)
LOG(("empty read diroffset"));
ctx->header.diroffset = ntohl(ctx->header.diroffset);
 
if (ctx->header.magic != 0x4e53544d || ctx->header.parser != 3) {
fclose(ctx->fh);
free(ctx);
return NULL;
}
 
return ctx;
}
 
static void container_process(struct container_ctx *ctx)
{
size_t val;
unsigned char filename[64];
u_int32_t start, len, flags1, flags2;
 
#ifdef WITH_MMAP
ctx->data = mmap(NULL, ctx->header.diroffset, PROT_READ, MAP_PRIVATE,
fileno(ctx->fh), 0);
#else
ctx->data = malloc(ctx->header.diroffset);
fseek(ctx->fh, 0, SEEK_SET);
val = fread(ctx->data, ctx->header.diroffset, 1, ctx->fh);
if (val == 0)
LOG(("empty read diroffset"));
#endif
fseek(ctx->fh, ctx->header.diroffset, SEEK_SET);
/* now work through the directory structure taking it apart into
* our structure */
#define BEREAD(x) do { val = fread(&(x), 4, 1, ctx->fh); if (val == 0)\
LOG(("empty read"));(x) = ntohl((x)); } while (0)
do {
val = fread(filename, 64, 1, ctx->fh);
if (val == 0)
LOG(("empty read filename"));
BEREAD(start);
BEREAD(len);
BEREAD(flags1);
BEREAD(flags2);
if (filename[0] != '\0')
container_add_to_dir(ctx, filename, start, len);
} while (filename[0] != '\0');
#undef BEREAD
ctx->processed = true;
}
 
static const struct container_dirent *container_lookup(
struct container_ctx *ctx,
const unsigned char *entryname)
{
unsigned int i;
 
for (i = 1; i <= ctx->entries; i++) {
struct container_dirent *e = ctx->directory + i - 1;
if (strcmp((char *)e->filename, (char *)entryname) == 0)
return e;
}
 
return NULL;
}
 
const unsigned char *container_get(struct container_ctx *ctx,
const unsigned char *entryname,
u_int32_t *size)
{
const struct container_dirent *e;
 
if (ctx->processed == false)
container_process(ctx);
 
e = container_lookup(ctx, entryname);
 
if (e == NULL)
return NULL;
 
*size = e->len;
 
return &ctx->data[e->startoffset];
}
 
const unsigned char *container_iterate(struct container_ctx *ctx, int *state)
{
struct container_dirent *e;
unsigned char *r;
 
if (ctx->processed == false)
container_process(ctx);
 
e = ctx->directory + *state;
 
r = e->filename;
 
if (r == NULL || r[0] == '\0')
r = NULL;
 
*state += 1;
 
return r;
}
 
const unsigned char *container_get_name(struct container_ctx *ctx)
{
return ctx->header.name;
}
 
const unsigned char *container_get_author(struct container_ctx *ctx)
{
return ctx->header.author;
}
 
 
static void container_write_dir(struct container_ctx *ctx)
{
size_t val;
unsigned int i;
u_int32_t tmp;
#define BEWRITE(x) do {tmp = htonl((x)); val = fwrite(&tmp, 4, 1, ctx->fh);\
if (val == 0) LOG(("empty write")); } while(0)
for (i = 1; i <= ctx->entries; i++) {
struct container_dirent *e = ctx->directory + i - 1;
val = fwrite(e->filename, 64, 1, ctx->fh);
if (val == 0)
LOG(("empty write filename"));
BEWRITE(e->startoffset);
BEWRITE(e->len);
BEWRITE(e->flags1);
BEWRITE(e->flags2);
}
#undef BEWRITE
/* empty entry signifies end of directory */
tmp = 0;
val = fwrite(&tmp, 4, 8, ctx->fh);
if (val == 0)
LOG(("empty write end"));
}
 
struct container_ctx *container_create(const char *filename,
const unsigned char *name,
const unsigned char *author)
{
size_t val;
struct container_ctx *ctx = calloc(sizeof(struct container_ctx), 1);
 
ctx->fh = fopen(filename, "wb");
 
if (ctx->fh == NULL) {
free(ctx);
return NULL;
}
 
ctx->creating = true;
ctx->entries = 0;
ctx->directory = NULL;
ctx->header.parser = htonl(3);
strncpy((char *)ctx->header.name, (char *)name, 32);
strncpy((char *)ctx->header.author, (char *)author, 64);
 
val = fwrite("NSTM", 4, 1, ctx->fh);
if (val == 0)
LOG(("empty write NSTM"));
val = fwrite(&ctx->header.parser, 4, 1, ctx->fh);
if (val == 0)
LOG(("empty write parser"));
val = fwrite(ctx->header.name, 32, 1, ctx->fh);
if (val == 0)
LOG(("empty write name"));
val = fwrite(ctx->header.author, 64, 1, ctx->fh);
if (val == 0)
LOG(("empty write author"));
 
ctx->header.diroffset = 108;
 
/* skip over the directory offset for now, and fill it in later.
* we don't know where it'll be yet!
*/
 
fseek(ctx->fh, 108, SEEK_SET);
 
return ctx;
}
 
void container_add(struct container_ctx *ctx, const unsigned char *entryname,
const unsigned char *data,
const u_int32_t datalen)
{
size_t val;
container_add_to_dir(ctx, entryname, ftell(ctx->fh), datalen);
val = fwrite(data, datalen, 1, ctx->fh);
if (val == 0)
LOG(("empty write add file"));
}
 
void container_close(struct container_ctx *ctx)
{
if (ctx->creating == true) {
size_t flen, nflen, val;
 
/* discover where the directory's going to go. */
flen = container_filelen(ctx->fh);
flen = (flen + 3) & (~3); /* round up to nearest 4 bytes */
 
/* write this location to the header */
fseek(ctx->fh, 104, SEEK_SET);
nflen = htonl(flen);
val = fwrite(&nflen, 4, 1, ctx->fh);
if (val == 0)
LOG(("empty write directory location"));
 
/* seek to where the directory will be, and write it */
fseek(ctx->fh, flen, SEEK_SET);
container_write_dir(ctx);
 
} else if (ctx->processed) {
#ifdef WITH_MMAP
munmap(ctx->data, ctx->header.diroffset);
#else
free(ctx->data);
#endif
}
 
fclose(ctx->fh);
free(ctx);
}
 
#ifdef WITH_THEME_INSTALL
 
/**
* install theme from container
* \param themefile a file containing the containerized theme
* \param dirbasename a directory basename including trailing path sep; the
* full path of the theme is then a subdirectory of that
* caller owns reference to returned string, NULL for error
*/
 
char *container_extract_theme(const char *themefile, const char *dirbasename)
{
struct stat statbuf;
struct container_ctx *cctx;
FILE *fh;
size_t val;
const unsigned char *e, *d;
char *themename, *dirname;
char path[PATH_MAX];
int state = 0;
unsigned int i;
u_int32_t flen;
 
cctx = container_open(themefile);
if (cctx == NULL) {
warn_user("FileOpenError", themefile);
return NULL;
}
themename = strdup((const char *)container_get_name(cctx));
if (themename == NULL) {
warn_user("NoMemory", 0);
container_close(cctx);
return NULL;
}
LOG(("theme name: %s", themename));
LOG(("theme author: %s", container_get_author(cctx)));
dirname = malloc(strlen(dirbasename) + strlen(themename) + 2);
if (dirname == NULL) {
warn_user(messages_get("NoMemory"), 0);
free(themename);
container_close(cctx);
return NULL;
}
strcpy(dirname, dirbasename);
strcat(dirname, themename);
if (stat(dirname, &statbuf) != -1) {
warn_user("DirectoryError", dirname);
container_close(cctx);
free(dirname);
free(themename);
return NULL;
}
mkdir(dirname, S_IRWXU);
 
for (e = container_iterate(cctx, &state), i = 0; i < cctx->entries;
e = container_iterate(cctx, &state), i++) {
LOG(("extracting %s", e));
snprintf(path, PATH_MAX, "%s/%s", dirname, e);
fh = fopen(path, "wb");
if (fh == NULL) {
warn_user("FileOpenError", (char *)e);
} else {
d = container_get(cctx, e, &flen);
val = fwrite(d, flen, 1, fh);
if (val == 0)
LOG(("empty write"));
fclose(fh);
}
}
LOG(("theme container unpacked"));
container_close(cctx);
free(dirname);
return themename;
 
}
 
#endif
 
#ifdef TEST_RIG
int main(int argc, char *argv[])
{
struct container_ctx *ctx = container_create("test.theme", "Test theme",
"Rob Kendrick");
u_int32_t size;
int state = 0;
char *n;
 
container_add(ctx, "CHEESE", "This is a test of some cheese.", sizeof("This is a test of some cheese."));
container_add(ctx, "FOO", "This is a test of some cheese.", sizeof("This is a test of some cheese."));
 
container_close(ctx);
 
ctx = container_open("test.theme");
 
printf("Theme name: %s\n", container_get_name(ctx));
printf("Theme author: %s\n", container_get_author(ctx));
 
printf("Test string: %s\n", container_get(ctx, "CHEESE", &size));
printf("Length of text: %d\n", size);
 
while ( (n = container_iterate(ctx, &state)) ) {
printf("%s\n", n);
}
 
container_close(ctx);
 
exit(0);
}
#endif
 
#ifdef NSTHEME
/* code to implement a simple container creator/extractor */
#include <getopt.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
 
static bool verbose = false;
 
static void show_usage(const char *argv0)
{
fprintf(stderr, "%s [options] <theme file> <directory>\n", argv0);
fprintf(stderr, " --help This text\n");
fprintf(stderr, " --create Create theme file from directory\n");
fprintf(stderr, " --extract Extract theme file into directory\n");
fprintf(stderr, " --name x Set theme's name when creating\n");
fprintf(stderr, " --author x Set theme's author when creating\n");
fprintf(stderr, " --verbose Print progress information\n");
fprintf(stderr, "\nOne and only one of --create or --extract must be specified.\n");
}
 
static void extract_theme(const char *themefile, const char *dirname)
{
struct stat statbuf;
struct container_ctx *cctx;
FILE *fh;
const unsigned char *e, *d;
char path[PATH_MAX];
int i, state = 0;
u_int32_t flen;
 
 
if (stat(dirname, &statbuf) != -1) {
fprintf(stderr, "error: directory '%s' already exists.\n",
dirname);
exit(1);
}
 
mkdir(dirname, S_IRWXU);
 
cctx = container_open(themefile);
if (cctx == NULL) {
fprintf(stderr, "error: unable to open theme file '%s'\n",
themefile);
exit(1);
}
 
if (verbose == true) {
printf("theme name: %s\n", container_get_name(cctx));
printf("theme author: %s\n", container_get_author(cctx));
}
 
for (e = container_iterate(cctx, &state), i = 0; i < cctx->entries;
e = container_iterate(cctx, &state), i++) {
if (verbose == true)
printf("extracting %s\n", e);
snprintf(path, PATH_MAX, "%s/%s", dirname, e);
fh = fopen(path, "wb");
if (fh == NULL) {
perror("warning: unable to open file for output");
} else {
d = container_get(cctx, e, &flen);
fwrite(d, flen, 1, fh);
fclose(fh);
}
}
 
container_close(cctx);
 
}
 
static void create_theme(const char *themefile, const char *dirname,
const unsigned char *name,
const unsigned char *author)
{
DIR *dir = opendir(dirname);
FILE *fh;
struct dirent *e;
struct stat statbuf;
struct container_ctx *cctx;
unsigned char *data;
char path[PATH_MAX];
size_t flen;
int t;
 
if (dir == NULL) {
perror("error: unable to open directory");
exit(1);
}
 
cctx = container_create(themefile, name, author);
 
errno = 0; /* to distinguish between end of dir and err */
 
while ((e = readdir(dir)) != NULL) {
if (strcmp(e->d_name, ".") != 0 &&
strcmp(e->d_name, "..") != 0) {
/* not the metadirs, so we want to process this. */
if (verbose == true)
printf("adding %s\n", e->d_name);
if (strlen(e->d_name) > 63) {
fprintf(stderr,
"warning: name truncated to length 63.\n");
}
 
snprintf(path, PATH_MAX, "%s/%s", dirname, e->d_name);
 
stat(path, &statbuf);
if (S_ISDIR(statbuf.st_mode)) {
fprintf(stderr,
"warning: skipping directory '%s'\n",
e->d_name);
continue;
}
 
fh = fopen(path, "rb");
if (fh == NULL) {
fprintf(stderr,
"warning: unable to open, skipping.");
} else {
flen = statbuf.st_size;
data = malloc(flen);
t = fread(data, flen, 1, fh);
fclose(fh);
container_add(cctx, (unsigned char *)e->d_name,
data, flen);
free(data);
}
}
errno = 0;
}
 
if (errno != 0) {
perror("error: couldn't enumerate directory");
closedir(dir);
container_close(cctx);
exit(1);
}
 
closedir(dir);
container_close(cctx);
}
 
int main(int argc, char *argv[])
{
static struct option l_opts[] = {
{ "help", 0, 0, 'h' },
{ "create", 0, 0, 'c' },
{ "extract", 0, 0, 'x' },
{ "name", 1, 0, 'n' },
{ "author", 1, 0, 'a' },
{ "verbose", 0, 0, 'v' },
 
{ NULL, 0, 0, 0 }
};
 
static char *s_opts = "hcxn:a:v";
int optch, optidx;
bool creating = false, extracting = false;
unsigned char name[32] = { '\0' }, author[64] = { '\0' };
char *themefile, *dirname;
 
while ((optch = getopt_long(argc, argv, s_opts, l_opts, &optidx)) != -1)
switch (optch) {
case 'h':
show_usage(argv[0]);
exit(0);
break;
case 'c':
creating = true;
break;
case 'x':
extracting = true;
break;
case 'n':
strncpy((char *)name, optarg, 31);
if (strlen(optarg) > 32)
fprintf(stderr, "warning: theme name truncated to 32 characters.\n");
break;
case 'a':
strncpy((char *)author, optarg, 63);
if (strlen(optarg) > 64)
fprintf(stderr, "warning: theme author truncated to 64 characters.\n");
break;
case 'v':
verbose = true;
break;
default:
show_usage(argv[0]);
exit(1);
break;
}
 
if (creating == extracting) {
show_usage(argv[0]);
exit(1);
}
 
if ((argc - optind) < 2) {
show_usage(argv[0]);
exit(1);
}
 
if (creating == true &&
(strlen((char *)name) == 0 || strlen((char *)author) == 0)) {
fprintf(stderr, "No theme name and/or author specified.\n");
show_usage(argv[0]);
exit(1);
}
 
themefile = strdup(argv[optind]);
dirname = strdup(argv[optind + 1]);
 
if (verbose == true)
printf("%s '%s' %s directory '%s'\n",
creating ? "creating" : "extracting", themefile,
creating ? "from" : "to", dirname);
 
if (creating) {
if (verbose == true)
printf("name = %s, author = %s\n", name, author);
create_theme(themefile, dirname, name, author);
} else {
extract_theme(themefile, dirname);
}
 
return 0;
}
#endif
/programs/network/netsurf/netsurf/utils/container.h
0,0 → 1,53
/*
* Copyright 2006 Rob Kendrick <rjek@rjek.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Container format handling for themes etc. */
 
#ifndef __CONTAINER_H__
#define __CONTAINER_H__
 
#include <sys/types.h>
 
struct container_ctx;
 
/* reading interface */
struct container_ctx *container_open(const char *filename);
const unsigned char *container_get(struct container_ctx *ctx,
const unsigned char *entryname,
u_int32_t *size);
const unsigned char *container_get_name(struct container_ctx *ctx);
const unsigned char *container_get_author(struct container_ctx *ctx);
const unsigned char *container_iterate(struct container_ctx *ctx,
int *state);
 
/* creating interface */
struct container_ctx *container_create(const char *filename,
const unsigned char *name,
const unsigned char *author);
void container_add(struct container_ctx *ctx, const unsigned char *entryname,
const unsigned char *data,
const u_int32_t datalen);
 
/* common interface */
void container_close(struct container_ctx *ctx);
 
#ifdef WITH_THEME_INSTALL
char *container_extract_theme(const char *themefile, const char *dirbasename);
#endif
#endif /* __CONTAINER_H__ */
/programs/network/netsurf/netsurf/utils/corestrings.c
0,0 → 1,731
/*
* Copyright 2012 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Useful interned string pointers (implementation).
*/
 
#include <dom/dom.h>
 
#include "utils/corestrings.h"
#include "utils/utils.h"
 
/* lwc_string strings */
lwc_string *corestring_lwc_a;
lwc_string *corestring_lwc_abscenter;
lwc_string *corestring_lwc_absmiddle;
lwc_string *corestring_lwc_align;
lwc_string *corestring_lwc_applet;
lwc_string *corestring_lwc_base;
lwc_string *corestring_lwc_baseline;
lwc_string *corestring_lwc_body;
lwc_string *corestring_lwc_bottom;
lwc_string *corestring_lwc_button;
lwc_string *corestring_lwc_caption;
lwc_string *corestring_lwc_center;
lwc_string *corestring_lwc_checkbox;
lwc_string *corestring_lwc_circle;
lwc_string *corestring_lwc_col;
lwc_string *corestring_lwc_default;
lwc_string *corestring_lwc_div;
lwc_string *corestring_lwc_embed;
lwc_string *corestring_lwc_file;
lwc_string *corestring_lwc_font;
lwc_string *corestring_lwc_frame;
lwc_string *corestring_lwc_frameset;
lwc_string *corestring_lwc_h1;
lwc_string *corestring_lwc_h2;
lwc_string *corestring_lwc_h3;
lwc_string *corestring_lwc_h4;
lwc_string *corestring_lwc_h5;
lwc_string *corestring_lwc_h6;
lwc_string *corestring_lwc_head;
lwc_string *corestring_lwc_hidden;
lwc_string *corestring_lwc_hr;
lwc_string *corestring_lwc_html;
lwc_string *corestring_lwc_https;
lwc_string *corestring_lwc_iframe;
lwc_string *corestring_lwc_image;
lwc_string *corestring_lwc_img;
lwc_string *corestring_lwc_input;
lwc_string *corestring_lwc_justify;
lwc_string *corestring_lwc_left;
lwc_string *corestring_lwc_li;
lwc_string *corestring_lwc_link;
lwc_string *corestring_lwc_meta;
lwc_string *corestring_lwc_middle;
lwc_string *corestring_lwc_multipart_form_data;
lwc_string *corestring_lwc_no;
lwc_string *corestring_lwc_noscript;
lwc_string *corestring_lwc_object;
lwc_string *corestring_lwc_optgroup;
lwc_string *corestring_lwc_option;
lwc_string *corestring_lwc_p;
lwc_string *corestring_lwc_param;
lwc_string *corestring_lwc_password;
lwc_string *corestring_lwc_poly;
lwc_string *corestring_lwc_polygon;
lwc_string *corestring_lwc_post;
lwc_string *corestring_lwc_radio;
lwc_string *corestring_lwc_rect;
lwc_string *corestring_lwc_rectangle;
lwc_string *corestring_lwc_refresh;
lwc_string *corestring_lwc_reset;
lwc_string *corestring_lwc_right;
lwc_string *corestring_lwc_search;
lwc_string *corestring_lwc_select;
lwc_string *corestring_lwc_src;
lwc_string *corestring_lwc_style;
lwc_string *corestring_lwc_submit;
lwc_string *corestring_lwc_table;
lwc_string *corestring_lwc_tbody;
lwc_string *corestring_lwc_td;
lwc_string *corestring_lwc_text;
lwc_string *corestring_lwc_textarea;
lwc_string *corestring_lwc_texttop;
lwc_string *corestring_lwc_text_css;
lwc_string *corestring_lwc_tfoot;
lwc_string *corestring_lwc_th;
lwc_string *corestring_lwc_thead;
lwc_string *corestring_lwc_title;
lwc_string *corestring_lwc_top;
lwc_string *corestring_lwc_tr;
lwc_string *corestring_lwc_ul;
lwc_string *corestring_lwc_url;
lwc_string *corestring_lwc_yes;
lwc_string *corestring_lwc__blank;
lwc_string *corestring_lwc__parent;
lwc_string *corestring_lwc__self;
lwc_string *corestring_lwc__top;
 
/* dom_string strings */
dom_string *corestring_dom_a;
dom_string *corestring_dom_abort;
dom_string *corestring_dom_afterprint;
dom_string *corestring_dom_align;
dom_string *corestring_dom_area;
dom_string *corestring_dom_async;
dom_string *corestring_dom_background;
dom_string *corestring_dom_beforeprint;
dom_string *corestring_dom_beforeunload;
dom_string *corestring_dom_bgcolor;
dom_string *corestring_dom_blur;
dom_string *corestring_dom_border;
dom_string *corestring_dom_bordercolor;
dom_string *corestring_dom_cancel;
dom_string *corestring_dom_canplay;
dom_string *corestring_dom_canplaythrough;
dom_string *corestring_dom_cellpadding;
dom_string *corestring_dom_cellspacing;
dom_string *corestring_dom_change;
dom_string *corestring_dom_charset;
dom_string *corestring_dom_class;
dom_string *corestring_dom_click;
dom_string *corestring_dom_close;
dom_string *corestring_dom_color;
dom_string *corestring_dom_cols;
dom_string *corestring_dom_content;
dom_string *corestring_dom_contextmenu;
dom_string *corestring_dom_coords;
dom_string *corestring_dom_cuechange;
dom_string *corestring_dom_dblclick;
dom_string *corestring_dom_defer;
dom_string *corestring_dom_drag;
dom_string *corestring_dom_dragend;
dom_string *corestring_dom_dragenter;
dom_string *corestring_dom_dragleave;
dom_string *corestring_dom_dragover;
dom_string *corestring_dom_dragstart;
dom_string *corestring_dom_drop;
dom_string *corestring_dom_durationchange;
dom_string *corestring_dom_emptied;
dom_string *corestring_dom_ended;
dom_string *corestring_dom_error;
dom_string *corestring_dom_focus;
dom_string *corestring_dom_hashchange;
dom_string *corestring_dom_height;
dom_string *corestring_dom_href;
dom_string *corestring_dom_hreflang;
dom_string *corestring_dom_hspace;
dom_string *corestring_dom_http_equiv;
dom_string *corestring_dom_id;
dom_string *corestring_dom_input;
dom_string *corestring_dom_invalid;
dom_string *corestring_dom_keydown;
dom_string *corestring_dom_keypress;
dom_string *corestring_dom_keyup;
dom_string *corestring_dom_link;
dom_string *corestring_dom_load;
dom_string *corestring_dom_loadeddata;
dom_string *corestring_dom_loadedmetadata;
dom_string *corestring_dom_loadstart;
dom_string *corestring_dom_map;
dom_string *corestring_dom_media;
dom_string *corestring_dom_message;
dom_string *corestring_dom_mousedown;
dom_string *corestring_dom_mousemove;
dom_string *corestring_dom_mouseout;
dom_string *corestring_dom_mouseover;
dom_string *corestring_dom_mouseup;
dom_string *corestring_dom_mousewheel;
dom_string *corestring_dom_name;
dom_string *corestring_dom_nohref;
dom_string *corestring_dom_offline;
dom_string *corestring_dom_online;
dom_string *corestring_dom_pagehide;
dom_string *corestring_dom_pageshow;
dom_string *corestring_dom_pause;
dom_string *corestring_dom_play;
dom_string *corestring_dom_playing;
dom_string *corestring_dom_popstate;
dom_string *corestring_dom_progress;
dom_string *corestring_dom_ratechange;
dom_string *corestring_dom_readystatechange;
dom_string *corestring_dom_rect;
dom_string *corestring_dom_rel;
dom_string *corestring_dom_reset;
dom_string *corestring_dom_resize;
dom_string *corestring_dom_rows;
dom_string *corestring_dom_scroll;
dom_string *corestring_dom_seeked;
dom_string *corestring_dom_seeking;
dom_string *corestring_dom_select;
dom_string *corestring_dom_shape;
dom_string *corestring_dom_show;
dom_string *corestring_dom_size;
dom_string *corestring_dom_sizes;
dom_string *corestring_dom_src;
dom_string *corestring_dom_stalled;
dom_string *corestring_dom_storage;
dom_string *corestring_dom_submit;
dom_string *corestring_dom_suspend;
dom_string *corestring_dom_target;
dom_string *corestring_dom_text;
dom_string *corestring_dom_text_javascript;
dom_string *corestring_dom_timeupdate;
dom_string *corestring_dom_type;
dom_string *corestring_dom_unload;
dom_string *corestring_dom_valign;
dom_string *corestring_dom_vlink;
dom_string *corestring_dom_volumechange;
dom_string *corestring_dom_vspace;
dom_string *corestring_dom_waiting;
dom_string *corestring_dom_width;
 
 
/*
* Free the core strings
*/
void corestrings_fini(void)
{
#define CSS_LWC_STRING_UNREF(NAME) \
do { \
if (corestring_lwc_##NAME != NULL) { \
lwc_string_unref(corestring_lwc_##NAME); \
corestring_lwc_##NAME = NULL; \
} \
} while (0)
 
CSS_LWC_STRING_UNREF(a);
CSS_LWC_STRING_UNREF(abscenter);
CSS_LWC_STRING_UNREF(absmiddle);
CSS_LWC_STRING_UNREF(align);
CSS_LWC_STRING_UNREF(applet);
CSS_LWC_STRING_UNREF(base);
CSS_LWC_STRING_UNREF(baseline);
CSS_LWC_STRING_UNREF(body);
CSS_LWC_STRING_UNREF(bottom);
CSS_LWC_STRING_UNREF(button);
CSS_LWC_STRING_UNREF(caption);
CSS_LWC_STRING_UNREF(center);
CSS_LWC_STRING_UNREF(checkbox);
CSS_LWC_STRING_UNREF(circle);
CSS_LWC_STRING_UNREF(col);
CSS_LWC_STRING_UNREF(default);
CSS_LWC_STRING_UNREF(div);
CSS_LWC_STRING_UNREF(embed);
CSS_LWC_STRING_UNREF(file);
CSS_LWC_STRING_UNREF(font);
CSS_LWC_STRING_UNREF(frame);
CSS_LWC_STRING_UNREF(frameset);
CSS_LWC_STRING_UNREF(h1);
CSS_LWC_STRING_UNREF(h2);
CSS_LWC_STRING_UNREF(h3);
CSS_LWC_STRING_UNREF(h4);
CSS_LWC_STRING_UNREF(h5);
CSS_LWC_STRING_UNREF(h6);
CSS_LWC_STRING_UNREF(head);
CSS_LWC_STRING_UNREF(hidden);
CSS_LWC_STRING_UNREF(hr);
CSS_LWC_STRING_UNREF(html);
CSS_LWC_STRING_UNREF(https);
CSS_LWC_STRING_UNREF(iframe);
CSS_LWC_STRING_UNREF(image);
CSS_LWC_STRING_UNREF(img);
CSS_LWC_STRING_UNREF(input);
CSS_LWC_STRING_UNREF(justify);
CSS_LWC_STRING_UNREF(left);
CSS_LWC_STRING_UNREF(li);
CSS_LWC_STRING_UNREF(link);
CSS_LWC_STRING_UNREF(meta);
CSS_LWC_STRING_UNREF(middle);
CSS_LWC_STRING_UNREF(multipart_form_data);
CSS_LWC_STRING_UNREF(no);
CSS_LWC_STRING_UNREF(noscript);
CSS_LWC_STRING_UNREF(object);
CSS_LWC_STRING_UNREF(optgroup);
CSS_LWC_STRING_UNREF(option);
CSS_LWC_STRING_UNREF(p);
CSS_LWC_STRING_UNREF(param);
CSS_LWC_STRING_UNREF(password);
CSS_LWC_STRING_UNREF(poly);
CSS_LWC_STRING_UNREF(polygon);
CSS_LWC_STRING_UNREF(post);
CSS_LWC_STRING_UNREF(radio);
CSS_LWC_STRING_UNREF(rect);
CSS_LWC_STRING_UNREF(rectangle);
CSS_LWC_STRING_UNREF(refresh);
CSS_LWC_STRING_UNREF(reset);
CSS_LWC_STRING_UNREF(right);
CSS_LWC_STRING_UNREF(search);
CSS_LWC_STRING_UNREF(select);
CSS_LWC_STRING_UNREF(src);
CSS_LWC_STRING_UNREF(style);
CSS_LWC_STRING_UNREF(submit);
CSS_LWC_STRING_UNREF(table);
CSS_LWC_STRING_UNREF(tbody);
CSS_LWC_STRING_UNREF(td);
CSS_LWC_STRING_UNREF(text);
CSS_LWC_STRING_UNREF(textarea);
CSS_LWC_STRING_UNREF(texttop);
CSS_LWC_STRING_UNREF(text_css);
CSS_LWC_STRING_UNREF(tfoot);
CSS_LWC_STRING_UNREF(th);
CSS_LWC_STRING_UNREF(thead);
CSS_LWC_STRING_UNREF(title);
CSS_LWC_STRING_UNREF(top);
CSS_LWC_STRING_UNREF(tr);
CSS_LWC_STRING_UNREF(ul);
CSS_LWC_STRING_UNREF(url);
CSS_LWC_STRING_UNREF(yes);
CSS_LWC_STRING_UNREF(_blank);
CSS_LWC_STRING_UNREF(_parent);
CSS_LWC_STRING_UNREF(_self);
CSS_LWC_STRING_UNREF(_top);
 
#undef CSS_LWC_STRING_UNREF
 
#define CSS_DOM_STRING_UNREF(NAME) \
do { \
if (corestring_dom_##NAME != NULL) { \
dom_string_unref(corestring_dom_##NAME); \
corestring_dom_##NAME = NULL; \
} \
} while (0)
 
CSS_DOM_STRING_UNREF(a);
CSS_DOM_STRING_UNREF(abort);
CSS_DOM_STRING_UNREF(afterprint);
CSS_DOM_STRING_UNREF(align);
CSS_DOM_STRING_UNREF(area);
CSS_DOM_STRING_UNREF(async);
CSS_DOM_STRING_UNREF(background);
CSS_DOM_STRING_UNREF(beforeprint);
CSS_DOM_STRING_UNREF(beforeunload);
CSS_DOM_STRING_UNREF(bgcolor);
CSS_DOM_STRING_UNREF(blur);
CSS_DOM_STRING_UNREF(border);
CSS_DOM_STRING_UNREF(bordercolor);
CSS_DOM_STRING_UNREF(cancel);
CSS_DOM_STRING_UNREF(canplay);
CSS_DOM_STRING_UNREF(canplaythrough);
CSS_DOM_STRING_UNREF(cellpadding);
CSS_DOM_STRING_UNREF(cellspacing);
CSS_DOM_STRING_UNREF(change);
CSS_DOM_STRING_UNREF(charset);
CSS_DOM_STRING_UNREF(class);
CSS_DOM_STRING_UNREF(click);
CSS_DOM_STRING_UNREF(close);
CSS_DOM_STRING_UNREF(color);
CSS_DOM_STRING_UNREF(cols);
CSS_DOM_STRING_UNREF(content);
CSS_DOM_STRING_UNREF(contextmenu);
CSS_DOM_STRING_UNREF(coords);
CSS_DOM_STRING_UNREF(cuechange);
CSS_DOM_STRING_UNREF(dblclick);
CSS_DOM_STRING_UNREF(defer);
CSS_DOM_STRING_UNREF(drag);
CSS_DOM_STRING_UNREF(dragend);
CSS_DOM_STRING_UNREF(dragenter);
CSS_DOM_STRING_UNREF(dragleave);
CSS_DOM_STRING_UNREF(dragover);
CSS_DOM_STRING_UNREF(dragstart);
CSS_DOM_STRING_UNREF(drop);
CSS_DOM_STRING_UNREF(durationchange);
CSS_DOM_STRING_UNREF(emptied);
CSS_DOM_STRING_UNREF(ended);
CSS_DOM_STRING_UNREF(error);
CSS_DOM_STRING_UNREF(focus);
CSS_DOM_STRING_UNREF(hashchange);
CSS_DOM_STRING_UNREF(height);
CSS_DOM_STRING_UNREF(href);
CSS_DOM_STRING_UNREF(hreflang);
CSS_DOM_STRING_UNREF(hspace);
CSS_DOM_STRING_UNREF(http_equiv);
CSS_DOM_STRING_UNREF(id);
CSS_DOM_STRING_UNREF(input);
CSS_DOM_STRING_UNREF(invalid);
CSS_DOM_STRING_UNREF(keydown);
CSS_DOM_STRING_UNREF(keypress);
CSS_DOM_STRING_UNREF(keyup);
CSS_DOM_STRING_UNREF(link);
CSS_DOM_STRING_UNREF(load);
CSS_DOM_STRING_UNREF(loadeddata);
CSS_DOM_STRING_UNREF(loadedmetadata);
CSS_DOM_STRING_UNREF(loadstart);
CSS_DOM_STRING_UNREF(map);
CSS_DOM_STRING_UNREF(media);
CSS_DOM_STRING_UNREF(message);
CSS_DOM_STRING_UNREF(mousedown);
CSS_DOM_STRING_UNREF(mousemove);
CSS_DOM_STRING_UNREF(mouseout);
CSS_DOM_STRING_UNREF(mouseover);
CSS_DOM_STRING_UNREF(mouseup);
CSS_DOM_STRING_UNREF(mousewheel);
CSS_DOM_STRING_UNREF(name);
CSS_DOM_STRING_UNREF(nohref);
CSS_DOM_STRING_UNREF(offline);
CSS_DOM_STRING_UNREF(online);
CSS_DOM_STRING_UNREF(pagehide);
CSS_DOM_STRING_UNREF(pageshow);
CSS_DOM_STRING_UNREF(pause);
CSS_DOM_STRING_UNREF(play);
CSS_DOM_STRING_UNREF(playing);
CSS_DOM_STRING_UNREF(popstate);
CSS_DOM_STRING_UNREF(progress);
CSS_DOM_STRING_UNREF(ratechange);
CSS_DOM_STRING_UNREF(readystatechange);
CSS_DOM_STRING_UNREF(rect);
CSS_DOM_STRING_UNREF(rel);
CSS_DOM_STRING_UNREF(reset);
CSS_DOM_STRING_UNREF(resize);
CSS_DOM_STRING_UNREF(rows);
CSS_DOM_STRING_UNREF(scroll);
CSS_DOM_STRING_UNREF(seeked);
CSS_DOM_STRING_UNREF(seeking);
CSS_DOM_STRING_UNREF(select);
CSS_DOM_STRING_UNREF(shape);
CSS_DOM_STRING_UNREF(show);
CSS_DOM_STRING_UNREF(size);
CSS_DOM_STRING_UNREF(sizes);
CSS_DOM_STRING_UNREF(src);
CSS_DOM_STRING_UNREF(stalled);
CSS_DOM_STRING_UNREF(storage);
CSS_DOM_STRING_UNREF(submit);
CSS_DOM_STRING_UNREF(suspend);
CSS_DOM_STRING_UNREF(target);
CSS_DOM_STRING_UNREF(text);
CSS_DOM_STRING_UNREF(text_javascript);
CSS_DOM_STRING_UNREF(timeupdate);
CSS_DOM_STRING_UNREF(type);
CSS_DOM_STRING_UNREF(unload);
CSS_DOM_STRING_UNREF(valign);
CSS_DOM_STRING_UNREF(vlink);
CSS_DOM_STRING_UNREF(volumechange);
CSS_DOM_STRING_UNREF(vspace);
CSS_DOM_STRING_UNREF(waiting);
CSS_DOM_STRING_UNREF(width);
#undef CSS_DOM_STRING_UNREF
}
 
 
/*
* Create the core strings
*/
nserror corestrings_init(void)
{
lwc_error lerror;
nserror error;
dom_exception exc;
 
#define CSS_LWC_STRING_INTERN(NAME) \
do { \
lerror = lwc_intern_string( \
(const char *)#NAME, \
sizeof(#NAME) - 1, \
&corestring_lwc_##NAME ); \
if ((lerror != lwc_error_ok) || \
(corestring_lwc_##NAME == NULL)) { \
error = NSERROR_NOMEM; \
goto error; \
} \
} while(0)
 
CSS_LWC_STRING_INTERN(a);
CSS_LWC_STRING_INTERN(abscenter);
CSS_LWC_STRING_INTERN(absmiddle);
CSS_LWC_STRING_INTERN(align);
CSS_LWC_STRING_INTERN(applet);
CSS_LWC_STRING_INTERN(base);
CSS_LWC_STRING_INTERN(baseline);
CSS_LWC_STRING_INTERN(body);
CSS_LWC_STRING_INTERN(bottom);
CSS_LWC_STRING_INTERN(button);
CSS_LWC_STRING_INTERN(caption);
CSS_LWC_STRING_INTERN(center);
CSS_LWC_STRING_INTERN(checkbox);
CSS_LWC_STRING_INTERN(circle);
CSS_LWC_STRING_INTERN(col);
CSS_LWC_STRING_INTERN(default);
CSS_LWC_STRING_INTERN(div);
CSS_LWC_STRING_INTERN(embed);
CSS_LWC_STRING_INTERN(file);
CSS_LWC_STRING_INTERN(font);
CSS_LWC_STRING_INTERN(frame);
CSS_LWC_STRING_INTERN(frameset);
CSS_LWC_STRING_INTERN(h1);
CSS_LWC_STRING_INTERN(h2);
CSS_LWC_STRING_INTERN(h3);
CSS_LWC_STRING_INTERN(h4);
CSS_LWC_STRING_INTERN(h5);
CSS_LWC_STRING_INTERN(h6);
CSS_LWC_STRING_INTERN(head);
CSS_LWC_STRING_INTERN(hidden);
CSS_LWC_STRING_INTERN(hr);
CSS_LWC_STRING_INTERN(html);
CSS_LWC_STRING_INTERN(https);
CSS_LWC_STRING_INTERN(iframe);
CSS_LWC_STRING_INTERN(image);
CSS_LWC_STRING_INTERN(img);
CSS_LWC_STRING_INTERN(input);
CSS_LWC_STRING_INTERN(justify);
CSS_LWC_STRING_INTERN(left);
CSS_LWC_STRING_INTERN(li);
CSS_LWC_STRING_INTERN(link);
CSS_LWC_STRING_INTERN(meta);
CSS_LWC_STRING_INTERN(middle);
CSS_LWC_STRING_INTERN(no);
CSS_LWC_STRING_INTERN(noscript);
CSS_LWC_STRING_INTERN(object);
CSS_LWC_STRING_INTERN(optgroup);
CSS_LWC_STRING_INTERN(option);
CSS_LWC_STRING_INTERN(p);
CSS_LWC_STRING_INTERN(param);
CSS_LWC_STRING_INTERN(password);
CSS_LWC_STRING_INTERN(poly);
CSS_LWC_STRING_INTERN(polygon);
CSS_LWC_STRING_INTERN(post);
CSS_LWC_STRING_INTERN(radio);
CSS_LWC_STRING_INTERN(rect);
CSS_LWC_STRING_INTERN(rectangle);
CSS_LWC_STRING_INTERN(refresh);
CSS_LWC_STRING_INTERN(reset);
CSS_LWC_STRING_INTERN(right);
CSS_LWC_STRING_INTERN(search);
CSS_LWC_STRING_INTERN(select);
CSS_LWC_STRING_INTERN(src);
CSS_LWC_STRING_INTERN(style);
CSS_LWC_STRING_INTERN(submit);
CSS_LWC_STRING_INTERN(table);
CSS_LWC_STRING_INTERN(tbody);
CSS_LWC_STRING_INTERN(td);
CSS_LWC_STRING_INTERN(text);
CSS_LWC_STRING_INTERN(textarea);
CSS_LWC_STRING_INTERN(texttop);
CSS_LWC_STRING_INTERN(tfoot);
CSS_LWC_STRING_INTERN(th);
CSS_LWC_STRING_INTERN(thead);
CSS_LWC_STRING_INTERN(title);
CSS_LWC_STRING_INTERN(top);
CSS_LWC_STRING_INTERN(tr);
CSS_LWC_STRING_INTERN(ul);
CSS_LWC_STRING_INTERN(url);
CSS_LWC_STRING_INTERN(yes);
CSS_LWC_STRING_INTERN(_blank);
CSS_LWC_STRING_INTERN(_parent);
CSS_LWC_STRING_INTERN(_self);
CSS_LWC_STRING_INTERN(_top);
#undef CSS_LWC_STRING_INTERN
 
 
lerror = lwc_intern_string("multipart/form-data",
SLEN("multipart/form-data"),
&corestring_lwc_multipart_form_data);
if ((lerror != lwc_error_ok) ||
(corestring_lwc_multipart_form_data == NULL)) {
error = NSERROR_NOMEM;
goto error;
}
 
lerror = lwc_intern_string("text/css", SLEN("text/css"),
&corestring_lwc_text_css);
if ((lerror != lwc_error_ok) || (corestring_lwc_text_css == NULL)) {
error = NSERROR_NOMEM;
goto error;
}
 
 
#define CSS_DOM_STRING_INTERN(NAME) \
do { \
exc = dom_string_create_interned( \
(const uint8_t *)#NAME, \
sizeof(#NAME) - 1, \
&corestring_dom_##NAME ); \
if ((exc != DOM_NO_ERR) || \
(corestring_dom_##NAME == NULL)) { \
error = NSERROR_NOMEM; \
goto error; \
} \
} while(0)
 
CSS_DOM_STRING_INTERN(a);
CSS_DOM_STRING_INTERN(abort);
CSS_DOM_STRING_INTERN(afterprint);
CSS_DOM_STRING_INTERN(align);
CSS_DOM_STRING_INTERN(area);
CSS_DOM_STRING_INTERN(async);
CSS_DOM_STRING_INTERN(background);
CSS_DOM_STRING_INTERN(beforeprint);
CSS_DOM_STRING_INTERN(beforeunload);
CSS_DOM_STRING_INTERN(bgcolor);
CSS_DOM_STRING_INTERN(blur);
CSS_DOM_STRING_INTERN(border);
CSS_DOM_STRING_INTERN(bordercolor);
CSS_DOM_STRING_INTERN(cancel);
CSS_DOM_STRING_INTERN(canplay);
CSS_DOM_STRING_INTERN(canplaythrough);
CSS_DOM_STRING_INTERN(cellpadding);
CSS_DOM_STRING_INTERN(cellspacing);
CSS_DOM_STRING_INTERN(change);
CSS_DOM_STRING_INTERN(charset);
CSS_DOM_STRING_INTERN(class);
CSS_DOM_STRING_INTERN(click);
CSS_DOM_STRING_INTERN(close);
CSS_DOM_STRING_INTERN(color);
CSS_DOM_STRING_INTERN(cols);
CSS_DOM_STRING_INTERN(content);
CSS_DOM_STRING_INTERN(contextmenu);
CSS_DOM_STRING_INTERN(coords);
CSS_DOM_STRING_INTERN(cuechange);
CSS_DOM_STRING_INTERN(dblclick);
CSS_DOM_STRING_INTERN(defer);
CSS_DOM_STRING_INTERN(drag);
CSS_DOM_STRING_INTERN(dragend);
CSS_DOM_STRING_INTERN(dragenter);
CSS_DOM_STRING_INTERN(dragleave);
CSS_DOM_STRING_INTERN(dragover);
CSS_DOM_STRING_INTERN(dragstart);
CSS_DOM_STRING_INTERN(drop);
CSS_DOM_STRING_INTERN(durationchange);
CSS_DOM_STRING_INTERN(emptied);
CSS_DOM_STRING_INTERN(ended);
CSS_DOM_STRING_INTERN(error);
CSS_DOM_STRING_INTERN(focus);
CSS_DOM_STRING_INTERN(hashchange);
CSS_DOM_STRING_INTERN(height);
CSS_DOM_STRING_INTERN(href);
CSS_DOM_STRING_INTERN(hreflang);
CSS_DOM_STRING_INTERN(hspace);
/* http-equiv: see below */
CSS_DOM_STRING_INTERN(id);
CSS_DOM_STRING_INTERN(input);
CSS_DOM_STRING_INTERN(invalid);
CSS_DOM_STRING_INTERN(keydown);
CSS_DOM_STRING_INTERN(keypress);
CSS_DOM_STRING_INTERN(keyup);
CSS_DOM_STRING_INTERN(link);
CSS_DOM_STRING_INTERN(load);
CSS_DOM_STRING_INTERN(loadeddata);
CSS_DOM_STRING_INTERN(loadedmetadata);
CSS_DOM_STRING_INTERN(loadstart);
CSS_DOM_STRING_INTERN(map);
CSS_DOM_STRING_INTERN(media);
CSS_DOM_STRING_INTERN(message);
CSS_DOM_STRING_INTERN(mousedown);
CSS_DOM_STRING_INTERN(mousemove);
CSS_DOM_STRING_INTERN(mouseout);
CSS_DOM_STRING_INTERN(mouseover);
CSS_DOM_STRING_INTERN(mouseup);
CSS_DOM_STRING_INTERN(mousewheel);
CSS_DOM_STRING_INTERN(name);
CSS_DOM_STRING_INTERN(nohref);
CSS_DOM_STRING_INTERN(offline);
CSS_DOM_STRING_INTERN(online);
CSS_DOM_STRING_INTERN(pagehide);
CSS_DOM_STRING_INTERN(pageshow);
CSS_DOM_STRING_INTERN(pause);
CSS_DOM_STRING_INTERN(play);
CSS_DOM_STRING_INTERN(playing);
CSS_DOM_STRING_INTERN(popstate);
CSS_DOM_STRING_INTERN(progress);
CSS_DOM_STRING_INTERN(ratechange);
CSS_DOM_STRING_INTERN(readystatechange);
CSS_DOM_STRING_INTERN(rect);
CSS_DOM_STRING_INTERN(rel);
CSS_DOM_STRING_INTERN(reset);
CSS_DOM_STRING_INTERN(resize);
CSS_DOM_STRING_INTERN(rows);
CSS_DOM_STRING_INTERN(scroll);
CSS_DOM_STRING_INTERN(seeked);
CSS_DOM_STRING_INTERN(seeking);
CSS_DOM_STRING_INTERN(select);
CSS_DOM_STRING_INTERN(shape);
CSS_DOM_STRING_INTERN(show);
CSS_DOM_STRING_INTERN(size);
CSS_DOM_STRING_INTERN(sizes);
CSS_DOM_STRING_INTERN(src);
CSS_DOM_STRING_INTERN(stalled);
CSS_DOM_STRING_INTERN(storage);
CSS_DOM_STRING_INTERN(submit);
CSS_DOM_STRING_INTERN(suspend);
CSS_DOM_STRING_INTERN(target);
CSS_DOM_STRING_INTERN(text);
CSS_DOM_STRING_INTERN(timeupdate);
CSS_DOM_STRING_INTERN(type);
CSS_DOM_STRING_INTERN(unload);
CSS_DOM_STRING_INTERN(valign);
CSS_DOM_STRING_INTERN(vlink);
CSS_DOM_STRING_INTERN(volumechange);
CSS_DOM_STRING_INTERN(vspace);
CSS_DOM_STRING_INTERN(waiting);
CSS_DOM_STRING_INTERN(width);
#undef CSS_DOM_STRING_INTERN
 
exc = dom_string_create_interned((const uint8_t *) "text/javascript",
SLEN("text/javascript"),
&corestring_dom_text_javascript);
if ((exc != DOM_NO_ERR) || (corestring_dom_text_javascript == NULL)) {
error = NSERROR_NOMEM;
goto error;
}
 
exc = dom_string_create_interned((const uint8_t *) "http-equiv",
SLEN("http-equiv"),
&corestring_dom_http_equiv);
if ((exc != DOM_NO_ERR) || (corestring_dom_http_equiv == NULL)) {
error = NSERROR_NOMEM;
goto error;
}
 
return NSERROR_OK;
 
error:
corestrings_fini();
 
return error;
}
/programs/network/netsurf/netsurf/utils/corestrings.h
0,0 → 1,237
/*
* Copyright 2012 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Useful interned string pointers (interface).
*/
 
#ifndef NETSURF_UTILS_CORESTRINGS_H_
#define NETSURF_UTILS_CORESTRINGS_H_
 
#include <libwapcaplet/libwapcaplet.h>
#include "utils/errors.h"
 
nserror corestrings_init(void);
void corestrings_fini(void);
 
/* lwc_string strings */
extern lwc_string *corestring_lwc_a;
extern lwc_string *corestring_lwc_abscenter;
extern lwc_string *corestring_lwc_absmiddle;
extern lwc_string *corestring_lwc_align;
extern lwc_string *corestring_lwc_applet;
extern lwc_string *corestring_lwc_base;
extern lwc_string *corestring_lwc_baseline;
extern lwc_string *corestring_lwc_body;
extern lwc_string *corestring_lwc_bottom;
extern lwc_string *corestring_lwc_button;
extern lwc_string *corestring_lwc_caption;
extern lwc_string *corestring_lwc_center;
extern lwc_string *corestring_lwc_checkbox;
extern lwc_string *corestring_lwc_circle;
extern lwc_string *corestring_lwc_col;
extern lwc_string *corestring_lwc_default;
extern lwc_string *corestring_lwc_div;
extern lwc_string *corestring_lwc_embed;
extern lwc_string *corestring_lwc_file;
extern lwc_string *corestring_lwc_font;
extern lwc_string *corestring_lwc_frame;
extern lwc_string *corestring_lwc_frameset;
extern lwc_string *corestring_lwc_h1;
extern lwc_string *corestring_lwc_h2;
extern lwc_string *corestring_lwc_h3;
extern lwc_string *corestring_lwc_h4;
extern lwc_string *corestring_lwc_h5;
extern lwc_string *corestring_lwc_h6;
extern lwc_string *corestring_lwc_head;
extern lwc_string *corestring_lwc_hidden;
extern lwc_string *corestring_lwc_hr;
extern lwc_string *corestring_lwc_html;
extern lwc_string *corestring_lwc_https;
extern lwc_string *corestring_lwc_iframe;
extern lwc_string *corestring_lwc_image;
extern lwc_string *corestring_lwc_img;
extern lwc_string *corestring_lwc_input;
extern lwc_string *corestring_lwc_justify;
extern lwc_string *corestring_lwc_left;
extern lwc_string *corestring_lwc_li;
extern lwc_string *corestring_lwc_link;
extern lwc_string *corestring_lwc_meta;
extern lwc_string *corestring_lwc_middle;
extern lwc_string *corestring_lwc_multipart_form_data;
extern lwc_string *corestring_lwc_no;
extern lwc_string *corestring_lwc_noscript;
extern lwc_string *corestring_lwc_object;
extern lwc_string *corestring_lwc_optgroup;
extern lwc_string *corestring_lwc_option;
extern lwc_string *corestring_lwc_p;
extern lwc_string *corestring_lwc_param;
extern lwc_string *corestring_lwc_password;
extern lwc_string *corestring_lwc_poly;
extern lwc_string *corestring_lwc_polygon;
extern lwc_string *corestring_lwc_post;
extern lwc_string *corestring_lwc_radio;
extern lwc_string *corestring_lwc_rect;
extern lwc_string *corestring_lwc_rectangle;
extern lwc_string *corestring_lwc_refresh;
extern lwc_string *corestring_lwc_reset;
extern lwc_string *corestring_lwc_right;
extern lwc_string *corestring_lwc_search;
extern lwc_string *corestring_lwc_select;
extern lwc_string *corestring_lwc_src;
extern lwc_string *corestring_lwc_style;
extern lwc_string *corestring_lwc_submit;
extern lwc_string *corestring_lwc_table;
extern lwc_string *corestring_lwc_tbody;
extern lwc_string *corestring_lwc_td;
extern lwc_string *corestring_lwc_text;
extern lwc_string *corestring_lwc_textarea;
extern lwc_string *corestring_lwc_texttop;
extern lwc_string *corestring_lwc_text_css;
extern lwc_string *corestring_lwc_tfoot;
extern lwc_string *corestring_lwc_th;
extern lwc_string *corestring_lwc_thead;
extern lwc_string *corestring_lwc_title;
extern lwc_string *corestring_lwc_top;
extern lwc_string *corestring_lwc_tr;
extern lwc_string *corestring_lwc_ul;
extern lwc_string *corestring_lwc_url;
extern lwc_string *corestring_lwc_yes;
extern lwc_string *corestring_lwc__blank;
extern lwc_string *corestring_lwc__parent;
extern lwc_string *corestring_lwc__self;
extern lwc_string *corestring_lwc__top;
 
struct dom_string;
 
/* dom_string strings */
extern struct dom_string *corestring_dom_a;
extern struct dom_string *corestring_dom_abort;
extern struct dom_string *corestring_dom_afterprint;
extern struct dom_string *corestring_dom_align;
extern struct dom_string *corestring_dom_area;
extern struct dom_string *corestring_dom_async;
extern struct dom_string *corestring_dom_background;
extern struct dom_string *corestring_dom_beforeprint;
extern struct dom_string *corestring_dom_beforeunload;
extern struct dom_string *corestring_dom_bgcolor;
extern struct dom_string *corestring_dom_blur;
extern struct dom_string *corestring_dom_border;
extern struct dom_string *corestring_dom_bordercolor;
extern struct dom_string *corestring_dom_cancel;
extern struct dom_string *corestring_dom_canplay;
extern struct dom_string *corestring_dom_canplaythrough;
extern struct dom_string *corestring_dom_cellpadding;
extern struct dom_string *corestring_dom_cellspacing;
extern struct dom_string *corestring_dom_change;
extern struct dom_string *corestring_dom_charset;
extern struct dom_string *corestring_dom_class;
extern struct dom_string *corestring_dom_click;
extern struct dom_string *corestring_dom_close;
extern struct dom_string *corestring_dom_color;
extern struct dom_string *corestring_dom_cols;
extern struct dom_string *corestring_dom_content;
extern struct dom_string *corestring_dom_contextmenu;
extern struct dom_string *corestring_dom_coords;
extern struct dom_string *corestring_dom_cuechange;
extern struct dom_string *corestring_dom_dblclick;
extern struct dom_string *corestring_dom_defer;
extern struct dom_string *corestring_dom_drag;
extern struct dom_string *corestring_dom_dragend;
extern struct dom_string *corestring_dom_dragenter;
extern struct dom_string *corestring_dom_dragleave;
extern struct dom_string *corestring_dom_dragover;
extern struct dom_string *corestring_dom_dragstart;
extern struct dom_string *corestring_dom_drop;
extern struct dom_string *corestring_dom_durationchange;
extern struct dom_string *corestring_dom_emptied;
extern struct dom_string *corestring_dom_ended;
extern struct dom_string *corestring_dom_error;
extern struct dom_string *corestring_dom_focus;
extern struct dom_string *corestring_dom_hashchange;
extern struct dom_string *corestring_dom_height;
extern struct dom_string *corestring_dom_href;
extern struct dom_string *corestring_dom_hreflang;
extern struct dom_string *corestring_dom_hspace;
extern struct dom_string *corestring_dom_http_equiv;
extern struct dom_string *corestring_dom_id;
extern struct dom_string *corestring_dom_input;
extern struct dom_string *corestring_dom_invalid;
extern struct dom_string *corestring_dom_keydown;
extern struct dom_string *corestring_dom_keypress;
extern struct dom_string *corestring_dom_keyup;
extern struct dom_string *corestring_dom_link;
extern struct dom_string *corestring_dom_load;
extern struct dom_string *corestring_dom_loadeddata;
extern struct dom_string *corestring_dom_loadedmetadata;
extern struct dom_string *corestring_dom_loadstart;
extern struct dom_string *corestring_dom_map;
extern struct dom_string *corestring_dom_media;
extern struct dom_string *corestring_dom_message;
extern struct dom_string *corestring_dom_mousedown;
extern struct dom_string *corestring_dom_mousemove;
extern struct dom_string *corestring_dom_mouseout;
extern struct dom_string *corestring_dom_mouseover;
extern struct dom_string *corestring_dom_mouseup;
extern struct dom_string *corestring_dom_mousewheel;
extern struct dom_string *corestring_dom_name;
extern struct dom_string *corestring_dom_nohref;
extern struct dom_string *corestring_dom_offline;
extern struct dom_string *corestring_dom_online;
extern struct dom_string *corestring_dom_pagehide;
extern struct dom_string *corestring_dom_pageshow;
extern struct dom_string *corestring_dom_pause;
extern struct dom_string *corestring_dom_play;
extern struct dom_string *corestring_dom_playing;
extern struct dom_string *corestring_dom_popstate;
extern struct dom_string *corestring_dom_progress;
extern struct dom_string *corestring_dom_ratechange;
extern struct dom_string *corestring_dom_readystatechange;
extern struct dom_string *corestring_dom_rect;
extern struct dom_string *corestring_dom_rel;
extern struct dom_string *corestring_dom_reset;
extern struct dom_string *corestring_dom_resize;
extern struct dom_string *corestring_dom_rows;
extern struct dom_string *corestring_dom_scroll;
extern struct dom_string *corestring_dom_seeked;
extern struct dom_string *corestring_dom_seeking;
extern struct dom_string *corestring_dom_select;
extern struct dom_string *corestring_dom_shape;
extern struct dom_string *corestring_dom_show;
extern struct dom_string *corestring_dom_size;
extern struct dom_string *corestring_dom_sizes;
extern struct dom_string *corestring_dom_src;
extern struct dom_string *corestring_dom_stalled;
extern struct dom_string *corestring_dom_storage;
extern struct dom_string *corestring_dom_submit;
extern struct dom_string *corestring_dom_suspend;
extern struct dom_string *corestring_dom_target;
extern struct dom_string *corestring_dom_text;
extern struct dom_string *corestring_dom_text_javascript;
extern struct dom_string *corestring_dom_timeupdate;
extern struct dom_string *corestring_dom_type;
extern struct dom_string *corestring_dom_unload;
extern struct dom_string *corestring_dom_valign;
extern struct dom_string *corestring_dom_vlink;
extern struct dom_string *corestring_dom_volumechange;
extern struct dom_string *corestring_dom_vspace;
extern struct dom_string *corestring_dom_waiting;
extern struct dom_string *corestring_dom_width;
 
 
#endif
/programs/network/netsurf/netsurf/utils/errors.h
0,0 → 1,72
/*
* Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Error codes
*/
 
#ifndef NETSURF_UTILS_ERRORS_H_
#define NETSURF_UTILS_ERRORS_H_
 
/**
* Enumeration of error codes
*/
typedef enum {
NSERROR_OK, /**< No error */
 
NSERROR_UNKNOWN, /**< Unknown error - DO *NOT* USE */
 
NSERROR_NOMEM, /**< Memory exhaustion */
 
NSERROR_NO_FETCH_HANDLER, /**< No fetch handler for URL scheme */
 
NSERROR_NOT_FOUND, /**< Requested item not found */
 
NSERROR_SAVE_FAILED, /**< Failed to save data */
 
NSERROR_CLONE_FAILED, /**< Failed to clone handle */
 
NSERROR_INIT_FAILED, /**< Initialisation failed */
 
NSERROR_MNG_ERROR, /**< An MNG error occurred */
 
NSERROR_BAD_ENCODING, /**< The character set is unknown */
 
NSERROR_NEED_DATA, /**< More data needed */
 
NSERROR_ENCODING_CHANGE, /**< The character changed */
 
NSERROR_BAD_PARAMETER, /**< Bad Parameter */
 
NSERROR_INVALID, /**< Invalid data */
 
NSERROR_BOX_CONVERT, /**< Box conversion failed */
 
NSERROR_STOPPED, /**< Content conversion stopped */
 
NSERROR_DOM, /**< DOM call returned error */
 
NSERROR_CSS, /**< CSS call returned error */
 
NSERROR_CSS_BASE, /**< CSS base sheet failed */
 
NSERROR_BAD_URL /**< Bad URL */
} nserror;
 
#endif
 
/programs/network/netsurf/netsurf/utils/filename.c
0,0 → 1,522
/*
* Copyright 2006 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Provides a central method of obtaining unique filenames.
*
* A maximum of 2^24 files can be allocated at any point in time.
*/
 
#include <assert.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
 
#include "utils/config.h"
#include "utils/filename.h"
#include "utils/log.h"
#include "utils/utils.h"
 
#define FULL_WORD (unsigned int)0xffffffffu
#define START_PREFIX ('0' + '0' * 10)
 
struct directory {
int numeric_prefix; /** numeric representation of prefix */
char prefix[10]; /** directory prefix, eg '00/11/52/' */
unsigned int low_used; /** first 32 files, 1 bit per file */
unsigned int high_used; /** last 32 files, 1 bit per file */
struct directory *next; /** next directory (sorted by prefix) */
};
 
 
static struct directory *root = NULL;
static char filename_buffer[12];
static char filename_directory[256];
 
static struct directory *filename_create_directory(const char *prefix);
static bool filename_flush_directory(const char *folder, int depth);
static bool filename_delete_recursive(char *folder);
 
/**
* Request a new, unique, filename.
*
* \return a pointer to a shared buffer containing the new filename,
* NULL on failure
*/
const char *filename_request(void)
{
struct directory *dir;
int i = -1;
 
for (dir = root; dir; dir = dir->next) {
if ((dir->low_used & dir->high_used) != FULL_WORD) {
if (dir->low_used != FULL_WORD) {
for (i = 0; (dir->low_used & (1 << i)); i++);
} else {
for (i = 0; (dir->high_used & (1 << i)); i++);
i += 32;
}
break;
}
}
 
if (i == -1) {
/* no available slots - create a new directory */
dir = filename_create_directory(NULL);
if (dir == NULL) {
LOG(("Failed to create a new directory."));
return NULL;
}
i = 63;
}
 
if (i < 32)
dir->low_used |= (1 << i);
else
dir->high_used |= (1 << (i - 32));
 
sprintf(filename_buffer, "%s%.2i", dir->prefix, i);
 
return filename_buffer;
}
 
 
/**
* Claim a specific filename.
*
* \param filename the filename to claim
* \return whether the claim was successful
*/
bool filename_claim(const char *filename)
{
char dir_prefix[9];
int file;
struct directory *dir;
 
/* filename format is always '01/23/45/XX' */
strncpy(dir_prefix, filename, 9);
dir_prefix[8] = '\0';
file = (filename[10] + filename[9] * 10 - START_PREFIX);
 
/* create the directory */
dir = filename_create_directory(dir_prefix);
if (dir == NULL)
return false;
 
/* update the entry */
if (file < 32) {
if (dir->low_used & (1 << file))
return false;
dir->low_used |= (1 << file);
} else {
if (dir->high_used & (1 << (file - 32)))
return false;
dir->high_used |= (1 << (file - 32));
}
 
return true;
}
 
 
/**
* Releases a filename for future use.
*
* \param filename the filename to release
*/
void filename_release(const char *filename)
{
struct directory *dir;
int index, file;
 
/* filename format is always '01/23/45/XX' */
index = ((filename[7] + filename[6] * 10 - START_PREFIX) |
((filename[4] + filename[3] * 10 - START_PREFIX) << 6) |
((filename[1] + filename[0] * 10 - START_PREFIX) << 12));
file = (filename[10] + filename[9] * 10 - START_PREFIX);
 
/* modify the correct directory entry */
for (dir = root; dir; dir = dir->next) {
if (dir->numeric_prefix == index) {
if (file < 32)
dir->low_used &= ~(1 << file);
else
dir->high_used &= ~(1 << (file - 32));
return;
}
}
}
 
 
/**
* Initialise the filename provider.
*/
bool filename_initialise(void)
{
char *directory, *start;
 
directory = strdup(TEMP_FILENAME_PREFIX);
if (directory == NULL)
return false;
 
for (start = directory; *start != '\0'; start++) {
if (*start == '/') {
*start = '\0';
nsmkdir(directory, S_IRWXU);
*start = '/';
}
}
 
LOG(("Temporary directory location: %s", directory));
nsmkdir(directory, S_IRWXU);
 
free(directory);
 
return true;
}
 
 
/**
* Deletes all files in the cache directory that are not accounted for.
*/
void filename_flush(void)
{
while (filename_flush_directory(TEMP_FILENAME_PREFIX, 0));
}
 
 
/**
* Deletes some files in a directory that are not accounted for.
*
* A single call to this function may not delete all the files in
* a directory. It should be called until it returns false.
*
* \param folder the folder to search
* \param depth the folder depth
* \returns whether further calls may be needed
*/
bool filename_flush_directory(const char *folder, int depth)
{
DIR *parent;
struct dirent *entry;
bool changed = false;
bool del;
int number, i;
int prefix = 0;
unsigned int prefix_mask = (0x3f << 12);
char child[256];
const char *prefix_start = NULL;
struct directory *dir = NULL;
 
/* Maximum permissible depth is 3 */
assert(depth <= 3);
 
if (depth > 0) {
/* Not a top-level directory, so determine the prefix
* by removing the last /XX component */
prefix_start = folder + strlen(folder) - depth * 3 + 1;
}
 
/* Calculate the numeric prefix */
for (i = 0; i < depth; i++) {
number = prefix_start[1] + prefix_start[0] * 10 - START_PREFIX;
prefix |= (number << (12 - i * 6));
prefix_mask |= (0x3f << (12 - i * 6));
prefix_start += 3;
}
 
/* If we're flushing a leaf directory, find it in the list */
if (depth == 3) {
for (dir = root; dir; dir = dir->next) {
if (dir->numeric_prefix == prefix)
break;
}
 
if (dir == NULL)
return false;
}
 
parent = opendir(folder);
 
while ((entry = readdir(parent))) {
struct stat statbuf;
 
/* Ignore '.' and '..' */
if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0)
continue;
 
snprintf(child, sizeof(child), "%s/%s", folder, entry->d_name);
child[sizeof(child) - 1] = '\0';
 
if (stat(child, &statbuf) == -1) {
LOG(("Unable to stat %s: %s", child, strerror(errno)));
continue;
}
 
/* first 3 depths are directories only, then files only */
if (depth < 3) {
/* Delete any unexpected files */
del = !S_ISDIR(statbuf.st_mode);
} else {
/* Delete any unexpected directories */
del = S_ISDIR(statbuf.st_mode);
}
 
/* check we are a file numbered '00' -> '63' */
if (del == false && (entry->d_name[0] >= '0') &&
(entry->d_name[0] <= '6') &&
(entry->d_name[1] >= '0') &&
(entry->d_name[1] <= '9') &&
(entry->d_name[2] == '\0')) {
number = atoi(entry->d_name);
 
if (number >= 0 && number <= 63) {
if (depth == 3) {
/* File: delete if not in bitfield */
if (number < 32)
del = !(dir->low_used &
(1 << number));
else
del = !(dir->high_used &
(1 << (number - 32)));
} else {
/* Directory: delete unless in list */
del = true;
 
/* Insert into numeric prefix */
prefix &= ~(0x3f << (12 - depth * 6));
prefix |= (number << (12 - depth * 6));
 
/* Find in dir list */
for (dir = root; dir; dir = dir->next) {
number = dir->numeric_prefix &
prefix_mask;
if (number == prefix) {
/* In list: retain */
del = false;
break;
}
}
}
} else {
/* Unexpected name: delete */
del = true;
}
} else {
/* Unexpected name: delete */
del = true;
}
 
/* continue if this is a file we want to retain */
if (del == false && (!S_ISDIR(statbuf.st_mode)))
continue;
 
/* delete or recurse */
if (del) {
if (S_ISDIR(statbuf.st_mode))
filename_delete_recursive(child);
 
if (remove(child))
LOG(("Failed to remove '%s'", child));
else
changed = true;
} else {
while (filename_flush_directory(child, depth + 1));
}
}
 
closedir(parent);
 
return changed;
}
 
 
/**
* Recursively deletes the contents of a directory
*
* \param directory the directory to delete
* \return true on success, false otherwise
*/
bool filename_delete_recursive(char *folder)
{
DIR *parent;
struct dirent *entry;
char child[256];
struct stat statbuf;
 
parent = opendir(folder);
 
while ((entry = readdir(parent))) {
/* Ignore '.' and '..' */
if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0)
continue;
 
snprintf(child, sizeof(child), "%s/%s", folder, entry->d_name);
child[sizeof(child) - 1] = '\0';
 
if (stat(child, &statbuf) == -1) {
LOG(("Unable to stat %s: %s", child, strerror(errno)));
continue;
}
 
if (S_ISDIR(statbuf.st_mode)) {
if (!filename_delete_recursive(child)) {
closedir(parent);
return false;
}
}
 
if (remove(child)) {
LOG(("Failed to remove '%s'", child));
closedir(parent);
return false;
}
}
 
closedir(parent);
 
return true;
}
 
 
/**
* Creates a new directory.
*
* \param prefix the prefix to use, or NULL to allocate a new one
* \return a new directory structure, or NULL on memory exhaustion or
* creation failure
*
* Empty directories are never deleted, except by an explicit call to
* filename_flush().
*/
static struct directory *filename_create_directory(const char *prefix)
{
char *last_1, *last_2;
int index;
struct directory *old_dir, *new_dir, *prev_dir = NULL;
char dir_prefix[16];
int i;
 
/* get the lowest unique prefix, or use the provided one */
if (prefix == NULL) {
for (index = 0, old_dir = root; old_dir;
index++, old_dir = old_dir->next) {
if (old_dir->numeric_prefix != index)
break;
 
prev_dir = old_dir;
}
 
sprintf(dir_prefix, "%.2i/%.2i/%.2i/",
((index >> 12) & 63),
((index >> 6) & 63),
((index >> 0) & 63));
 
prefix = dir_prefix;
} else {
/* prefix format is always '01/23/45/' */
index = ((prefix[7] + prefix[6] * 10 - START_PREFIX) |
((prefix[4] + prefix[3] * 10 - START_PREFIX) << 6) |
((prefix[1] + prefix[0] * 10 - START_PREFIX) << 12));
 
for (old_dir = root; old_dir; old_dir = old_dir->next) {
if (old_dir->numeric_prefix == index)
return old_dir;
 
else if (old_dir->numeric_prefix > index)
break;
 
prev_dir = old_dir;
}
}
 
/* allocate a new directory */
new_dir = malloc(sizeof(struct directory));
if (new_dir == NULL) {
LOG(("No memory for malloc()"));
return NULL;
}
 
strncpy(new_dir->prefix, prefix, 9);
new_dir->prefix[9] = '\0';
new_dir->low_used = new_dir->high_used = 0;
new_dir->numeric_prefix = index;
 
if (prev_dir == NULL) {
new_dir->next = root;
root = new_dir;
} else {
new_dir->next = prev_dir->next;
prev_dir->next = new_dir;
}
 
/* if the previous directory has the same parent then we can simply
* create the child. */
if (prev_dir && strncmp(prev_dir->prefix, new_dir->prefix, 6) == 0) {
new_dir->prefix[8] = '\0';
sprintf(filename_directory, "%s/%s",
TEMP_FILENAME_PREFIX,
new_dir->prefix);
new_dir->prefix[8] = '/';
 
if (!is_dir(filename_directory)) {
if (!nsmkdir(filename_directory, S_IRWXU))
return new_dir;
 
/* the user has probably deleted the parent directory
* whilst we are running if there is an error, so we
* don't report this yet and try to create the
* structure normally. */
LOG(("Failed to create optimised structure '%s'",
filename_directory));
}
}
 
/* create the directory structure */
sprintf(filename_directory, "%s/", TEMP_FILENAME_PREFIX);
last_1 = filename_directory + SLEN(TEMP_FILENAME_PREFIX) + 1;
last_2 = new_dir->prefix;
 
/* create each subdirectory, up to the maximum depth of 3 */
for (i = 0; i < 3 && *last_2; i++) {
*last_1++ = *last_2++;
while (*last_2 && *last_2 != '/')
*last_1++ = *last_2++;
 
if (*last_2) {
last_1[0] = '\0';
 
if (!is_dir(filename_directory)) {
if (nsmkdir(filename_directory, S_IRWXU)) {
LOG(("Failed to create directory '%s'",
filename_directory));
return NULL;
}
}
}
}
 
return new_dir;
}
/programs/network/netsurf/netsurf/utils/filename.h
0,0 → 1,36
/*
* Copyright 2006 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef _NETSURF_UTILS_FILENAME_H_
#define _NETSURF_UTILS_FILENAME_H_
 
#include <stdbool.h>
 
#ifdef riscos
#define TEMP_FILENAME_PREFIX "<Wimp$ScrapDir>/WWW/NetSurf/Cache"
#else
#define TEMP_FILENAME_PREFIX "/tmp/WWW/NetSurf/Cache"
#endif
 
const char *filename_request(void);
bool filename_claim(const char *filename);
void filename_release(const char *filename);
bool filename_initialise(void);
void filename_flush(void);
 
#endif
/programs/network/netsurf/netsurf/utils/filepath.c
0,0 → 1,323
/*
* Copyright 2010 Vincent Sanders <vince@kyllikki.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Provides utility functions for finding readable files.
*
* These functions are intended to make finding resource files more straightforward.
*/
 
#include <sys/types.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
 
#include "utils/config.h"
#include "utils/filepath.h"
 
/** maximum number of elements in the resource vector */
#define MAX_RESPATH 128
 
/* exported interface documented in filepath.h */
char *filepath_vsfindfile(char *str, const char *format, va_list ap)
{
char *realpathname;
char *pathname;
int len;
 
pathname = malloc(PATH_MAX);
if (pathname == NULL)
return NULL; /* unable to allocate memory */
 
len = vsnprintf(pathname, PATH_MAX, format, ap);
 
if ((len < 0) || (len >= PATH_MAX)) {
/* error or output exceeded PATH_MAX length so
* operation is doomed to fail.
*/
free(pathname);
return NULL;
}
 
realpathname = realpath(pathname, str);
free(pathname);
if (realpathname != NULL) {
/* sucessfully expanded pathname */
if (access(realpathname, R_OK) != 0) {
/* unable to read the file */
return NULL;
}
}
 
return realpathname;
}
 
/* exported interface documented in filepath.h */
char *filepath_sfindfile(char *str, const char *format, ...)
{
va_list ap;
char *ret;
 
va_start(ap, format);
ret = filepath_vsfindfile(str, format, ap);
va_end(ap);
 
return ret;
}
 
/* exported interface documented in filepath.h */
char *filepath_findfile(const char *format, ...)
{
char *str;
char *ret;
va_list ap;
 
str = malloc(PATH_MAX);
if (str == NULL)
return NULL; /* unable to allocate memory */
 
va_start(ap, format);
ret = filepath_vsfindfile(str, format, ap);
va_end(ap);
 
if (ret == NULL)
free(str);
 
return ret;
}
 
/* exported interface documented in filepath.h */
char *filepath_sfind(char **respathv, char *filepath, const char *filename)
{
int respathc = 0;
 
if ((respathv == NULL) || (respathv[0] == NULL) || (filepath == NULL))
return NULL;
 
while (respathv[respathc] != NULL) {
if (filepath_sfindfile(filepath, "%s/%s", respathv[respathc], filename) != NULL) {
return filepath;
}
 
respathc++;
}
 
return NULL;
}
 
/* exported interface documented in filepath.h */
char *filepath_find(char **respathv, const char *filename)
{
char *ret;
char *filepath;
 
if ((respathv == NULL) || (respathv[0] == NULL))
return NULL;
 
filepath = malloc(PATH_MAX);
if (filepath == NULL)
return NULL;
 
ret = filepath_sfind(respathv, filepath, filename);
 
if (ret == NULL)
free(filepath);
 
return ret;
}
 
/* exported interface documented in filepath.h */
char *filepath_sfinddef(char **respathv, char *filepath, const char *filename, const char *def)
{
char t[PATH_MAX];
char *ret;
 
if ((respathv == NULL) || (respathv[0] == NULL) || (filepath == NULL))
return NULL;
 
ret = filepath_sfind(respathv, filepath, filename);
 
if ((ret == NULL) && (def != NULL)) {
/* search failed, return the path specified */
ret = filepath;
if (def[0] == '~') {
snprintf(t, PATH_MAX, "%s/%s/%s", getenv("HOME"), def + 1, filename);
} else {
snprintf(t, PATH_MAX, "%s/%s", def, filename);
}
if (realpath(t, ret) == NULL) {
strcpy(ret, t);
}
 
}
return ret;
}
 
 
/* exported interface documented in filepath.h */
char **
filepath_generate(char * const *pathv, const char * const *langv)
{
char **respath; /* resource paths vector */
int pathc = 0;
int langc = 0;
int respathc = 0;
struct stat dstat;
char tmppath[PATH_MAX];
 
respath = calloc(MAX_RESPATH, sizeof(char *));
 
while (pathv[pathc] != NULL) {
if ((stat(pathv[pathc], &dstat) == 0) &&
S_ISDIR(dstat.st_mode)) {
/* path element exists and is a directory */
langc = 0;
while (langv[langc] != NULL) {
snprintf(tmppath, sizeof tmppath, "%s/%s", pathv[pathc],langv[langc]);
if ((stat(tmppath, &dstat) == 0) &&
S_ISDIR(dstat.st_mode)) {
/* path element exists and is a directory */
respath[respathc++] = strdup(tmppath);
}
langc++;
}
respath[respathc++] = strdup(pathv[pathc]);
}
pathc++;
}
 
return respath;
}
 
/* expand ${} in a string into environment variables */
static char *
expand_path(const char *path, int pathlen)
{
char *exp;
int explen;
int cstart = -1;
int cloop = 0;
char *envv;
int envlen;
int replen; /* length of replacement */
 
exp = malloc(pathlen + 1);
if (exp == NULL)
return NULL;
 
memcpy(exp, path, pathlen);
exp[pathlen] = 0;
 
explen = strlen(exp);
 
while (exp[cloop] != 0) {
if ((exp[cloop] == '$') &&
(exp[cloop + 1] == '{')) {
cstart = cloop;
cloop++;
}
if ((cstart != -1) &&
(exp[cloop] == '}')) {
replen = cloop - cstart;
exp[cloop] = 0;
envv = getenv(exp + cstart + 2);
if (envv == NULL) {
memmove(exp + cstart,
exp + cloop + 1,
explen - cloop);
explen -= replen;
} else {
envlen = strlen(envv);
exp = realloc(exp, explen + envlen - replen);
memmove(exp + cstart + envlen,
exp + cloop + 1,
explen - cloop );
memmove(exp + cstart, envv, envlen);
explen += envlen - replen;
}
cloop -= replen;
cstart = -1;
}
 
cloop++;
}
 
if (explen == 1) {
free(exp);
exp = NULL;
}
 
return exp;
}
 
/* exported interface documented in filepath.h */
char **
filepath_path_to_strvec(const char *path)
{
char **strvec;
int strc = 0;
const char *estart; /* path element start */
const char *eend; /* path element end */
int elen;
 
strvec = calloc(MAX_RESPATH, sizeof(char *));
if (strvec == NULL)
return NULL;
 
estart = eend = path;
 
while (strc < (MAX_RESPATH - 2)) {
while ( (*eend != 0) && (*eend != ':') )
eend++;
elen = eend - estart;
 
if (elen > 1) {
/* more than an empty colon */
strvec[strc] = expand_path(estart, elen);
if (strvec[strc] != NULL) {
/* successfully expanded an element */
strc++;
}
}
 
/* skip colons */
while (*eend == ':')
eend++;
 
/* check for termination */
if (*eend == 0)
break;
estart = eend;
}
return strvec;
}
 
/* exported interface documented in filepath.h */
void filepath_free_strvec(char **pathv)
{
free(pathv[0]);
free(pathv);
}
/programs/network/netsurf/netsurf/utils/filepath.h
0,0 → 1,119
/*
* Copyright 2010 Vincent Sanders <vince@kyllikki.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/**
* \file utils/filepath.h
* \brief Utility routines to obtain paths to file resources.
*/
 
#ifndef _NETSURF_UTILS_FILEPATH_H_
#define _NETSURF_UTILS_FILEPATH_H_
 
#include <stdarg.h>
 
 
/** Create a normalised file name.
*
* If the file described by the format exists and is accessible the
* normalised path is placed in str and a pointer to str returned
* otherwise NULL is returned. The string in str is always modified.
*
* @param str A buffer to contain the normalised file name must be at
* least PATH_MAX bytes long.
* @param format A printf format for the filename.
* @param ap The list of arguments for the format.
* @return A pointer to the expanded filename or NULL if the file is
* not present or accessible.
*/
char *filepath_vsfindfile(char *str, const char *format, va_list ap);
 
 
/** Create a normalised file name.
*
* Similar to vsfindfile but takes variadic (printf like) parameters
*/
char *filepath_sfindfile(char *str, const char *format, ...);
 
 
/** Create a normalised file name.
*
* Similar to sfindfile but allocates its own storage for the
* returned string. The caller must free this sorage.
*/
char *filepath_findfile(const char *format, ...);
 
 
/** Searches an array of resource paths for a file.
*
* Iterates through a vector of resource paths and returns the
* normalised file name of the first acessible file or NULL if no file
* can be found in any of the resource paths.
*
* @param respathv The resource path vector to iterate.
* @param filepath The buffer to place the result in.
* @param filename The filename of the resource to search for.
* @return A pointer to filepath if a target is found or NULL if not.
*/
char *filepath_sfind(char **respathv, char *filepath, const char *filename);
 
 
/** Searches an array of resource paths for a file.
*
* Similar to filepath_sfind except it allocates its own storage for
* the returned string. The caller must free this sorage.
*/
char *filepath_find(char **respathv, const char *filename);
 
 
/** Searches an array of resource paths for a file optionally forcing a default.
*
* Similar to filepath_sfind except if no resource is found the default
* is used as an additional path element to search, if that still
* fails the returned path is set to the concatination of the default
* path and the filename.
*/
char *filepath_sfinddef(char **respathv, char *filepath, const char *filename,
const char *def);
 
 
/** Merge two string vectors into a resource search path vector.
*
* @param pathv A string vector containing path elemets to scan.
* @param langv A string vector containing language names to enumerate.
* @return A pointer to a NULL terminated string vector of valid
* resource directories.
*/
char **filepath_generate(char * const *pathv, const char * const *langv);
 
 
/** Convert a colon separated list of path elements into a string vector.
*
* @param path A colon separated path.
* @return A pointer to a NULL terminated string vector of valid
* resource directories.
*/
char **filepath_path_to_strvec(const char *path);
 
 
/** Free a string vector
*
* Free a string vector allocated by filepath_path_to_strvec
*/
void filepath_free_strvec(char **pathv);
 
#endif /* _NETSURF_UTILS_FILEPATH_H_ */
/programs/network/netsurf/netsurf/utils/git-testament.pl
0,0 → 1,226
#!/usr/bin/perl -w
 
use strict;
 
=head1
 
Generate a testament describing the current Git status. This gets written
out in a C form which can be used to construct the NetSurf Git testament
file for signon notification.
 
If there is no Git in place, the data is invented arbitrarily.
 
=cut
 
$ENV{LC_ALL} = 'C';
 
my $root = shift @ARGV;
my $targetfile = shift @ARGV;
 
my %gitinfo; # The Git information
 
$root .= "/" unless ($root =~ m@/$@);
 
my $git_present = 0;
if ( -d ".git" ) {
$git_present = 1;
}
 
sub compat_tmpnam {
# File::Temp was introduced in Perl 5.6.1
my $have_file_tmp = eval { require File::Temp };
 
if ( ! $have_file_tmp ) {
return "$$.gitt";
} else {
return File::Temp::tmpnam();
}
}
 
sub compat_md5_hex {
# Digest::MD5 was introduced in Perl 5.7.1
my $have_digest_md5 = eval { require Digest::MD5 };
my $have_md5 = eval { require MD5 };
my $data = shift;
 
if ( ! $have_digest_md5 ) {
return MD5->hexhash($data);
} else {
return Digest::MD5->new->add($data)->hexdigest;
}
}
 
sub gather_output {
my $cmd = shift;
my $tmpfile = compat_tmpnam();
local $/ = undef();
system("$cmd > $tmpfile");
open(my $CMDH, "<", $tmpfile);
my $ret = <$CMDH>;
close($CMDH);
unlink($tmpfile);
return $ret;
}
 
if ( $git_present ) {
my @bits = split /\s+/, `git config --get-regexp "^remote.*.url\$"`;
$gitinfo{url} = $bits[1];
chomp $gitinfo{url};
$gitinfo{revision} = `git rev-parse HEAD`;
chomp $gitinfo{revision};
$gitinfo{branch} = `git for-each-ref --format="\%(refname:short)" \$(git symbolic-ref HEAD 2>/dev/null || git show-ref -s HEAD)`;
chomp $gitinfo{branch};
@bits = split /\s+/, `git describe --tags --exact-match HEAD 2>/dev/null`;
$bits[0] = "" unless exists $bits[0];
$gitinfo{tag} = $bits[0];
} else {
$gitinfo{url} = "http://nowhere/tarball/";
$gitinfo{revision} = "unknown";
$gitinfo{branch} = "tarball";
$gitinfo{tag} = "";
}
 
my %gitstatus; # The Git status output
 
if ( $git_present ) {
foreach my $line (split(/\n/, gather_output("git status --porcelain"))) {
chomp $line;
my ($X, $Y, $fp) = ($line =~ /^(.)(.) (.+)$/);
my $fn = $fp;
$fn = ($fp =~ /(.+) ->/) if ($fp =~ / -> /);
next unless (care_about_file($fn));
# Normalise $X and $Y (WT and index) into a simple A/M/D etc
$gitstatus{$fn} = "$X$Y";
}
}
 
my %userinfo; # The information about the current user
 
{
my @pwent = getpwuid($<);
$userinfo{USERNAME} = $pwent[0];
my $gecos = $pwent[6];
$gecos =~ s/,.+//g;
$gecos =~ s/"/'/g;
$gecos =~ s/\\/\\\\/g;
$userinfo{GECOS} = $gecos;
}
 
# The current date, in AmigaOS version friendly format (dd.mm.yyyy)
 
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
my $compiledate = sprintf("%02d.%02d.%d",$mday,$mon+1,$year+1900);
chomp $compiledate;
 
# Spew the testament out
 
my $testament = "";
 
$testament .= "#define USERNAME \"$userinfo{USERNAME}\"\n";
$testament .= "#define GECOS \"$userinfo{GECOS}\"\n";
 
my $qroot = $root;
$qroot =~ s/"/\\"/g;
 
my $hostname = $ENV{HOSTNAME};
 
unless ( defined($hostname) && $hostname ne "") {
# Try hostname command if env-var empty
$hostname = gather_output("hostname");
chomp $hostname;
}
 
$hostname = "unknown-host" unless (defined($hostname) && $hostname ne "");
$hostname =~ s/"/\\"/g;
 
$testament .= "#define WT_ROOT \"$qroot\"\n";
$testament .= "#define WT_HOSTNAME \"$hostname\"\n";
$testament .= "#define WT_COMPILEDATE \"$compiledate\"\n";
 
my $cibuild = $ENV{CI_BUILD};
if (defined ($cibuild) && ($cibuild ne '')) {
$testament .= "#define CI_BUILD \"$cibuild\"\n";
}
 
$testament .= "#define WT_BRANCHPATH \"$gitinfo{branch}\"\n";
 
if ($gitinfo{branch} =~ m@^master$@) {
$testament .= "#define WT_BRANCHISMASTER 1\n";
}
if ($gitinfo{tag} =~ m@.@) {
$testament .= "#define WT_BRANCHISTAG 1\n";
$testament .= "#define WT_TAGIS \"$gitinfo{tag}\"\n";
}
if ($gitinfo{url} =~ m@/tarball/@) {
$testament .= "#define WT_NO_GIT 1\n";
}
$testament .= "#define WT_REVID \"$gitinfo{revision}\"\n";
$testament .= "#define WT_MODIFIED " . scalar(keys %gitstatus) . "\n";
$testament .= "#define WT_MODIFICATIONS {\\\n";
my $doneone = 0;
foreach my $filename (sort keys %gitstatus) {
if ($doneone) {
$testament .= ", \\\n";
}
$testament .= " { \"$filename\", \"$gitstatus{$filename}\" }";
$doneone = 1;
}
$testament .= " \\\n}\n";
 
my $oldcsum = "";
if ( -e $targetfile ) {
open(my $OLDVALUES, "<", $targetfile);
foreach my $line (readline($OLDVALUES)) {
if ($line =~ /MD5:([0-9a-f]+)/) {
$oldcsum = $1;
}
}
close($OLDVALUES);
}
 
my $newcsum = compat_md5_hex($testament);
 
if ($oldcsum ne $newcsum) {
print "TESTMENT: $targetfile\n";
open(my $NEWVALUES, ">", $targetfile) or die "$!";
print $NEWVALUES "/* ", $targetfile,"\n";
print $NEWVALUES <<'EOS';
*
* Revision testament.
*
* *WARNING* this file is automatically generated by git-testament.pl
*
* Copyright 2012 NetSurf Browser Project
*/
 
EOS
 
print $NEWVALUES "#ifndef NETSURF_REVISION_TESTAMENT\n";
print $NEWVALUES "#define NETSURF_REVISION_TESTAMENT \"$newcsum\"\n\n";
print $NEWVALUES "/* Revision testament checksum:\n";
print $NEWVALUES " * MD5:", $newcsum,"\n */\n\n";
print $NEWVALUES "/* Revision testament: */\n";
print $NEWVALUES $testament;
print $NEWVALUES "\n#endif\n";
close($NEWVALUES);
foreach my $unwanted (@ARGV) {
next unless(-e $unwanted);
print "TESTAMENT: Removing $unwanted\n";
system("rm", "-f", "--", $unwanted);
}
} else {
print "TESTMENT: unchanged\n";
}
 
exit 0;
 
sub care_about_file {
my ($fn) = @_;
return 0 if ($fn =~ /\.d$/); # Don't care for extraneous DEP files
return 0 if ($fn =~ /\.a$/); # Don't care for extraneous archive files
return 0 if ($fn =~ /\.md5$/); # Don't care for md5sum files
return 0 if ($fn =~ /\.map$/); # Don't care for map files
return 0 if ($fn =~ /\.gitt$/); # Don't care for testament temp files
return 1;
}
/programs/network/netsurf/netsurf/utils/hashtable.c
0,0 → 1,334
/*
* Copyright 2006 Rob Kendrick <rjek@rjek.com>
* Copyright 2006 Richard Wilson <info@tinct.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Write-Once hash table for string to string mappings */
 
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#ifdef TEST_RIG
#include <assert.h>
#include <stdio.h>
#endif
#include "utils/hashtable.h"
#include "utils/log.h"
 
 
struct hash_entry {
char *pairing; /**< block containing 'key\0value\0' */
unsigned int key_length; /**< length of key */
struct hash_entry *next; /**< next entry */
};
 
struct hash_table {
unsigned int nchains;
struct hash_entry **chain;
};
 
/**
* Hash a string, returning a 32bit value. The hash algorithm used is
* Fowler Noll Vo - a very fast and simple hash, ideal for short strings.
* See http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash for more details.
*
* \param datum The string to hash.
* \param len Pointer to unsigned integer to record datum's length in.
* \return The calculated hash value for the datum.
*/
 
static inline unsigned int hash_string_fnv(const char *datum, unsigned int *len)
{
unsigned int z = 0x811c9dc5;
const char *start = datum;
*len = 0;
 
if (datum == NULL)
return 0;
 
while (*datum) {
z *= 0x01000193;
z ^= *datum++;
}
*len = datum - start;
 
return z;
}
 
 
/**
* Create a new hash table, and return a context for it. The memory consumption
* of a hash table is approximately 8 + (nchains * 12) bytes if it is empty.
*
* \param chains Number of chains/buckets this hash table will have. This
* should be a prime number, and ideally a prime number just
* over a power of two, for best performance and distribution.
* \return struct hash_table containing the context of this hash table or NULL
* if there is insufficent memory to create it and its chains.
*/
 
struct hash_table *hash_create(unsigned int chains)
{
struct hash_table *r = malloc(sizeof(struct hash_table));
 
if (r == NULL) {
LOG(("Not enough memory for hash table."));
return NULL;
}
 
r->nchains = chains;
r->chain = calloc(chains, sizeof(struct hash_entry));
 
if (r->chain == NULL) {
LOG(("Not enough memory for %d hash table chains.", chains));
free(r);
return NULL;
}
 
return r;
}
 
/**
* Destroys a hash table, freeing all memory associated with it.
*
* \param ht Hash table to destroy. After the function returns, this
* will nolonger be valid.
*/
 
void hash_destroy(struct hash_table *ht)
{
unsigned int i;
 
if (ht == NULL)
return;
 
for (i = 0; i < ht->nchains; i++) {
if (ht->chain[i] != NULL) {
struct hash_entry *e = ht->chain[i];
while (e) {
struct hash_entry *n = e->next;
free(e->pairing);
free(e);
e = n;
}
}
}
 
free(ht->chain);
free(ht);
}
 
/**
* Adds a key/value pair to a hash table. If the key you're adding is already
* in the hash table, it does not replace it, but it does take precedent over
* it. The old key/value pair will be inaccessable but still in memory until
* hash_destroy() is called on the hash table.
*
* \param ht The hash table context to add the key/value pair to.
* \param key The key to associate the value with. A copy is made.
* \param value The value to associate the key with. A copy is made.
* \return true if the add succeeded, false otherwise. (Failure most likely
* indicates insufficent memory to make copies of the key and value.
*/
 
bool hash_add(struct hash_table *ht, const char *key, const char *value)
{
unsigned int h, c, v;
struct hash_entry *e;
 
if (ht == NULL || key == NULL || value == NULL)
return false;
 
e = malloc(sizeof(struct hash_entry));
if (e == NULL) {
LOG(("Not enough memory for hash entry."));
return false;
}
 
h = hash_string_fnv(key, &(e->key_length));
c = h % ht->nchains;
 
v = strlen(value) ;
e->pairing = malloc(v + e->key_length + 2);
if (e->pairing == NULL) {
LOG(("Not enough memory for string duplication."));
free(e);
return false;
}
memcpy(e->pairing, key, e->key_length + 1);
memcpy(e->pairing + e->key_length + 1, value, v + 1);
 
e->next = ht->chain[c];
ht->chain[c] = e;
 
return true;
}
 
/**
* Looks up a the value associated with with a key from a specific hash table.
*
* \param ht The hash table context to look up the key in.
* \param key The key to search for.
* \return The value associated with the key, or NULL if it was not found.
*/
 
const char *hash_get(struct hash_table *ht, const char *key)
{
unsigned int h, c, key_length;
struct hash_entry *e;
 
if (ht == NULL || key == NULL)
return NULL;
 
h = hash_string_fnv(key, &key_length);
c = h % ht->nchains;
 
for (e = ht->chain[c]; e; e = e->next)
if ((key_length == e->key_length) &&
(memcmp(key, e->pairing, key_length) == 0))
return e->pairing + key_length + 1;
 
return NULL;
}
 
/**
* Iterate through all available hash keys.
*
* \param ht The hash table context to iterate.
* \param c1 Pointer to first context
* \param c2 Pointer to second context (set to 0 on first call)
* \return The next hash key, or NULL for no more keys
*/
 
const char *hash_iterate(struct hash_table *ht, unsigned int *c1, unsigned int **c2) {
struct hash_entry **he = (struct hash_entry **)c2;
 
if (ht == NULL)
return NULL;
 
if (!*he)
*c1 = -1;
else
*he = (*he)->next;
 
if (*he)
return (*he)->pairing;
 
while (!*he) {
(*c1)++;
if (*c1 >= ht->nchains)
return NULL;
*he = ht->chain[*c1];
}
return (*he)->pairing;
}
 
/* A simple test rig. To compile, use:
* gcc -o hashtest -I../ -DTEST_RIG utils/hashtable.c
*
* If you make changes to this hash table implementation, please rerun this
* test, and if possible, through valgrind to make sure there are no memory
* leaks or invalid memory accesses. If you add new functionality, please
* include a test for it that has good coverage along side the other tests.
*/
 
#ifdef TEST_RIG
 
int main(int argc, char *argv[])
{
struct hash_table *a, *b;
FILE *dict;
char keybuf[BUFSIZ], valbuf[BUFSIZ];
int i;
 
a = hash_create(79);
assert(a != NULL);
 
b = hash_create(103);
assert(b != NULL);
 
hash_add(a, "cow", "moo");
hash_add(b, "moo", "cow");
 
hash_add(a, "pig", "oink");
hash_add(b, "oink", "pig");
 
hash_add(a, "chicken", "cluck");
hash_add(b, "cluck", "chicken");
 
hash_add(a, "dog", "woof");
hash_add(b, "woof", "dog");
 
hash_add(a, "cat", "meow");
hash_add(b, "meow", "cat");
 
#define MATCH(x,y) assert(!strcmp(hash_get(a, x), y)); assert(!strcmp(hash_get(b, y), x))
MATCH("cow", "moo");
MATCH("pig", "oink");
MATCH("chicken", "cluck");
MATCH("dog", "woof");
MATCH("cat", "meow");
 
hash_destroy(a);
hash_destroy(b);
 
/* this test requires /usr/share/dict/words - a large list of English
* words. We load the entire file - odd lines are used as keys, and
* even lines are used as the values for the previous line. we then
* work through it again making sure everything matches.
*
* We do this twice - once in a hash table with many chains, and once
* with a hash table with fewer chains.
*/
 
a = hash_create(1031);
b = hash_create(7919);
 
dict = fopen("/usr/share/dict/words", "r");
if (dict == NULL) {
fprintf(stderr, "Unable to open /usr/share/dict/words - extensive testing skipped.\n");
exit(0);
}
 
while (!feof(dict)) {
fscanf(dict, "%s", keybuf);
fscanf(dict, "%s", valbuf);
hash_add(a, keybuf, valbuf);
hash_add(b, keybuf, valbuf);
}
 
for (i = 0; i < 5; i++) {
fseek(dict, 0, SEEK_SET);
 
while (!feof(dict)) {
fscanf(dict, "%s", keybuf);
fscanf(dict, "%s", valbuf);
assert(strcmp(hash_get(a, keybuf), valbuf) == 0);
assert(strcmp(hash_get(b, keybuf), valbuf) == 0);
}
}
 
hash_destroy(a);
hash_destroy(b);
 
fclose(dict);
 
return 0;
}
 
#endif
/programs/network/netsurf/netsurf/utils/hashtable.h
0,0 → 1,36
/*
* Copyright 2006 Rob Kendrick <rjek@rjek.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Write-Once hash table for string to string mappings */
 
#ifndef _NETSURF_UTILS_HASHTABLE_H_
#define _NETSURF_UTILS_HASHTABLE_H_
 
#include <stdbool.h>
 
struct hash_table;
 
struct hash_table *hash_create(unsigned int chains);
void hash_destroy(struct hash_table *ht);
bool hash_add(struct hash_table *ht, const char *key, const char *value);
const char *hash_get(struct hash_table *ht, const char *key);
const char *hash_iterate(struct hash_table *ht, unsigned int *c1,
unsigned int **c2);
 
#endif
/programs/network/netsurf/netsurf/utils/http/challenge.c
0,0 → 1,140
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdlib.h>
 
#include "utils/http.h"
 
#include "utils/http/challenge_internal.h"
#include "utils/http/generics.h"
#include "utils/http/parameter_internal.h"
#include "utils/http/primitives.h"
 
/**
* Representation of an HTTP challenge
*/
struct http_challenge {
http__item base;
 
lwc_string *scheme; /**< Challenge scheme */
http_parameter *params; /**< Challenge parameters */
};
 
/**
* Destroy an HTTP challenge
*
* \param self Challenge to destroy
*/
static void http_destroy_challenge(http_challenge *self)
{
lwc_string_unref(self->scheme);
http_parameter_list_destroy(self->params);
free(self);
}
 
/**
* Parse an HTTP challenge
*
* \param input Pointer to current input byte. Updated on exit.
* \param challenge Pointer to location to receive challenge
* \return NSERROR_OK on success,
* NSERROR_NOMEM on memory exhaustion,
* NSERROR_NOT_FOUND if no parameter could be parsed
*
* The returned challenge is owned by the caller.
*/
nserror http__parse_challenge(const char **input, http_challenge **challenge)
{
const char *pos = *input;
http_challenge *result;
lwc_string *scheme;
http_parameter *first = NULL;
http_parameter *params = NULL;
nserror error;
 
/* challenge = auth-scheme 1*SP 1#auth-param
* auth-scheme = token
* auth-param = parameter
*/
 
error = http__parse_token(&pos, &scheme);
if (error != NSERROR_OK)
return error;
 
if (*pos != ' ' && *pos != '\t') {
lwc_string_unref(scheme);
return NSERROR_NOT_FOUND;
}
 
http__skip_LWS(&pos);
 
error = http__parse_parameter(&pos, &first);
if (error != NSERROR_OK) {
lwc_string_unref(scheme);
return error;
}
 
http__skip_LWS(&pos);
 
if (*pos == ',') {
error = http__item_list_parse(&pos,
http__parse_parameter, first, &params);
if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) {
lwc_string_unref(scheme);
return error;
}
} else {
params = first;
}
 
result = malloc(sizeof(*result));
if (result == NULL) {
http_parameter_list_destroy(params);
lwc_string_unref(scheme);
return NSERROR_NOMEM;
}
 
HTTP__ITEM_INIT(result, NULL, http_destroy_challenge);
result->scheme = scheme;
result->params = params;
 
*challenge = result;
*input = pos;
 
return NSERROR_OK;
}
 
/* See challenge.h for documentation */
const http_challenge *http_challenge_list_iterate(const http_challenge *cur,
lwc_string **scheme, http_parameter **parameters)
{
if (cur == NULL)
return NULL;
 
*scheme = lwc_string_ref(cur->scheme);
*parameters = cur->params;
 
return (http_challenge *) cur->base.next;
}
 
/* See challenge.h for documentation */
void http_challenge_list_destroy(http_challenge *list)
{
http__item_list_destroy(list);
}
 
/programs/network/netsurf/netsurf/utils/http/challenge.h
0,0 → 1,47
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_UTILS_HTTP_CHALLENGE_H_
#define NETSURF_UTILS_HTTP_CHALLENGE_H_
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/http/parameter.h"
 
typedef struct http_challenge http_challenge;
 
/**
* Iterate over a challenge list
*
* \param cur Pointer to current iteration position, list head to start
* \param scheme Pointer to location to receive challenge scheme
* \param parameters Pointer to location to receive challenge parameters
* \return Pointer to next iteration position, or NULL for end of iteration
*/
const http_challenge *http_challenge_list_iterate(const http_challenge *cur,
lwc_string **scheme, http_parameter **parameters);
 
/**
* Destroy a list of HTTP challenges
*
* \param list List to destroy
*/
void http_challenge_list_destroy(http_challenge *list);
 
#endif
 
/programs/network/netsurf/netsurf/utils/http/challenge_internal.h
0,0 → 1,27
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_UTILS_HTTP_CHALLENGE_INTERNAL_H_
#define NETSURF_UTILS_HTTP_CHALLENGE_INTERNAL_H_
 
#include "utils/errors.h"
#include "utils/http/challenge.h"
 
nserror http__parse_challenge(const char **input, http_challenge **parameter);
 
#endif
/programs/network/netsurf/netsurf/utils/http/content-disposition.c
0,0 → 1,78
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdlib.h>
 
#include "utils/http.h"
 
#include "utils/http/generics.h"
#include "utils/http/parameter_internal.h"
#include "utils/http/primitives.h"
 
/* See content-disposition.h for documentation */
nserror http_parse_content_disposition(const char *header_value,
http_content_disposition **result)
{
const char *pos = header_value;
lwc_string *mtype;
http_parameter *params = NULL;
http_content_disposition *cd;
nserror error;
 
/* disposition-type *( ";" parameter ) */
 
http__skip_LWS(&pos);
 
error = http__parse_token(&pos, &mtype);
if (error != NSERROR_OK)
return error;
 
http__skip_LWS(&pos);
 
if (*pos == ';') {
error = http__item_list_parse(&pos,
http__parse_parameter, NULL, &params);
if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) {
lwc_string_unref(mtype);
return error;
}
}
 
cd = malloc(sizeof(*cd));
if (cd == NULL) {
http_parameter_list_destroy(params);
lwc_string_unref(mtype);
return NSERROR_NOMEM;
}
 
cd->disposition_type = mtype;
cd->parameters = params;
 
*result = cd;
 
return NSERROR_OK;
}
 
/* See content-disposition.h for documentation */
void http_content_disposition_destroy(http_content_disposition *victim)
{
lwc_string_unref(victim->disposition_type);
http_parameter_list_destroy(victim->parameters);
free(victim);
}
 
/programs/network/netsurf/netsurf/utils/http/content-disposition.h
0,0 → 1,49
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_UTILS_HTTP_CONTENT_DISPOSITION_H_
#define NETSURF_UTILS_HTTP_CONTENT_DISPOSITION_H_
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/http/parameter.h"
 
typedef struct http_content_disposition {
lwc_string *disposition_type;
http_parameter *parameters;
} http_content_disposition;
 
/**
* Parse an HTTP Content-Disposition header value
*
* \param header_value Header value to parse
* \param result Pointer to location to receive result
* \return NSERROR_OK on success,
* NSERROR_NOMEM on memory exhaustion
*/
nserror http_parse_content_disposition(const char *header_value,
http_content_disposition **result);
 
/**
* Destroy a content disposition object
*
* \param victim Object to destroy
*/
void http_content_disposition_destroy(http_content_disposition *victim);
 
#endif
/programs/network/netsurf/netsurf/utils/http/content-type.c
0,0 → 1,128
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "utils/http.h"
 
#include "utils/http/generics.h"
#include "utils/http/parameter_internal.h"
#include "utils/http/primitives.h"
 
/* See content-type.h for documentation */
nserror http_parse_content_type(const char *header_value,
http_content_type **result)
{
const char *pos = header_value;
lwc_string *type;
lwc_string *subtype = NULL;
http_parameter *params = NULL;
char *mime;
size_t mime_len;
lwc_string *imime;
http_content_type *ct;
nserror error;
 
/* type "/" subtype *( ";" parameter ) */
 
http__skip_LWS(&pos);
 
error = http__parse_token(&pos, &type);
if (error != NSERROR_OK)
return error;
 
http__skip_LWS(&pos);
 
if (*pos != '/') {
lwc_string_unref(type);
return NSERROR_NOT_FOUND;
}
 
pos++;
 
http__skip_LWS(&pos);
 
error = http__parse_token(&pos, &subtype);
if (error != NSERROR_OK) {
lwc_string_unref(type);
return error;
}
 
http__skip_LWS(&pos);
 
if (*pos == ';') {
error = http__item_list_parse(&pos,
http__parse_parameter, NULL, &params);
if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) {
lwc_string_unref(subtype);
lwc_string_unref(type);
return error;
}
}
 
/* <type> + <subtype> + '/' */
mime_len = lwc_string_length(type) + lwc_string_length(subtype) + 1;
 
mime = malloc(mime_len + 1);
if (mime == NULL) {
http_parameter_list_destroy(params);
lwc_string_unref(subtype);
lwc_string_unref(type);
return NSERROR_NOMEM;
}
 
sprintf(mime, "%.*s/%.*s",
(int) lwc_string_length(type), lwc_string_data(type),
(int) lwc_string_length(subtype), lwc_string_data(subtype));
 
lwc_string_unref(subtype);
lwc_string_unref(type);
 
if (lwc_intern_string(mime, mime_len, &imime) != lwc_error_ok) {
http_parameter_list_destroy(params);
free(mime);
return NSERROR_NOMEM;
}
 
free(mime);
 
ct = malloc(sizeof(*ct));
if (ct == NULL) {
lwc_string_unref(imime);
http_parameter_list_destroy(params);
return NSERROR_NOMEM;
}
 
ct->media_type = imime;
ct->parameters = params;
 
*result = ct;
 
return NSERROR_OK;
}
 
/* See content-type.h for documentation */
void http_content_type_destroy(http_content_type *victim)
{
lwc_string_unref(victim->media_type);
http_parameter_list_destroy(victim->parameters);
free(victim);
}
 
/programs/network/netsurf/netsurf/utils/http/content-type.h
0,0 → 1,49
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_UTILS_HTTP_CONTENT_TYPE_H_
#define NETSURF_UTILS_HTTP_CONTENT_TYPE_H_
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/http/parameter.h"
 
typedef struct http_content_type {
lwc_string *media_type;
http_parameter *parameters;
} http_content_type;
 
/**
* Parse an HTTP Content-Type header value
*
* \param header_value Header value to parse
* \param result Pointer to location to receive result
* \return NSERROR_OK on success,
* NSERROR_NOMEM on memory exhaustion
*/
nserror http_parse_content_type(const char *header_value,
http_content_type **result);
 
/**
* Destroy a content type object
*
* \param victim Object to destroy
*/
void http_content_type_destroy(http_content_type *victim);
 
#endif
/programs/network/netsurf/netsurf/utils/http/generics.c
0,0 → 1,99
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdlib.h>
 
#include "utils/http/generics.h"
#include "utils/http/primitives.h"
 
/**
* Destructor for an item list
*
* \param list List to destroy
*/
void http___item_list_destroy(http__item *list)
{
while (list != NULL) {
http__item *victim = list;
 
list = victim->next;
 
victim->free(victim);
}
}
 
/**
* Parse a list of items
*
* \param input Pointer to current input byte. Updated on exit.
* \param itemparser Pointer to function to parse list items
* \param first Pointer to first item, or NULL.
* \param parameters Pointer to location to receive on-heap parameter list.
* \return NSERROR_OK on success,
* NSERROR_NOMEM on memory exhaustion,
* NSERROR_NOT_FOUND if no items could be parsed
*
* The returned list is owned by the caller
*
* \note Ownership of the \a first item is passed to this function.
*/
nserror http___item_list_parse(const char **input,
http__itemparser itemparser, http__item *first,
http__item **items)
{
const char *pos = *input;
const char separator = *pos;
http__item *item;
http__item *list = first;
nserror error = NSERROR_OK;
 
/* 1*( <separator> <item> ) */
 
while (*pos == separator) {
pos++;
 
http__skip_LWS(&pos);
 
error = itemparser(&pos, &item);
if (error == NSERROR_OK) {
if (list != NULL)
item->next = list;
 
list = item;
 
http__skip_LWS(&pos);
} else if (error != NSERROR_NOT_FOUND) {
/* Permit <separator> LWS <separator> */
break;
}
}
 
if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) {
http__item_list_destroy(list);
} else if (list == NULL) {
error = NSERROR_NOT_FOUND;
} else {
error = NSERROR_OK;
*items = list;
*input = pos;
}
 
return error;
}
 
 
/programs/network/netsurf/netsurf/utils/http/generics.h
0,0 → 1,56
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_UTILS_HTTP_GENERICS_H_
#define NETSURF_UTILS_HTTP_GENERICS_H_
 
#include "utils/errors.h"
 
/**
* Representation of an item
*/
typedef struct http__item {
struct http__item *next; /**< Next item in list, or NULL */
 
void (*free)(struct http__item *self); /**< Item destructor */
} http__item;
 
#define HTTP__ITEM_INIT(item, n, f) \
((http__item *) (item))->next = (http__item *) (n); \
((http__item *) (item))->free = (void (*)(http__item *)) (f)
 
/**
* Type of an item parser
*/
typedef nserror (*http__itemparser)(const char **input, http__item **item);
 
 
void http___item_list_destroy(http__item *list);
#define http__item_list_destroy(l) \
http___item_list_destroy((http__item *) (l))
 
nserror http___item_list_parse(const char **input,
http__itemparser itemparser, http__item *first,
http__item **items);
#define http__item_list_parse(i, p, f, r) \
http___item_list_parse((i), \
(http__itemparser) (p), \
(http__item *) (f), \
(http__item **) (void *) (r))
 
#endif
/programs/network/netsurf/netsurf/utils/http/make.http
0,0 → 1,22
CFLAGS += -O2
NETSURF_FB_FRONTEND := sdl
NETSURF_FB_FONTLIB := internal
 
NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
 
# Default resource install path
NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
 
# Default framebuffer search path
NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
 
# freetype compiled in font serch path
NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
OBJS := challenge.o generics.o primitives.o parameter.o \
content-disposition.o content-type.o www-authenticate.o
 
 
OUTFILE = TEST.o
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include
include $(MENUETDEV)/makefiles/Makefile_for_o_lib
/programs/network/netsurf/netsurf/utils/http/parameter.c
0,0 → 1,153
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdlib.h>
#include <string.h>
 
#include "utils/http.h"
 
#include "utils/http/generics.h"
#include "utils/http/parameter_internal.h"
#include "utils/http/primitives.h"
 
/**
* Representation of an HTTP parameter
*/
struct http_parameter {
http__item base;
 
lwc_string *name; /**< Parameter name */
lwc_string *value; /**< Parameter value */
};
 
/**
* Destructor for an HTTP parameter
*
* \param self Parameter to destroy
*/
static void http_destroy_parameter(http_parameter *self)
{
lwc_string_unref(self->name);
lwc_string_unref(self->value);
free(self);
}
 
/**
* Parse an HTTP parameter
*
* \param input Pointer to current input byte. Updated on exit.
* \param parameter Pointer to location to receive on-heap parameter.
* \return NSERROR_OK on success,
* NSERROR_NOMEM on memory exhaustion,
* NSERROR_NOT_FOUND if no parameter could be parsed
*
* The returned parameter is owned by the caller.
*/
nserror http__parse_parameter(const char **input, http_parameter **parameter)
{
const char *pos = *input;
lwc_string *name;
lwc_string *value;
http_parameter *param;
nserror error;
 
/* token "=" ( token | quoted-string ) */
 
error = http__parse_token(&pos, &name);
if (error != NSERROR_OK)
return error;
 
http__skip_LWS(&pos);
 
if (*pos != '=') {
lwc_string_unref(name);
return NSERROR_NOT_FOUND;
}
 
pos++;
 
http__skip_LWS(&pos);
 
if (*pos == '"')
error = http__parse_quoted_string(&pos, &value);
else
error = http__parse_token(&pos, &value);
 
if (error != NSERROR_OK) {
lwc_string_unref(name);
return error;
}
 
param = malloc(sizeof(*param));
if (param == NULL) {
lwc_string_unref(value);
lwc_string_unref(name);
return NSERROR_NOMEM;
}
 
HTTP__ITEM_INIT(param, NULL, http_destroy_parameter);
param->name = name;
param->value = value;
 
*parameter = param;
*input = pos;
 
return NSERROR_OK;
}
 
/* See parameter.h for documentation */
nserror http_parameter_list_find_item(const http_parameter *list,
lwc_string *name, lwc_string **value)
{
bool match;
 
while (list != NULL) {
if (lwc_string_caseless_isequal(name, list->name,
&match) == lwc_error_ok && match)
break;
 
list = (http_parameter *) list->base.next;
}
 
if (list == NULL)
return NSERROR_NOT_FOUND;
 
*value = lwc_string_ref(list->value);
 
return NSERROR_OK;
}
 
/* See parameter.h for documentation */
const http_parameter *http_parameter_list_iterate(const http_parameter *cur,
lwc_string **name, lwc_string **value)
{
if (cur == NULL)
return NULL;
 
*name = lwc_string_ref(cur->name);
*value = lwc_string_ref(cur->value);
 
return (http_parameter *) cur->base.next;
}
 
/* See parameter.h for documentation */
void http_parameter_list_destroy(http_parameter *list)
{
http__item_list_destroy(list);
}
 
/programs/network/netsurf/netsurf/utils/http/parameter.h
0,0 → 1,59
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_UTILS_HTTP_PARAMETER_H_
#define NETSURF_UTILS_HTTP_PARAMETER_H_
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/errors.h"
 
typedef struct http_parameter http_parameter;
 
/**
* Find a named item in an HTTP parameter list
*
* \param list List to search
* \param name Name of item to search for
* \param value Pointer to location to receive value
* \return NSERROR_OK on success,
* NSERROR_NOT_FOUND if requested item does not exist
*/
nserror http_parameter_list_find_item(const http_parameter *list,
lwc_string *name, lwc_string **value);
 
/**
* Iterate over a parameter list
*
* \param cur Pointer to current iteration position, list head to start
* \param name Pointer to location to receive item name
* \param value Pointer to location to receive item value
* \return Pointer to next iteration position, or NULL for end of iteration
*/
const http_parameter *http_parameter_list_iterate(const http_parameter *cur,
lwc_string **name, lwc_string **value);
 
/**
* Destroy a list of HTTP parameters
*
* \param list List to destroy
*/
void http_parameter_list_destroy(http_parameter *list);
 
#endif
 
/programs/network/netsurf/netsurf/utils/http/parameter_internal.h
0,0 → 1,27
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_UTILS_HTTP_PARAMETER_INTERNAL_H_
#define NETSURF_UTILS_HTTP_PARAMETER_INTERNAL_H_
 
#include "utils/errors.h"
#include "utils/http/parameter.h"
 
nserror http__parse_parameter(const char **input, http_parameter **parameter);
 
#endif
/programs/network/netsurf/netsurf/utils/http/primitives.c
0,0 → 1,146
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
 
#include "utils/http/primitives.h"
 
/**
* Skip past linear whitespace in input
*
* \param input Pointer to current input byte. Updated on exit.
*/
void http__skip_LWS(const char **input)
{
const char *pos = *input;
 
while (*pos == ' ' || *pos == '\t')
pos++;
 
*input = pos;
}
 
/**
* Determine if a character is valid for an HTTP token
*
* \param c Character to consider
* \return True if character is valid, false otherwise
*/
static bool http_is_token_char(uint8_t c)
{
/* [ 32 - 126 ] except ()<>@,;:\"/[]?={} SP HT */
 
if (c <= ' ' || 126 < c)
return false;
 
return (strchr("()<>@,;:\\\"/[]?={}", c) == NULL);
}
 
/**
* Parse an HTTP token
*
* \param input Pointer to current input byte. Updated on exit.
* \param value Pointer to location to receive on-heap token value.
* \return NSERROR_OK on success,
* NSERROR_NOMEM on memory exhaustion,
* NSERROR_NOT_FOUND if no token could be parsed
*
* The returned value is owned by the caller
*/
nserror http__parse_token(const char **input, lwc_string **value)
{
const uint8_t *start = (const uint8_t *) *input;
const uint8_t *end;
lwc_string *token;
 
end = start;
while (http_is_token_char(*end))
end++;
 
if (end == start)
return NSERROR_NOT_FOUND;
 
if (lwc_intern_string((const char *) start,
end - start, &token) != lwc_error_ok)
return NSERROR_NOMEM;
 
*value = token;
*input = (const char *) end;
 
return NSERROR_OK;
}
 
/**
* Parse an HTTP quoted-string
*
* \param input Pointer to current input byte. Updated on exit.
* \param value Pointer to location to receive on-heap string value.
* \return NSERROR_OK on success,
* NSERROR_NOMEM on memory exhaustion,
* NSERROR_NOT_FOUND if no string could be parsed
*
* The returned value is owned by the caller
*/
nserror http__parse_quoted_string(const char **input, lwc_string **value)
{
const uint8_t *start = (const uint8_t *) *input;
const uint8_t *end;
uint8_t c;
lwc_string *string_value;
 
/* <"> *( qdtext | quoted-pair ) <">
* qdtext = any TEXT except <">
* quoted-pair = "\" CHAR
* TEXT = [ HT, CR, LF, 32-126, 128-255 ]
* CHAR = [ 0 - 127 ]
*
* \todo TEXT may contain non 8859-1 chars encoded per RFC 2047
* \todo Support quoted-pairs
*/
 
if (*start != '"')
return NSERROR_NOT_FOUND;
 
end = start = start + 1;
 
c = *end;
while (c == '\t' || c == '\r' || c == '\n' ||
c == ' ' || c == '!' ||
('#' <= c && c <= 126) || c > 127) {
end++;
c = *end;
}
 
if (*end != '"')
return NSERROR_NOT_FOUND;
 
if (lwc_intern_string((const char *) start, end - start,
&string_value) != lwc_error_ok)
return NSERROR_NOMEM;
 
*value = string_value;
 
*input = (const char *) end + 1;
 
return NSERROR_OK;
}
 
 
/programs/network/netsurf/netsurf/utils/http/primitives.h
0,0 → 1,32
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_UTILS_HTTP_PRIMITIVES_H_
#define NETSURF_UTILS_HTTP_PRIMITIVES_H_
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/errors.h"
 
void http__skip_LWS(const char **input);
 
nserror http__parse_token(const char **input, lwc_string **value);
 
nserror http__parse_quoted_string(const char **input, lwc_string **value);
 
#endif
/programs/network/netsurf/netsurf/utils/http/www-authenticate.c
0,0 → 1,75
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdlib.h>
 
#include "utils/http/challenge_internal.h"
#include "utils/http/generics.h"
#include "utils/http/parameter_internal.h"
#include "utils/http/primitives.h"
#include "utils/http/www-authenticate.h"
 
/* See www-authenticate.h for documentation */
nserror http_parse_www_authenticate(const char *header_value,
http_www_authenticate **result)
{
const char *pos = header_value;
http_challenge *first = NULL;
http_challenge *list = NULL;
http_www_authenticate *wa;
nserror error;
 
/* 1#challenge */
 
http__skip_LWS(&pos);
 
error = http__parse_challenge(&pos, &first);
if (error != NSERROR_OK)
return error;
 
http__skip_LWS(&pos);
 
if (*pos == ',') {
error = http__item_list_parse(&pos,
http__parse_challenge, first, &list);
if (error != NSERROR_OK && error != NSERROR_NOT_FOUND)
return error;
} else {
list = first;
}
 
wa = malloc(sizeof(*wa));
if (wa == NULL) {
http_challenge_list_destroy(list);
return NSERROR_NOMEM;
}
 
wa->challenges = list;
 
*result = wa;
 
return NSERROR_OK;
}
 
/* See www-authenticate.h for documentation */
void http_www_authenticate_destroy(http_www_authenticate *victim)
{
http_challenge_list_destroy(victim->challenges);
free(victim);
}
 
/programs/network/netsurf/netsurf/utils/http/www-authenticate.h
0,0 → 1,48
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef NETSURF_UTILS_HTTP_WWW_AUTHENTICATE_H_
#define NETSURF_UTILS_HTTP_WWW_AUTHENTICATE_H_
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/http/challenge.h"
 
typedef struct http_www_authenticate {
http_challenge *challenges;
} http_www_authenticate;
 
/**
* Parse an HTTP WWW-Authenticate header value
*
* \param header_value Header value to parse
* \param result Pointer to location to receive result
* \return NSERROR_OK on success,
* NSERROR_NOMEM on memory exhaustion
*/
nserror http_parse_www_authenticate(const char *header_value,
http_www_authenticate **result);
 
/**
* Destroy a www authenticate object
*
* \param victim Object to destroy
*/
void http_www_authenticate_destroy(http_www_authenticate *victim);
 
#endif
/programs/network/netsurf/netsurf/utils/http.h
0,0 → 1,35
/*
* Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* HTTP header parsing functions
*/
 
#ifndef NETSURF_UTILS_HTTP_H_
#define NETSURF_UTILS_HTTP_H_
 
#include <libwapcaplet/libwapcaplet.h>
 
#include "utils/errors.h"
 
#include "utils/http/content-disposition.h"
#include "utils/http/content-type.h"
#include "utils/http/www-authenticate.h"
 
#endif
 
/programs/network/netsurf/netsurf/utils/libdom.c
0,0 → 1,379
/*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* libdom utilities (implementation).
*/
 
#include <assert.h>
#include <dom/dom.h>
 
#include "utils/config.h"
#include "utils/log.h"
 
#include "utils/libdom.h"
 
/* exported interface documented in libdom.h */
bool libdom_treewalk(dom_node *root,
bool (*callback)(dom_node *node, dom_string *name, void *ctx),
void *ctx)
{
dom_node *node;
bool result = true;
 
node = dom_node_ref(root); /* tree root */
 
while (node != NULL) {
dom_node *next = NULL;
dom_node_type type;
dom_string *name;
dom_exception exc;
 
exc = dom_node_get_first_child(node, &next);
if (exc != DOM_NO_ERR) {
dom_node_unref(node);
break;
}
 
if (next != NULL) { /* 1. children */
dom_node_unref(node);
node = next;
} else {
exc = dom_node_get_next_sibling(node, &next);
if (exc != DOM_NO_ERR) {
dom_node_unref(node);
break;
}
 
if (next != NULL) { /* 2. siblings */
dom_node_unref(node);
node = next;
} else { /* 3. ancestor siblings */
while (node != NULL) {
exc = dom_node_get_next_sibling(node,
&next);
if (exc != DOM_NO_ERR) {
dom_node_unref(node);
node = NULL;
break;
}
 
if (next != NULL) {
dom_node_unref(next);
break;
}
 
exc = dom_node_get_parent_node(node,
&next);
if (exc != DOM_NO_ERR) {
dom_node_unref(node);
node = NULL;
break;
}
 
dom_node_unref(node);
node = next;
}
 
if (node == NULL)
break;
 
exc = dom_node_get_next_sibling(node, &next);
if (exc != DOM_NO_ERR) {
dom_node_unref(node);
break;
}
 
dom_node_unref(node);
node = next;
}
}
 
assert(node != NULL);
 
exc = dom_node_get_node_type(node, &type);
if ((exc != DOM_NO_ERR) || (type != DOM_ELEMENT_NODE))
continue;
 
exc = dom_node_get_node_name(node, &name);
if (exc != DOM_NO_ERR)
continue;
 
result = callback(node, name, ctx);
 
dom_string_unref(name);
 
if (result == false) {
break; /* callback caused early termination */
}
 
}
return result;
}
 
 
/* libdom_treewalk context for libdom_find_element */
struct find_element_ctx {
lwc_string *search;
dom_node *found;
};
 
/* libdom_treewalk callback for libdom_find_element */
static bool libdom_find_element_callback(dom_node *node, dom_string *name,
void *ctx)
{
struct find_element_ctx *data = ctx;
 
if (dom_string_caseless_lwc_isequal(name, data->search)) {
/* Found element */
data->found = node;
return false; /* Discontinue search */
}
 
return true; /* Continue search */
}
 
 
/* exported interface documented in libdom.h */
dom_node *libdom_find_element(dom_node *node, lwc_string *element_name)
{
struct find_element_ctx data;
 
assert(element_name != NULL);
 
if (node == NULL)
return NULL;
 
data.search = element_name;
data.found = NULL;
 
libdom_treewalk(node, libdom_find_element_callback, &data);
 
return data.found;
}
 
 
/* exported interface documented in libdom.h */
dom_node *libdom_find_first_element(dom_node *parent, lwc_string *element_name)
{
dom_node *element;
dom_exception exc;
dom_string *node_name = NULL;
dom_node_type node_type;
dom_node *next_node;
 
exc = dom_node_get_first_child(parent, &element);
if ((exc != DOM_NO_ERR) || (element == NULL)) {
return NULL;
}
 
/* find first node thats a element */
do {
exc = dom_node_get_node_type(element, &node_type);
 
if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
exc = dom_node_get_node_name(element, &node_name);
if ((exc == DOM_NO_ERR) && (node_name != NULL)) {
if (dom_string_caseless_lwc_isequal(node_name,
element_name)) {
dom_string_unref(node_name);
break;
}
dom_string_unref(node_name);
}
}
 
exc = dom_node_get_next_sibling(element, &next_node);
dom_node_unref(element);
if (exc == DOM_NO_ERR) {
element = next_node;
} else {
element = NULL;
}
} while (element != NULL);
 
return element;
}
 
/* exported interface documented in libdom.h */
void libdom_iterate_child_elements(dom_node *parent,
libdom_iterate_cb cb, void *ctx)
{
dom_nodelist *children;
uint32_t index, num_children;
dom_exception error;
 
error = dom_node_get_child_nodes(parent, &children);
if (error != DOM_NO_ERR || children == NULL)
return;
 
error = dom_nodelist_get_length(children, &num_children);
if (error != DOM_NO_ERR) {
dom_nodelist_unref(children);
return;
}
 
for (index = 0; index < num_children; index++) {
dom_node *child;
dom_node_type type;
 
error = dom_nodelist_item(children, index, &child);
if (error != DOM_NO_ERR) {
dom_nodelist_unref(children);
return;
}
 
error = dom_node_get_node_type(child, &type);
if (error == DOM_NO_ERR && type == DOM_ELEMENT_NODE) {
if (cb(child, ctx) == false) {
dom_node_unref(child);
dom_nodelist_unref(children);
return;
}
}
 
dom_node_unref(child);
}
 
dom_nodelist_unref(children);
}
 
/* exported interface documented in libdom.h */
nserror libdom_hubbub_error_to_nserror(dom_hubbub_error error)
{
switch (error) {
 
/* HUBBUB_REPROCESS is not handled here because it can
* never occur outside the hubbub treebuilder
*/
 
case DOM_HUBBUB_OK:
/* parsed ok */
return NSERROR_OK;
 
case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED):
/* hubbub input paused */
return NSERROR_OK;
 
case DOM_HUBBUB_NOMEM:
/* out of memory error from DOM */
return NSERROR_NOMEM;
 
case DOM_HUBBUB_BADPARM:
/* Bad parameter passed to creation */
return NSERROR_BAD_PARAMETER;
 
case DOM_HUBBUB_DOM:
/* DOM call returned error */
return NSERROR_DOM;
 
case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_ENCODINGCHANGE):
/* encoding changed */
return NSERROR_ENCODING_CHANGE;
 
case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_NOMEM):
/* out of memory error from parser */
return NSERROR_NOMEM;
 
case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_BADPARM):
return NSERROR_BAD_PARAMETER;
 
case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_INVALID):
return NSERROR_INVALID;
 
case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_FILENOTFOUND):
return NSERROR_NOT_FOUND;
 
case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_NEEDDATA):
return NSERROR_NEED_DATA;
 
case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_BADENCODING):
return NSERROR_BAD_ENCODING;
 
case (DOM_HUBBUB_HUBBUB_ERR | HUBBUB_UNKNOWN):
/* currently only generated by the libdom hubbub binding */
return NSERROR_DOM;
default:
/* unknown error */
/** @todo better error handling and reporting */
return NSERROR_UNKNOWN;
}
return NSERROR_UNKNOWN;
}
 
 
static void ignore_dom_msg(uint32_t severity, void *ctx, const char *msg, ...)
{
}
 
/* exported interface documented in libdom.h */
nserror libdom_parse_file(const char *filename, const char *encoding, dom_document **doc)
{
dom_hubbub_parser_params parse_params;
dom_hubbub_error error;
dom_hubbub_parser *parser;
dom_document *document;
FILE *fp = NULL;
#define BUF_SIZE 512
uint8_t buf[BUF_SIZE];
 
fp = fopen(filename, "r");
if (fp == NULL) {
return NSERROR_NOT_FOUND;
}
 
parse_params.enc = encoding;
parse_params.fix_enc = false;
parse_params.enable_script = false;
parse_params.msg = ignore_dom_msg;
parse_params.script = NULL;
parse_params.ctx = NULL;
parse_params.daf = NULL;
 
error = dom_hubbub_parser_create(&parse_params, &parser, &document);
if (error != DOM_HUBBUB_OK) {
fclose(fp);
return libdom_hubbub_error_to_nserror(error);
}
 
while (feof(fp) == 0) {
size_t read = fread(buf, sizeof(buf[0]), BUF_SIZE, fp);
 
error = dom_hubbub_parser_parse_chunk(parser, buf, read);
if (error != DOM_HUBBUB_OK) {
dom_node_unref(document);
dom_hubbub_parser_destroy(parser);
fclose(fp);
return NSERROR_DOM;
}
}
 
error = dom_hubbub_parser_completed(parser);
if (error != DOM_HUBBUB_OK) {
dom_node_unref(document);
dom_hubbub_parser_destroy(parser);
fclose(fp);
return libdom_hubbub_error_to_nserror(error);
}
 
dom_hubbub_parser_destroy(parser);
fclose(fp);
 
*doc = document;
return NSERROR_OK;
}
/programs/network/netsurf/netsurf/utils/libdom.h
0,0 → 1,80
/*
* Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
 
/** \file
* libdom utilities (implementation).
*/
 
#ifndef NETSURF_UTILS_LIBDOM_H_
#define NETSURF_UTILS_LIBDOM_H_
 
#include <stdbool.h>
 
#include <dom/dom.h>
 
#include <dom/bindings/hubbub/parser.h>
#include <dom/bindings/hubbub/errors.h>
 
/**
* depth-first walk the dom calling callback for each element
*
* \param root the dom node to use as the root of the tree walk
* \return true if all nodes were examined, false if the callback terminated
* the walk early.
*/
bool libdom_treewalk(dom_node *root,
bool (*callback)(dom_node *node, dom_string *name, void *ctx),
void *ctx);
 
/**
* Search the descendants of a node for an element.
*
* \param node dom_node to search children of, or NULL
* \param element_name name of element to find
* \return first child of node which is an element and matches name, or
* NULL if not found or parameter node is NULL
*/
dom_node *libdom_find_element(dom_node *node, lwc_string *element_name);
 
/**
* Search children of a node for first named element
* \param parent dom_node to search children of, or NULL
* \param element_name name of element to find
* \return first child of node which is an element and matches name, or
* NULL if not found or parameter node is NULL
*/
dom_node *libdom_find_first_element(dom_node *parent, lwc_string *element_name);
 
typedef bool (*libdom_iterate_cb)(dom_node *node, void *ctx);
 
void libdom_iterate_child_elements(dom_node *parent,
libdom_iterate_cb cb, void *ctx);
 
nserror libdom_parse_file(const char *filename, const char *encoding,
dom_document **doc);
 
/**
* Convert libdom hubbub binding errors to nserrors.
*
* \param error The hubbub binding error to convert
* \return The appropriate nserror
*/
nserror libdom_hubbub_error_to_nserror(dom_hubbub_error error);
 
#endif
/programs/network/netsurf/netsurf/utils/locale.c
0,0 → 1,53
/*
* Copyright 2008 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Locale-specific variants of various routines (implementation)
*/
 
#include <ctype.h>
#include <locale.h>
 
#include "utils/locale.h"
 
/* <ctype.h> functions */
#define MAKELSCTYPE(x) int ls_##x(int c) \
{ \
int ret; \
setlocale(LC_ALL, ""); \
ret = x(c); \
setlocale(LC_ALL, "C"); \
return ret; \
}
 
MAKELSCTYPE(isalpha)
MAKELSCTYPE(isalnum)
MAKELSCTYPE(iscntrl)
MAKELSCTYPE(isdigit)
MAKELSCTYPE(isgraph)
MAKELSCTYPE(islower)
MAKELSCTYPE(isprint)
MAKELSCTYPE(ispunct)
MAKELSCTYPE(isspace)
MAKELSCTYPE(isupper)
MAKELSCTYPE(isxdigit)
MAKELSCTYPE(tolower)
MAKELSCTYPE(toupper)
 
#undef MAKELSCTYPE
 
/programs/network/netsurf/netsurf/utils/locale.h
0,0 → 1,42
/*
* Copyright 2008 John-Mark Bell <jmb@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Locale-specific variants of various routines (interface)
*/
 
#ifndef _NETSURF_UTILS_LOCALE_H_
#define _NETSURF_UTILS_LOCALE_H_
 
/* <ctype.h> functions */
int ls_isalpha(int c);
int ls_isalnum(int c);
int ls_iscntrl(int c);
int ls_isdigit(int c);
int ls_isgraph(int c);
int ls_islower(int c);
int ls_isprint(int c);
int ls_ispunct(int c);
int ls_isspace(int c);
int ls_isupper(int c);
int ls_isxdigit(int c);
int ls_tolower(int c);
int ls_toupper(int c);
 
#endif
 
/programs/network/netsurf/netsurf/utils/log.c
0,0 → 1,122
/*
* Copyright 2007 Rob Kendrick <rjek@netsurf-browser.org>
* Copyright 2004-2007 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2004 John Tytgat <joty@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdarg.h>
#include <stdio.h>
#include <sys/time.h>
#include "desktop/netsurf.h"
 
#include "utils/log.h"
 
nserror nslog_init(nslog_ensure_t *ensure, int *pargc, char **argv)
{
nserror ret = NSERROR_OK;
 
if (((*pargc) > 1) &&
(argv[1][0] == '-') &&
(argv[1][1] == 'v') &&
(argv[1][2] == 0)) {
int argcmv;
for (argcmv = 2; argcmv < (*pargc); argcmv++) {
argv[argcmv - 1] = argv[argcmv];
}
(*pargc)--;
 
/* ensure we actually show logging */
verbose_log = true;
/* ensure stderr is available */
if (ensure != NULL) {
if (ensure(stderr) == false) {
/* failed to ensure output */
ret = NSERROR_INIT_FAILED;
}
}
}
return ret;
}
 
#ifndef NDEBUG
 
/* Subtract the `struct timeval' values X and Y,
storing the result in RESULT.
Return 1 if the difference is negative, otherwise 0.
*/
 
static int
timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
{
/* Perform the carry for the later subtraction by updating y. */
if (x->tv_usec < y->tv_usec) {
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
y->tv_usec -= 1000000 * nsec;
y->tv_sec += nsec;
}
if (x->tv_usec - y->tv_usec > 1000000) {
int nsec = (x->tv_usec - y->tv_usec) / 1000000;
y->tv_usec += 1000000 * nsec;
y->tv_sec -= nsec;
}
 
/* Compute the time remaining to wait.
tv_usec is certainly positive. */
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_usec = x->tv_usec - y->tv_usec;
 
/* Return 1 if result is negative. */
return x->tv_sec < y->tv_sec;
}
 
const char *nslog_gettime(void)
{
static struct timeval start_tv;
static char buff[32];
 
struct timeval tv;
struct timeval now_tv;
 
if (!timerisset(&start_tv)) {
gettimeofday(&start_tv, NULL);
}
gettimeofday(&now_tv, NULL);
 
timeval_subtract(&tv, &now_tv, &start_tv);
 
snprintf(buff, sizeof(buff),"(%ld.%06ld)",
(long)tv.tv_sec, (long)tv.tv_usec);
 
return buff;
}
 
void nslog_log(const char *format, ...)
{
va_list ap;
 
va_start(ap, format);
 
vfprintf(stderr, format, ap);
 
va_end(ap);
}
 
#endif
 
/programs/network/netsurf/netsurf/utils/log.h
0,0 → 1,78
/*
* Copyright 2003 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004 John Tytgat <joty@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef _NETSURF_LOG_H_
#define _NETSURF_LOG_H_
 
#include <stdio.h>
#include "desktop/netsurf.h"
#include "utils/errors.h"
 
/**
* Ensures the FILE handle is available to write logging to.
*
* This is provided by the frontends if required
*/
typedef bool(nslog_ensure_t)(FILE *fptr);
 
/**
* Initialise the logging system.
*
* Sets up everything required for logging. Processes the argv passed
* to remove the -v switch for verbose logging. If necessary ensures
* the output file handle is available.
*/
extern nserror nslog_init(nslog_ensure_t *ensure, int *pargc, char **argv);
 
#ifdef NDEBUG
# define LOG(x) ((void) 0)
#else
 
/**
* Obtain a formatted string suitable for prepending to a log message
*
* \return formatted string of the time since first log call
*/
extern const char *nslog_gettime(void);
extern void nslog_log(const char *format, ...);
 
# ifdef __GNUC__
# define LOG_FN __PRETTY_FUNCTION__
# define LOG_LN __LINE__
# elif defined(__CC_NORCROFT)
# define LOG_FN __func__
# define LOG_LN __LINE__
# else
# define LOG_FN ""
# define LOG_LN __LINE__
# endif
 
#define LOG(x) \
do { \
if (verbose_log) { \
nslog_log("%s " __FILE__ " %s %i: ", \
nslog_gettime(), LOG_FN, LOG_LN); \
nslog_log x; \
nslog_log("\n"); \
} \
} while(0)
 
#endif
 
#endif
/programs/network/netsurf/netsurf/utils/make.utils
0,0 → 1,23
CFLAGS += -O2
NETSURF_FB_FRONTEND := sdl
NETSURF_FB_FONTLIB := internal
 
NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
 
# Default resource install path
NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
 
# Default framebuffer search path
NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
 
# freetype compiled in font serch path
NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
OBJS := base64.o corestrings.o filename.o filepath.o hashtable.o \
libdom.o locale.o log.o messages.o nsurl.o talloc.o url.o \
utf8.o utils.o useragent.o
 
 
OUTFILE = TEST.o
CFLAGS += -I ../include/ -I ../ -I../../ -I./ -I/home/sourcerer/kos_src/newenginek/kolibri/include
include $(MENUETDEV)/makefiles/Makefile_for_o_lib
/programs/network/netsurf/netsurf/utils/memanalyze.pl
0,0 → 1,380
#!/usr/bin/env perl
#
# Example input:
#
# MEM mprintf.c:1094 malloc(32) = e5718
# MEM mprintf.c:1103 realloc(e5718, 64) = e6118
# MEM sendf.c:232 free(f6520)
 
my $mallocs=0;
my $callocs=0;
my $reallocs=0;
my $strdups=0;
my $showlimit;
 
while(1) {
if($ARGV[0] eq "-v") {
$verbose=1;
shift @ARGV;
}
elsif($ARGV[0] eq "-t") {
$trace=1;
shift @ARGV;
}
elsif($ARGV[0] eq "-l") {
# only show what alloc that caused a memlimit failure
$showlimit=1;
shift @ARGV;
}
else {
last;
}
}
 
my $maxmem;
 
sub newtotal {
my ($newtot)=@_;
# count a max here
 
if($newtot > $maxmem) {
$maxmem= $newtot;
}
}
 
my $file = $ARGV[0];
 
if(! -f $file) {
print "Usage: memanalyze.pl [options] <dump file>\n",
"Options:\n",
" -l memlimit failure displayed\n",
" -v Verbose\n",
" -t Trace\n";
exit;
}
 
open(FILE, "<$file");
 
if($showlimit) {
while(<FILE>) {
if(/^LIMIT.*memlimit$/) {
print $_;
last;
}
}
close(FILE);
exit;
}
 
 
 
while(<FILE>) {
chomp $_;
$line = $_;
 
if($line =~ /^LIMIT ([^ ]*):(\d*) (.*)/) {
# new memory limit test prefix
my $i = $3;
my ($source, $linenum) = ($1, $2);
if($trace && ($i =~ /([^ ]*) reached memlimit/)) {
print "LIMIT: $1 returned error at $source:$linenum\n";
}
}
elsif($line =~ /^MEM ([^ ]*):(\d*) (.*)/) {
# generic match for the filename+linenumber
$source = $1;
$linenum = $2;
$function = $3;
 
if($function =~ /free\(0x([0-9a-f]*)/) {
$addr = $1;
if(!exists $sizeataddr{$addr}) {
print "FREE ERROR: No memory allocated: $line\n";
}
elsif(-1 == $sizeataddr{$addr}) {
print "FREE ERROR: Memory freed twice: $line\n";
print "FREE ERROR: Previously freed at: ".$getmem{$addr}."\n";
}
else {
$totalmem -= $sizeataddr{$addr};
if($trace) {
print "FREE: malloc at ".$getmem{$addr}." is freed again at $source:$linenum\n";
printf("FREE: %d bytes freed, left allocated: $totalmem bytes\n", $sizeataddr{$addr});
}
 
newtotal($totalmem);
$frees++;
 
$sizeataddr{$addr}=-1; # set -1 to mark as freed
$getmem{$addr}="$source:$linenum";
 
}
}
elsif($function =~ /malloc\((\d*)\) = 0x([0-9a-f]*)/) {
$size = $1;
$addr = $2;
 
if($sizeataddr{$addr}>0) {
# this means weeeeeirdo
print "Mixed debug compile, rebuild curl now\n";
}
 
$sizeataddr{$addr}=$size;
$totalmem += $size;
 
if($trace) {
print "MALLOC: malloc($size) at $source:$linenum",
" makes totally $totalmem bytes\n";
}
 
newtotal($totalmem);
$mallocs++;
 
$getmem{$addr}="$source:$linenum";
}
elsif($function =~ /calloc\((\d*),(\d*)\) = 0x([0-9a-f]*)/) {
$size = $1*$2;
$addr = $3;
 
$arg1 = $1;
$arg2 = $2;
 
if($sizeataddr{$addr}>0) {
# this means weeeeeirdo
print "Mixed debug compile, rebuild curl now\n";
}
 
$sizeataddr{$addr}=$size;
$totalmem += $size;
 
if($trace) {
print "CALLOC: calloc($arg1,$arg2) at $source:$linenum",
" makes totally $totalmem bytes\n";
}
 
newtotal($totalmem);
$callocs++;
 
$getmem{$addr}="$source:$linenum";
}
elsif($function =~ /realloc\(0x([0-9a-f]*), (\d*)\) = 0x([0-9a-f]*)/) {
$oldaddr = $1;
$newsize = $2;
$newaddr = $3;
 
$totalmem -= $sizeataddr{$oldaddr};
if($trace) {
printf("REALLOC: %d less bytes and ", $sizeataddr{$oldaddr});
}
$sizeataddr{$oldaddr}=0;
 
$totalmem += $newsize;
$sizeataddr{$newaddr}=$newsize;
 
if($trace) {
printf("%d more bytes ($source:$linenum)\n", $newsize);
}
 
newtotal($totalmem);
$reallocs++;
 
$getmem{$oldaddr}="";
$getmem{$newaddr}="$source:$linenum";
}
elsif($function =~ /strdup\(0x([0-9a-f]*)\) \((\d*)\) = 0x([0-9a-f]*)/) {
# strdup(a5b50) (8) = df7c0
 
$dup = $1;
$size = $2;
$addr = $3;
$getmem{$addr}="$source:$linenum";
$sizeataddr{$addr}=$size;
 
$totalmem += $size;
 
if($trace) {
printf("STRDUP: $size bytes at %s, makes totally: %d bytes\n",
$getmem{$addr}, $totalmem);
}
 
newtotal($totalmem);
$strdups++;
}
elsif($function =~ /strndup\(0x([0-9a-f]*), (\d*)\) \((\d*)\) = 0x([0-9a-f]*)/) {
# strndup(a5b50, 20) (8) = df7c0
 
$dup = $1;
$limit = $2;
$size = $3;
$addr = $4;
$getmem{$addr}="$source:$linenum";
$sizeataddr{$addr}=$size;
 
$totalmem += $size;
 
if($trace) {
printf("STRDUP: $size bytes at %s, makes totally: %d bytes\n",
$getmem{$addr}, $totalmem);
}
 
newtotal($totalmem);
$strdups++;
}
else {
print "Not recognized input line: $function\n";
}
}
# FD url.c:1282 socket() = 5
elsif($_ =~ /^FD ([^ ]*):(\d*) (.*)/) {
# generic match for the filename+linenumber
$source = $1;
$linenum = $2;
$function = $3;
 
if($function =~ /socket\(\) = (\d*)/) {
$filedes{$1}=1;
$getfile{$1}="$source:$linenum";
$openfile++;
}
elsif($function =~ /accept\(\) = (\d*)/) {
$filedes{$1}=1;
$getfile{$1}="$source:$linenum";
$openfile++;
}
elsif($function =~ /sclose\((\d*)\)/) {
if($filedes{$1} != 1) {
print "Close without open: $line\n";
}
else {
$filedes{$1}=0; # closed now
$openfile--;
}
}
}
# FILE url.c:1282 fopen("blabla") = 0x5ddd
elsif($_ =~ /^FILE ([^ ]*):(\d*) (.*)/) {
# generic match for the filename+linenumber
$source = $1;
$linenum = $2;
$function = $3;
 
if($function =~ /fopen\(\"([^\"]*)\",\"([^\"]*)\"\) = (\(nil\)|0x([0-9a-f]*))/) {
if($3 eq "(nil)") {
;
}
else {
$fopen{$4}=1;
$fopenfile{$4}="$source:$linenum";
$fopens++;
}
}
# fclose(0x1026c8)
elsif($function =~ /fclose\(0x([0-9a-f]*)\)/) {
if(!$fopen{$1}) {
print "fclose() without fopen(): $line\n";
}
else {
$fopen{$1}=0;
$fopens--;
}
}
}
# GETNAME url.c:1901 getnameinfo()
elsif($_ =~ /^GETNAME ([^ ]*):(\d*) (.*)/) {
# not much to do
}
 
# ADDR url.c:1282 getaddrinfo() = 0x5ddd
elsif($_ =~ /^ADDR ([^ ]*):(\d*) (.*)/) {
# generic match for the filename+linenumber
$source = $1;
$linenum = $2;
$function = $3;
 
if($function =~ /getaddrinfo\(\) = (\(nil\)|0x([0-9a-f]*))/) {
my $add = $2;
if($add eq "(nil)") {
;
}
else {
$addrinfo{$add}=1;
$addrinfofile{$add}="$source:$linenum";
$addrinfos++;
}
}
# fclose(0x1026c8)
elsif($function =~ /freeaddrinfo\(0x([0-9a-f]*)\)/) {
if(!$addrinfo{$1}) {
print "freeaddrinfo() without getaddrinfo(): $line\n";
}
else {
$addrinfo{$1}=0;
$addrinfos--;
}
}
 
 
}
else {
print "Not recognized prefix line: $line\n";
}
}
close(FILE);
 
if($totalmem) {
print "Leak detected: memory still allocated: $totalmem bytes\n";
 
for(keys %sizeataddr) {
$addr = $_;
$size = $sizeataddr{$addr};
if($size > 0) {
print "At $addr, there's $size bytes.\t";
print " allocated by ".$getmem{$addr}."\n";
$allocs{$getmem{$addr}}++;
$amount{$getmem{$addr}} += $size;
}
}
 
print "Summary by location of allocation:\n";
print "Allocs\tBytes\tLocation\n";
for (sort { $amount{$b} <=> $amount{$a} } keys %allocs) {
print "$allocs{$_}\t$amount{$_}\t$_\n";
}
}
 
if($openfile) {
for(keys %filedes) {
if($filedes{$_} == 1) {
print "Open file descriptor created at ".$getfile{$_}."\n";
}
}
}
 
if($fopens) {
print "Open FILE handles left at:\n";
for(keys %fopen) {
if($fopen{$_} == 1) {
print "fopen() called at ".$fopenfile{$_}."\n";
}
}
}
 
if($addrinfos) {
print "IPv6-style name resolve data left at:\n";
for(keys %addrinfofile) {
if($addrinfo{$_} == 1) {
print "getaddrinfo() called at ".$addrinfofile{$_}."\n";
}
}
}
 
if($verbose) {
print "Mallocs: $mallocs\n",
"Reallocs: $reallocs\n",
"Callocs: $callocs\n",
"Strdups: $strdups\n",
"Frees: $frees\n",
"Allocations: ".($mallocs + $callocs + $reallocs + $strdups)."\n";
 
print "Maximum allocated: $maxmem\n";
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/utils/memdebug.c
0,0 → 1,381
/** \file
* Heap debugging functions (implementation).
*
* Based on memdebug.c from curl (see below), with the following modifications:
*
* - renamed functions from curl_ to memdebug_
* - added memdebug_strndup
* - added guard bytes before and after each block to help detect overflows
* - if a guard byte is corrupted during free, dumps the DA to file
*/
 
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id: memdebug.c,v 1.1 2004/07/28 22:35:02 bursa Exp $
***************************************************************************/
 
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#ifdef riscos
#include <unixlib/local.h>
 
#include "oslib/os.h"
#include "oslib/osfile.h"
#endif
 
#include "memdebug.h"
 
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 
#define MAGIC 0x34343434
#define GUARD 0x34
 
#if defined(riscos) && !defined(__ELF__)
extern int __dynamic_num;
#endif
 
struct memdebug {
size_t size;
unsigned int magic;
double mem[1];
/* I'm hoping this is the thing with the strictest alignment
* requirements. That also means we waste some space :-( */
};
 
/*
* Note that these debug functions are very simple and they are meant to
* remain so. For advanced analysis, record a log file and write perl scripts
* to analyze them!
*
* Don't use these with multithreaded test programs!
*/
 
#define logfile memdebug_debuglogfile
FILE *memdebug_debuglogfile;
static bool memlimit; /* enable memory limit */
static long memsize; /* set number of mallocs allowed */
 
/* this sets the log file name */
void memdebug_memdebug(const char *logname)
{
if(logname)
logfile = fopen(logname, "w");
else
logfile = stderr;
}
 
/* This function sets the number of malloc() calls that should return
successfully! */
void memdebug_memlimit(long limit)
{
memlimit = true;
memsize = limit;
}
 
/* returns true if this isn't allowed! */
static bool countcheck(const char *func, int line, const char *source)
{
/* if source is NULL, then the call is made internally and this check
should not be made */
if(memlimit && source) {
if(!memsize) {
if(logfile && source)
fprintf(logfile, "LIMIT %s:%d %s reached memlimit\n",
source, line, func);
if(source)
fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
source, line, func);
return true; /* RETURN ERROR! */
}
else
memsize--; /* countdown */
 
/* log the countdown */
if(logfile && source)
fprintf(logfile, "LIMIT %s:%d %ld ALLOCS left\n",
source, line, memsize);
 
}
 
return false; /* allow this */
}
 
void *memdebug_malloc(size_t wantedsize, int line, const char *source)
{
struct memdebug *mem;
size_t size;
 
if(countcheck("malloc", line, source))
return NULL;
 
/* alloc at least 64 bytes */
size = sizeof(struct memdebug)+wantedsize + 8;
 
mem=(struct memdebug *)(malloc)(size);
if(mem) {
unsigned int i;
/* fill memory with junk */
memset(mem->mem, 0xA5, wantedsize);
mem->size = wantedsize;
mem->magic = MAGIC;
for (i = 0; i != 8; i++)
((char *) mem->mem)[wantedsize + i] = GUARD;
}
 
if(logfile && source)
fprintf(logfile, "MEM %s:%d malloc(%zu) = %p\n",
source, line, wantedsize, mem ? mem->mem : 0);
return (mem ? mem->mem : NULL);
}
 
void *memdebug_calloc(size_t wanted_elements, size_t wanted_size,
int line, const char *source)
{
struct memdebug *mem;
size_t size, user_size;
 
if(countcheck("calloc", line, source))
return NULL;
 
/* alloc at least 64 bytes */
user_size = wanted_size * wanted_elements;
size = sizeof(struct memdebug) + user_size + 8;
 
mem = (struct memdebug *)(malloc)(size);
if(mem) {
unsigned int i;
/* fill memory with zeroes */
memset(mem->mem, 0, user_size);
mem->size = user_size;
mem->magic = MAGIC;
for (i = 0; i != 8; i++)
((char *) mem->mem)[mem->size + i] = GUARD;
}
 
if(logfile && source)
fprintf(logfile, "MEM %s:%d calloc(%zu,%zu) = %p\n",
source, line, wanted_elements, wanted_size, mem ? mem->mem : 0);
return (mem ? mem->mem : NULL);
}
 
char *memdebug_strdup(const char *str, int line, const char *source)
{
char *mem;
size_t len;
 
assert(str != NULL);
 
if(countcheck("strdup", line, source))
return NULL;
 
len=strlen(str)+1;
 
mem=memdebug_malloc(len, 0, NULL); /* NULL prevents logging */
if (mem)
memcpy(mem, str, len);
 
if(logfile)
fprintf(logfile, "MEM %s:%d strdup(%p) (%zu) = %p\n",
source, line, str, len, mem);
 
return mem;
}
 
char *memdebug_strndup(const char *str, size_t size, int line, const char *source)
{
char *mem;
size_t len;
 
assert(str != NULL);
 
if(countcheck("strndup", line, source))
return NULL;
 
len=strlen(str)+1;
if (size < len - 1)
len = size + 1;
 
mem=memdebug_malloc(len, 0, NULL); /* NULL prevents logging */
if (mem) {
memcpy(mem, str, len);
mem[len - 1] = 0;
}
 
if(logfile)
fprintf(logfile, "MEM %s:%d strndup(%p, %zd) (%zu) = %p\n",
source, line, str, size, len, mem);
 
return mem;
}
 
/* We provide a realloc() that accepts a NULL as pointer, which then
performs a malloc(). In order to work with ares. */
void *memdebug_realloc(void *ptr, size_t wantedsize,
int line, const char *source)
{
unsigned int i;
struct memdebug *mem=NULL;
 
size_t size = sizeof(struct memdebug)+wantedsize+8;
 
if(countcheck("realloc", line, source))
return NULL;
 
if(ptr) {
mem = (struct memdebug *)(void *)
((char *)ptr - offsetof(struct memdebug, mem));
}
 
if(logfile) {
if (mem && mem->magic != MAGIC)
fprintf(logfile, "MAGIC match failed!\n");
for (i = 0; mem && i != 8; i++)
if (((char *) mem->mem)[mem->size + i] != GUARD)
fprintf(logfile, "GUARD %u match failed!\n", i);
fprintf(logfile, "MEM %s:%d realloc(%p, %zu) = ",
source, line, ptr, wantedsize);
fflush(logfile);
}
 
mem=(struct memdebug *)(realloc)(mem, size);
if(logfile)
fprintf(logfile, "%p\n", mem?mem->mem:NULL);
 
if(mem) {
mem->size = wantedsize;
mem->magic = MAGIC;
for (i = 0; i != 8; i++)
((char *) mem->mem)[wantedsize + i] = GUARD;
return mem->mem;
}
 
return NULL;
}
 
void memdebug_free(void *ptr, int line, const char *source)
{
unsigned int i;
struct memdebug *mem;
 
if (!ptr)
return;
 
assert(ptr != NULL);
 
mem = (struct memdebug *)(void *)
((char *)ptr - offsetof(struct memdebug, mem));
if(logfile) {
fprintf(logfile, "MEM %s:%d free(%p)\n", source, line, ptr);
if (mem->magic != MAGIC) {
fprintf(logfile, "MAGIC match failed!\n");
#ifdef riscos
#ifndef __ELF__
if (__dynamic_num != -1) {
int size;
byte *base_address;
xosdynamicarea_read(__dynamic_num, &size, &base_address,
0, 0, 0, 0, 0);
fprintf(logfile, "saving DA %i %p %x\n", __dynamic_num, base_address,
size);
xosfile_save("core", (bits) base_address, 0, base_address,
base_address + size);
}
#else
__unixlib_write_coredump(NULL);
#endif
#endif
}
fflush(logfile);
for (i = 0; i != 8; i++)
if (((char *) mem->mem)[mem->size + i] != GUARD)
fprintf(logfile, "GUARD %u match failed!\n", i);
fflush(logfile);
}
 
/* destroy */
memset(mem->mem, 0x13, mem->size);
mem->magic = 0x13131313;
for (i = 0; i != 8; i++)
((char *) mem->mem)[mem->size + i] = 0x13;
 
/* free for real */
(free)(mem);
}
 
int memdebug_socket(int domain, int type, int protocol, int line,
const char *source)
{
int sockfd=(socket)(domain, type, protocol);
if(logfile && (sockfd!=-1))
fprintf(logfile, "FD %s:%d socket() = %d\n",
source, line, sockfd);
return sockfd;
}
 
int memdebug_accept(int s, void *saddr, void *saddrlen,
int line, const char *source)
{
struct sockaddr *addr = (struct sockaddr *)saddr;
socklen_t *addrlen = (socklen_t *)saddrlen;
int sockfd=(accept)(s, addr, addrlen);
if(logfile)
fprintf(logfile, "FD %s:%d accept() = %d\n",
source, line, sockfd);
return sockfd;
}
 
/* this is our own defined way to close sockets on *ALL* platforms */
int memdebug_sclose(int sockfd, int line, const char *source)
{
int res=sclose(sockfd);
if(logfile)
fprintf(logfile, "FD %s:%d sclose(%d)\n",
source, line, sockfd);
return res;
}
 
FILE *memdebug_fopen(const char *file, const char *mode,
int line, const char *source)
{
FILE *res=(fopen)(file, mode);
if(logfile)
fprintf(logfile, "FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
source, line, file, mode, res);
return res;
}
 
int memdebug_fclose(FILE *file, int line, const char *source)
{
int res;
 
assert(file != NULL);
 
res=(fclose)(file);
if(logfile)
fprintf(logfile, "FILE %s:%d fclose(%p)\n",
source, line, file);
return res;
}
/programs/network/netsurf/netsurf/utils/memdebug.h
0,0 → 1,106
/** \file
* Heap debugging functions (interface).
*
* Based on memdebug.h from curl (see below), with the following modifications:
*
* - renamed functions from curl_ to memdebug_
* - added memdebug_strndup
* - added guard bytes before and after each block to help detect overflows
* - if a guard byte is corrupted during free, dumps the DA to file
*/
 
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id: memdebug.h,v 1.1 2004/07/28 22:35:02 bursa Exp $
***************************************************************************/
 
#ifndef _MEMDEBUG_H_
#define _MEMDEBUG_H_
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
 
#define logfile memdebug_debuglogfile
 
extern FILE *logfile;
 
/* memory functions */
void *memdebug_malloc(size_t size, int line, const char *source);
void *memdebug_calloc(size_t elements, size_t size, int line, const char *source);
void *memdebug_realloc(void *ptr, size_t size, int line, const char *source);
void memdebug_free(void *ptr, int line, const char *source);
char *memdebug_strdup(const char *str, int line, const char *source);
char *memdebug_strndup(const char *str, size_t size, int line, const char *source);
void memdebug_memdebug(const char *logname);
void memdebug_memlimit(long limit);
 
/* file descriptor manipulators */
int memdebug_socket(int domain, int type, int protocol, int line , const char *);
int memdebug_sclose(int sockfd, int, const char *source);
int memdebug_accept(int s, void *addr, void *addrlen,
int line, const char *source);
 
/* FILE functions */
FILE *memdebug_fopen(const char *file, const char *mode, int line,
const char *source);
int memdebug_fclose(FILE *file, int line, const char *source);
 
#ifndef MEMDEBUG_NODEFINES
 
#undef strdup
#define strdup(ptr) memdebug_strdup(ptr, __LINE__, __FILE__)
#define strndup(ptr,size) memdebug_strndup(ptr, size, __LINE__, __FILE__)
#define malloc(size) memdebug_malloc(size, __LINE__, __FILE__)
#define calloc(nbelem,size) memdebug_calloc(nbelem, size, __LINE__, __FILE__)
#define realloc(ptr,size) memdebug_realloc(ptr, size, __LINE__, __FILE__)
#define free(ptr) memdebug_free(ptr, __LINE__, __FILE__)
 
#define socket(domain,type,protocol)\
memdebug_socket(domain,type,protocol,__LINE__,__FILE__)
#undef accept /* for those with accept as a macro */
#define accept(sock,addr,len)\
memdebug_accept(sock,addr,len,__LINE__,__FILE__)
 
#define getaddrinfo(host,serv,hint,res) \
memdebug_getaddrinfo(host,serv,hint,res,__LINE__,__FILE__)
#define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \
memdebug_getnameinfo(sa,salen,host,hostlen,serv,servlen,flags, __LINE__, \
__FILE__)
#define freeaddrinfo(data) \
memdebug_freeaddrinfo(data,__LINE__,__FILE__)
 
/* sclose is probably already defined, redefine it! */
#undef sclose
#define sclose(sockfd) memdebug_sclose(sockfd,__LINE__,__FILE__)
/* ares-adjusted define: */
#undef closesocket
#define closesocket(sockfd) memdebug_sclose(sockfd,__LINE__,__FILE__)
 
#undef fopen
#define fopen(file,mode) memdebug_fopen(file,mode,__LINE__,__FILE__)
#define fclose(file) memdebug_fclose(file,__LINE__,__FILE__)
 
#endif /* MEMDEBUG_NODEFINES */
 
#endif
/programs/network/netsurf/netsurf/utils/merge-messages.lua
0,0 → 1,83
#!/usr/bin/env lua5.1
 
local lfs = require "lfs"
 
local en_stat = assert(lfs.attributes "!NetSurf/Resources/en/Messages")
local language = { }
local sorted = { }
 
io.stderr:write("loading non-en languages...\n");
 
for dir in lfs.dir "!NetSurf/Resources" do
local path = "!NetSurf/Resources/" .. dir
if dir ~= "en" and lfs.attributes(path .. "/Messages") then
local f = io.open(path .. "/Messages", "r")
local c = 0
io.stderr:write(dir, ":")
language[dir] = { }
sorted[#sorted + 1] = dir
for l in f:lines() do
if l:sub(1, 1) ~= "#" then
local tag, msg = l:match "^([^:]*):(.*)$"
if tag then
language[dir][tag] = msg
c = c + 1
end
end
end
f:close()
io.stderr:write(tostring(c), " entries.\n")
end
end
 
table.sort(sorted)
 
io.stderr:write("working through en...\n")
 
local manipulators = {
{ "^(ami.*)", "ami.%1" },
{ "^(gtk.*)", "gtk.%1" },
{ "^(Help.*)", "ro.%1" },
{ "^(ARexx.*)", "ami.%1" },
 
{ "^(.*)$", "all.%1" } -- must be last
}
 
local function manipulate_tag(t)
for _, m in ipairs(manipulators) do
local r, s = t:gsub(m[1], m[2])
if s > 0 then return r end
end
return t
end
 
local f = io.open("!NetSurf/Resources/en/Messages", "r")
 
for l in f:lines() do
if l:sub(1,1) == "#" then
print(l)
else
local tag, msg = l:match "^([^:]*):(.*)$"
if not tag then
print(l)
else
local mtag = manipulate_tag(tag)
io.stdout:write("en.", mtag, ":", msg, "\n")
for _, langname in ipairs(sorted) do
local trans = language[langname][tag]
if not trans then
io.stderr:write("*** language ", langname, " lacks translation for ", mtag, "/", tag, "\n")
trans = msg
end
io.stdout:write(langname, ".", mtag, ":", trans, "\n")
language[langname][tag] = nil
end
end
end
end
 
for _, langname in ipairs(sorted) do
for tag in pairs(language[langname]) do
io.stderr:write("*** language ", langname, " contains orphan tag ", tag, "\n")
end
end
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/utils/messages.c
0,0 → 1,298
/*
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2006 Rob Kendrick <rjek@rjek.com>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Localised message support (implementation).
*
* Native language messages are loaded from a file and stored hashed by key for
* fast access.
*/
 
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <zlib.h>
#include <stdarg.h>
 
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
#include "utils/hashtable.h"
 
/** We store the messages in a fixed-size hash table. */
#define HASH_SIZE 101
 
/** The hash table used to store the standard Messages file for the old API */
static struct hash_table *messages_hash = NULL;
 
/**
* Read keys and values from messages file.
*
* \param path pathname of messages file
* \param ctx struct hash_table to merge with, or NULL for a new one.
* \return struct hash_table containing the context or NULL in case of error.
*/
 
struct hash_table *messages_load_ctx(const char *path, struct hash_table *ctx)
{
char s[400];
gzFile fp;
 
assert(path != NULL);
 
ctx = (ctx != NULL) ? ctx : hash_create(HASH_SIZE);
 
if (ctx == NULL) {
LOG(("Unable to create hash table for messages file %s", path));
return NULL;
}
 
fp = gzopen(path, "r");
if (!fp) {
snprintf(s, sizeof s, "Unable to open messages file "
"\"%.100s\": %s", path, strerror(errno));
s[sizeof s - 1] = 0;
LOG(("%s", s));
hash_destroy(ctx);
return NULL;
}
 
while (gzgets(fp, s, sizeof s)) {
char *colon, *value;
 
if (s[0] == 0 || s[0] == '#')
continue;
 
s[strlen(s) - 1] = 0; /* remove \n at end */
colon = strchr(s, ':');
if (!colon)
continue;
*colon = 0; /* terminate key */
value = colon + 1;
 
if (hash_add(ctx, s, value) == false) {
LOG(("Unable to add %s:%s to hash table of %s",
s, value, path));
gzclose(fp);
hash_destroy(ctx);
return NULL;
}
}
 
gzclose(fp);
 
return ctx;
}
 
/**
* Read keys and values from messages file into the standard Messages hash.
*
* \param path pathname of messages file
*
* The messages are merged with any previously loaded messages. Any keys which
* are present already are replaced with the new value.
*
* Exits through die() in case of error.
*/
 
void messages_load(const char *path)
{
struct hash_table *m;
char s[400];
 
if (path == NULL)
return;
LOG(("Loading Messages from '%s'", path));
m = messages_load_ctx(path, messages_hash);
if (m == NULL) {
LOG(("Unable to open Messages file '%s'. Possible reason: %s",
path, strerror(errno)));
snprintf(s, sizeof s,
"Unable to open Messages file '%s'.", path);
die(s);
}
 
messages_hash = m;
}
 
/**
* Fast lookup of a message by key.
*
* \param key key of message
* \param ctx context of messages file to look up in
* \return value of message, or key if not found
*/
 
const char *messages_get_ctx(const char *key, struct hash_table *ctx)
{
const char *r;
 
assert(key != NULL);
 
/* If we're called with no context, it's nicer to return the
* key rather than explode - this allows attempts to get messages
* before messages_hash is set up to fail gracefully, for example */
if (ctx == NULL)
return key;
 
r = hash_get(ctx, key);
 
return r ? r : key;
}
 
/* exported interface documented in messages.h */
char *messages_get_buff(const char *key, ...)
{
const char *msg_fmt;
char *buff = NULL; /* formatted buffer to return */
int buff_len = 0;
va_list ap;
 
msg_fmt = messages_get_ctx(key, messages_hash);
 
va_start(ap, key);
buff_len = vsnprintf(buff, buff_len, msg_fmt, ap);
va_end(ap);
 
buff = malloc(buff_len + 1);
 
if (buff == NULL) {
LOG(("malloc failed"));
warn_user("NoMemory", 0);
} else {
va_start(ap, key);
vsnprintf(buff, buff_len + 1, msg_fmt, ap);
va_end(ap);
}
 
return buff;
}
 
 
/**
* Fast lookup of a message by key from the standard Messages hash.
*
* \param key key of message
* \return value of message, or key if not found
*/
 
const char *messages_get(const char *key)
{
return messages_get_ctx(key, messages_hash);
}
 
 
/**
* lookup of a message by errorcode from the standard Messages hash.
*
* \param code errorcode of message
* \return message text
*/
 
const char *messages_get_errorcode(nserror code)
{
switch (code) {
case NSERROR_OK:
/**< No error */
return messages_get_ctx("OK", messages_hash);
 
case NSERROR_NOMEM:
/**< Memory exhaustion */
return messages_get_ctx("NoMemory", messages_hash);
 
case NSERROR_NO_FETCH_HANDLER:
/**< No fetch handler for URL scheme */
return messages_get_ctx("NoHandler", messages_hash);
 
case NSERROR_NOT_FOUND:
/**< Requested item not found */
return messages_get_ctx("NotFound", messages_hash);
 
case NSERROR_SAVE_FAILED:
/**< Failed to save data */
return messages_get_ctx("SaveFailed", messages_hash);
 
case NSERROR_CLONE_FAILED:
/**< Failed to clone handle */
return messages_get_ctx("CloneFailed", messages_hash);
 
case NSERROR_INIT_FAILED:
/**< Initialisation failed */
return messages_get_ctx("InitFailed", messages_hash);
 
case NSERROR_MNG_ERROR:
/**< An MNG error occurred */
return messages_get_ctx("MNGError", messages_hash);
 
case NSERROR_BAD_ENCODING:
/**< The character set is unknown */
return messages_get_ctx("BadEncoding", messages_hash);
 
case NSERROR_NEED_DATA:
/**< More data needed */
return messages_get_ctx("NeedData", messages_hash);
 
case NSERROR_ENCODING_CHANGE:
/**< The character set encoding change was unhandled */
return messages_get_ctx("EncodingChanged", messages_hash);
 
case NSERROR_BAD_PARAMETER:
/**< Bad Parameter */
return messages_get_ctx("BadParameter", messages_hash);
 
case NSERROR_INVALID:
/**< Invalid data */
return messages_get_ctx("Invalid", messages_hash);
 
case NSERROR_BOX_CONVERT:
/**< Box conversion failed */
return messages_get_ctx("BoxConvert", messages_hash);
 
case NSERROR_STOPPED:
/**< Content conversion stopped */
return messages_get_ctx("Stopped", messages_hash);
 
case NSERROR_DOM:
/**< DOM call returned error */
return messages_get_ctx("ParsingFail", messages_hash);
 
case NSERROR_CSS:
/**< CSS call returned error */
return messages_get_ctx("CSSGeneric", messages_hash);
 
case NSERROR_CSS_BASE:
/**< CSS base sheet failed */
return messages_get_ctx("CSSBase", messages_hash);
 
case NSERROR_BAD_URL:
/**< Bad URL */
return messages_get_ctx("BadURL", messages_hash);
 
default:
case NSERROR_UNKNOWN:
break;
}
 
/**< Unknown error */
return messages_get_ctx("Unknown", messages_hash);
}
/programs/network/netsurf/netsurf/utils/messages.h
0,0 → 1,64
/*
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Localised message support (interface).
*
* The messages module loads a file of keys and associated strings, and
* provides fast lookup by key. The messages file consists of key:value lines,
* comment lines starting with #, and other lines are ignored. Use
* messages_load() to read the file into memory. To lookup a key, use
* messages_get("key").
*
* It can also load additional messages files into different contexts and allow
* you to look up values in it independantly from the standard shared Messages
* file table. Use the _ctx versions of the functions to do this.
*/
 
#ifndef _NETSURF_UTILS_MESSAGES_H_
#define _NETSURF_UTILS_MESSAGES_H_
 
#include "utils/errors.h"
#include "utils/hashtable.h"
 
void messages_load(const char *path);
struct hash_table *messages_load_ctx(const char *path, struct hash_table *ctx);
const char *messages_get_ctx(const char *key, struct hash_table *ctx);
const char *messages_get(const char *key);
 
/**
* lookup of a message by errorcode from the standard Messages hash.
*
* \param code errorcode of message
* \return message text
*/
const char *messages_get_errorcode(nserror code);
 
/**
* Formatted message from a key in the global message hash.
*
* \param key key of message
* \param ... message parameters
* \return buffer containing formatted message text or NULL if memory
* is unavailable. The caller owns the returned buffer and is
* responsible for freeing it.
*/
 
char *messages_get_buff(const char *key, ...);
 
#endif
/programs/network/netsurf/netsurf/utils/nsurl.c
0,0 → 1,2122
/*
* Copyright 2011 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* NetSurf URL handling (implementation).
*/
 
#include <assert.h>
#include <ctype.h>
#include <libwapcaplet/libwapcaplet.h>
#include <stdlib.h>
#include <string.h>
 
#include "utils/errors.h"
#include "utils/log.h"
#include "utils/nsurl.h"
#include "utils/utils.h"
 
 
/* Define to enable NSURL debugging */
#undef NSURL_DEBUG
 
static bool nsurl__is_unreserved(unsigned char c)
{
/* From RFC3986 section 2.3 (unreserved characters)
*
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
*
*/
static const bool unreserved[256] = {
false, false, false, false, false, false, false, false, /* 00 */
false, false, false, false, false, false, false, false, /* 08 */
false, false, false, false, false, false, false, false, /* 10 */
false, false, false, false, false, false, false, false, /* 18 */
false, false, false, false, false, false, false, false, /* 20 */
false, false, false, false, false, true, true, false, /* 28 */
true, true, true, true, true, true, true, true, /* 30 */
true, true, false, false, false, false, false, false, /* 38 */
false, true, true, true, true, true, true, true, /* 40 */
true, true, true, true, true, true, true, true, /* 48 */
true, true, true, true, true, true, true, true, /* 50 */
true, true, true, false, false, false, false, true, /* 58 */
false, true, true, true, true, true, true, true, /* 60 */
true, true, true, true, true, true, true, true, /* 68 */
true, true, true, true, true, true, true, true, /* 70 */
true, true, true, false, false, false, true, false, /* 78 */
false, false, false, false, false, false, false, false, /* 80 */
false, false, false, false, false, false, false, false, /* 88 */
false, false, false, false, false, false, false, false, /* 90 */
false, false, false, false, false, false, false, false, /* 98 */
false, false, false, false, false, false, false, false, /* A0 */
false, false, false, false, false, false, false, false, /* A8 */
false, false, false, false, false, false, false, false, /* B0 */
false, false, false, false, false, false, false, false, /* B8 */
false, false, false, false, false, false, false, false, /* C0 */
false, false, false, false, false, false, false, false, /* C8 */
false, false, false, false, false, false, false, false, /* D0 */
false, false, false, false, false, false, false, false, /* D8 */
false, false, false, false, false, false, false, false, /* E0 */
false, false, false, false, false, false, false, false, /* E8 */
false, false, false, false, false, false, false, false, /* F0 */
false, false, false, false, false, false, false, false /* F8 */
};
return unreserved[c];
}
 
/* The ASCII codes which should not be percent escaped */
static bool nsurl__is_no_escape(unsigned char c)
{
static const bool no_escape[256] = {
false, false, false, false, false, false, false, false, /* 00 */
false, false, false, false, false, false, false, false, /* 08 */
false, false, false, false, false, false, false, false, /* 10 */
false, false, false, false, false, false, false, false, /* 18 */
false, true, false, true, true, false, true, true, /* 20 */
true, true, true, true, true, true, true, true, /* 28 */
true, true, true, true, true, true, true, true, /* 30 */
true, true, true, true, false, true, false, true, /* 38 */
true, true, true, true, true, true, true, true, /* 40 */
true, true, true, true, true, true, true, true, /* 48 */
true, true, true, true, true, true, true, true, /* 50 */
true, true, true, true, false, true, false, true, /* 58 */
false, true, true, true, true, true, true, true, /* 60 */
true, true, true, true, true, true, true, true, /* 68 */
true, true, true, true, true, true, true, true, /* 70 */
true, true, true, false, true, false, true, false, /* 78 */
false, false, false, false, false, false, false, false, /* 80 */
false, false, false, false, false, false, false, false, /* 88 */
false, false, false, false, false, false, false, false, /* 90 */
false, false, false, false, false, false, false, false, /* 98 */
false, false, false, false, false, false, false, false, /* A0 */
false, false, false, false, false, false, false, false, /* A8 */
false, false, false, false, false, false, false, false, /* B0 */
false, false, false, false, false, false, false, false, /* B8 */
false, false, false, false, false, false, false, false, /* C0 */
false, false, false, false, false, false, false, false, /* C8 */
false, false, false, false, false, false, false, false, /* D0 */
false, false, false, false, false, false, false, false, /* D8 */
false, false, false, false, false, false, false, false, /* E0 */
false, false, false, false, false, false, false, false, /* E8 */
false, false, false, false, false, false, false, false, /* F0 */
false, false, false, false, false, false, false, false, /* F8 */
};
return no_escape[c];
}
 
 
/** nsurl scheme type */
enum scheme_type {
NSURL_SCHEME_OTHER,
NSURL_SCHEME_HTTP,
NSURL_SCHEME_HTTPS,
NSURL_SCHEME_FTP,
NSURL_SCHEME_MAILTO
};
 
 
/** nsurl components */
struct nsurl_components {
lwc_string *scheme;
lwc_string *username;
lwc_string *password;
lwc_string *host;
lwc_string *port;
lwc_string *path;
lwc_string *query;
lwc_string *fragment;
 
enum scheme_type scheme_type;
};
 
 
/**
* NetSurf URL object
*
* [scheme]://[username][:password]@[host]:[port][/path][?query][#fragment]
*/
struct nsurl {
struct nsurl_components components;
 
int count; /* Number of references to NetSurf URL object */
 
size_t length; /* Length of string */
char string[FLEX_ARRAY_LEN_DECL]; /* Full URL as a string */
};
 
 
/** Marker set, indicating positions of sections within a URL string */
struct url_markers {
size_t start; /** start of URL */
size_t scheme_end;
size_t authority;
 
size_t colon_first;
size_t at;
size_t colon_last;
 
size_t path;
size_t query;
size_t fragment;
 
size_t end; /** end of URL */
 
enum scheme_type scheme_type;
};
 
 
/** Marker set, indicating positions of sections within a URL string */
struct nsurl_component_lengths {
size_t scheme;
size_t username;
size_t password;
size_t host;
size_t port;
size_t path;
size_t query;
size_t fragment;
};
 
 
/** Flags indicating which parts of a URL string are required for a nsurl */
enum nsurl_string_flags {
NSURL_F_SCHEME = (1 << 0),
NSURL_F_SCHEME_PUNCTUATION = (1 << 1),
NSURL_F_AUTHORITY_PUNCTUATION = (1 << 2),
NSURL_F_USERNAME = (1 << 3),
NSURL_F_PASSWORD = (1 << 4),
NSURL_F_CREDENTIALS_PUNCTUATION = (1 << 5),
NSURL_F_HOST = (1 << 6),
NSURL_F_PORT = (1 << 7),
NSURL_F_AUTHORITY = (NSURL_F_USERNAME |
NSURL_F_PASSWORD |
NSURL_F_HOST |
NSURL_F_PORT),
NSURL_F_PATH = (1 << 8),
NSURL_F_QUERY = (1 << 9),
NSURL_F_FRAGMENT_PUNCTUATION = (1 << 10),
NSURL_F_FRAGMENT = (1 << 11)
};
 
 
/** Sections of a URL */
enum url_sections {
URL_SCHEME,
URL_CREDENTIALS,
URL_HOST,
URL_PATH,
URL_QUERY,
URL_FRAGMENT
};
 
 
#define nsurl__component_copy(c) (c == NULL) ? NULL : lwc_string_ref(c)
 
#define nsurl__component_compare(c1, c2, match) \
if (c1 && c2 && lwc_error_ok == \
lwc_string_isequal(c1, c2, match)) { \
/* do nothing */ \
} else if (c1 || c2) { \
*match = false; \
}
 
 
/**
* Obtains a set of markers delimiting sections in a URL string
*
* \param url_s URL string
* \param markers Updated to mark sections in the URL string
* \param joining True iff URL string is a relative URL for joining
*/
static void nsurl__get_string_markers(const char * const url_s,
struct url_markers *markers, bool joining)
{
const char *pos = url_s; /** current position in url_s */
bool is_http = false;
bool trailing_whitespace = false;
 
/* Initialise marker set */
struct url_markers marker = { 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, NSURL_SCHEME_OTHER };
 
/* Skip any leading whitespace in url_s */
while (isspace(*pos))
pos++;
 
/* Record start point */
marker.start = pos - url_s;
 
marker.scheme_end = marker.authority = marker.colon_first = marker.at =
marker.colon_last = marker.path = marker.start;
 
if (*pos == '\0') {
/* Nothing but whitespace, early exit */
marker.query = marker.fragment = marker.end = marker.path;
*markers = marker;
return;
}
 
/* Get scheme */
if (isalpha(*pos)) {
pos++;
 
while (*pos != ':' && *pos != '\0') {
if (!isalnum(*pos) && *pos != '+' &&
*pos != '-' && *pos != '.') {
/* This character is not valid in the
* scheme */
break;
}
pos++;
}
 
if (*pos == ':') {
/* This delimits the end of the scheme */
size_t off;
 
marker.scheme_end = pos - url_s;
 
off = marker.scheme_end - marker.start;
 
/* Detect http(s) and mailto for scheme specifc
* normalisation */
if (off == SLEN("http") &&
(((*(pos - off + 0) == 'h') ||
(*(pos - off + 0) == 'H')) &&
((*(pos - off + 1) == 't') ||
(*(pos - off + 1) == 'T')) &&
((*(pos - off + 2) == 't') ||
(*(pos - off + 2) == 'T')) &&
((*(pos - off + 3) == 'p') ||
(*(pos - off + 3) == 'P')))) {
marker.scheme_type = NSURL_SCHEME_HTTP;
is_http = true;
} else if (off == SLEN("https") &&
(((*(pos - off + 0) == 'h') ||
(*(pos - off + 0) == 'H')) &&
((*(pos - off + 1) == 't') ||
(*(pos - off + 1) == 'T')) &&
((*(pos - off + 2) == 't') ||
(*(pos - off + 2) == 'T')) &&
((*(pos - off + 3) == 'p') ||
(*(pos - off + 3) == 'P')) &&
((*(pos - off + 4) == 's') ||
(*(pos - off + 4) == 'S')))) {
marker.scheme_type = NSURL_SCHEME_HTTPS;
is_http = true;
} else if (off == SLEN("ftp") &&
(((*(pos - off + 0) == 'f') ||
(*(pos - off + 0) == 'F')) &&
((*(pos - off + 1) == 't') ||
(*(pos - off + 1) == 'T')) &&
((*(pos - off + 2) == 'p') ||
(*(pos - off + 2) == 'P')))) {
marker.scheme_type = NSURL_SCHEME_FTP;
} else if (off == SLEN("mailto") &&
(((*(pos - off + 0) == 'm') ||
(*(pos - off + 0) == 'M')) &&
((*(pos - off + 1) == 'a') ||
(*(pos - off + 1) == 'A')) &&
((*(pos - off + 2) == 'i') ||
(*(pos - off + 2) == 'I')) &&
((*(pos - off + 3) == 'l') ||
(*(pos - off + 3) == 'L')) &&
((*(pos - off + 4) == 't') ||
(*(pos - off + 4) == 'T')) &&
((*(pos - off + 5) == 'o') ||
(*(pos - off + 5) == 'O')))) {
marker.scheme_type = NSURL_SCHEME_MAILTO;
}
 
/* Skip over colon */
pos++;
 
/* Mark place as start of authority */
marker.authority = marker.colon_first = marker.at =
marker.colon_last = marker.path =
pos - url_s;
 
} else {
/* Not found a scheme */
if (joining == false) {
/* Assuming no scheme == http */
marker.scheme_type = NSURL_SCHEME_HTTP;
is_http = true;
}
}
}
 
/* Get authority
*
* Two slashes always indicates the start of an authority.
*
* We are more relaxed in the case of http:
* a. when joining, one or more slashes indicates start of authority
* b. when not joining, we assume authority if no scheme was present
* and in the case of mailto: when we assume there is an authority.
*/
if ((*pos == '/' && *(pos + 1) == '/') ||
(is_http && ((joining && *pos == '/') ||
(joining == false &&
marker.scheme_end != marker.start))) ||
marker.scheme_type == NSURL_SCHEME_MAILTO) {
 
/* Skip over leading slashes */
if (*pos == '/') {
if (is_http == false) {
if (*pos == '/') pos++;
if (*pos == '/') pos++;
} else {
while (*pos == '/')
pos++;
}
 
marker.authority = marker.colon_first = marker.at =
marker.colon_last = marker.path =
pos - url_s;
}
 
/* Need to get (or complete) the authority */
while (*pos != '\0') {
if (*pos == '/' || *pos == '?' || *pos == '#') {
/* End of the authority */
break;
 
} else if (*pos == ':' && marker.colon_first ==
marker.authority) {
/* could be username:password or host:port
* separator */
marker.colon_first = pos - url_s;
 
} else if (*pos == ':' && marker.colon_first !=
marker.authority) {
/* could be host:port separator */
marker.colon_last = pos - url_s;
 
} else if (*pos == '@' && marker.at ==
marker.authority) {
/* Credentials @ host separator */
marker.at = pos - url_s;
}
 
pos++;
}
 
marker.path = pos - url_s;
 
} else if ((*pos == '\0' || *pos == '/') &&
joining == false && is_http == true) {
marker.path = pos - url_s;
}
 
/* Get path
*
* Needs to start with '/' if there's no authority
*/
if (*pos == '/' || ((marker.path == marker.authority) &&
(*pos != '?') && (*pos != '#') && (*pos != '\0'))) {
while (*(++pos) != '\0') {
if (*pos == '?' || *pos == '#') {
/* End of the path */
break;
}
}
}
 
marker.query = pos - url_s;
 
/* Get query */
if (*pos == '?') {
while (*(++pos) != '\0') {
if (*pos == '#') {
/* End of the query */
break;
}
}
}
 
marker.fragment = pos - url_s;
 
/* Get fragment */
if (*pos == '#') {
while (*(++pos) != '\0')
;
}
 
/* We got to the end of url_s.
* Need to skip back over trailing whitespace to find end of URL */
pos--;
if (pos >= url_s && isspace(*pos)) {
trailing_whitespace = true;
while (pos >= url_s && isspace(*pos))
pos--;
}
 
marker.end = pos + 1 - url_s;
 
if (trailing_whitespace == true) {
/* Ensure last url section doesn't pass end */
if (marker.fragment > marker.end)
marker.fragment = marker.end;
if (marker.query > marker.end)
marker.query = marker.end;
if (marker.path > marker.end)
marker.path = marker.end;
if (marker.colon_last > marker.end)
marker.colon_last = marker.end;
if (marker.at > marker.end)
marker.at = marker.end;
if (marker.colon_last > marker.end)
marker.colon_last = marker.end;
if (marker.fragment > marker.end)
marker.fragment = marker.end;
}
 
/* Got all the URL components pegged out now */
*markers = marker;
}
 
 
/**
* Remove dot segments from a path, as per rfc 3986, 5.2.4
*
* \param path path to remove dot segments from ('\0' terminated)
* \param output path with dot segments removed
* \return size of output
*/
static size_t nsurl__remove_dot_segments(char *path, char *output)
{
char *path_pos = path;
char *output_pos = output;
 
while (*path_pos != '\0') {
#ifdef NSURL_DEBUG
LOG((" in:%s", path_pos));
LOG(("out:%.*s", output_pos - output, output));
#endif
if (*path_pos == '.') {
if (*(path_pos + 1) == '.' &&
*(path_pos + 2) == '/') {
/* Found prefix of "../" */
path_pos += SLEN("../");
continue;
 
} else if (*(path_pos + 1) == '/') {
/* Found prefix of "./" */
path_pos += SLEN("./");
continue;
}
} else if (*path_pos == '/' && *(path_pos + 1) == '.') {
if (*(path_pos + 2) == '/') {
/* Found prefix of "/./" */
path_pos += SLEN("/.");
continue;
 
} else if (*(path_pos + 2) == '\0') {
/* Found "/." at end of path */
*(output_pos++) = '/';
 
/* End of input path */
break;
 
} else if (*(path_pos + 2) == '.') {
if (*(path_pos + 3) == '/') {
/* Found prefix of "/../" */
path_pos += SLEN("/..");
 
if (output_pos > output)
output_pos--;
while (output_pos > output &&
*output_pos != '/')
output_pos--;
 
continue;
 
} else if (*(path_pos + 3) == '\0') {
/* Found "/.." at end of path */
 
while (output_pos > output &&
*(output_pos -1 ) !='/')
output_pos--;
 
/* End of input path */
break;
}
}
} else if (*path_pos == '.') {
if (*(path_pos + 1) == '\0') {
/* Found "." at end of path */
 
/* End of input path */
break;
 
} else if (*(path_pos + 1) == '.' &&
*(path_pos + 2) == '\0') {
/* Found ".." at end of path */
 
/* End of input path */
break;
}
}
/* Copy first character into output path */
*output_pos++ = *path_pos++;
 
/* Copy up to but not including next '/' */
while ((*path_pos != '/') && (*path_pos != '\0'))
*output_pos++ = *path_pos++;
}
 
return output_pos - output;
}
 
 
/**
* Get the length of the longest section
*
* \param m markers delimiting url sections in a string
* \return the length of the longest section
*/
static size_t nsurl__get_longest_section(struct url_markers *m)
{
size_t length = m->scheme_end - m->start; /* scheme */
 
if (length < m->at - m->authority) /* credentials */
length = m->at - m->authority;
 
if (length < m->path - m->at) /* host */
length = m->path - m->at;
 
if (length < m->query - m->path) /* path */
length = m->query - m->path;
 
if (length < m->fragment - m->query) /* query */
length = m->fragment - m->query;
 
if (length < m->end - m->fragment) /* fragment */
length = m->end - m->fragment;
 
return length;
}
 
 
/**
* Converts two hexadecimal digits to a single number
*
* \param c1 most significant hex digit
* \param c2 least significant hex digit
* \return the total value of the two digit hex number, or -ve if input not hex
*
* For unescaping url encoded characters.
*/
static inline int nsurl__get_ascii_offset(char c1, char c2)
{
int offset;
 
/* Use 1st char as most significant hex digit */
if (isdigit(c1))
offset = 16 * (c1 - '0');
else if (c1 >= 'a' && c1 <= 'f')
offset = 16 * (c1 - 'a' + 10);
else if (c1 >= 'A' && c1 <= 'F')
offset = 16 * (c1 - 'A' + 10);
else
/* Not valid hex */
return -1;
 
/* Use 2nd char as least significant hex digit and sum */
if (isdigit(c2))
offset += c2 - '0';
else if (c2 >= 'a' && c2 <= 'f')
offset += c2 - 'a' + 10;
else if (c2 >= 'A' && c2 <= 'F')
offset += c2 - 'A' + 10;
else
/* Not valid hex */
return -1;
 
return offset;
}
 
 
/**
* Create the components of a NetSurf URL object for a section of a URL string
*
* \param url_s URL string
* \param section Sets which section of URL string is to be normalised
* \param pegs Set of markers delimiting the URL string's sections
* \param pos_norm A buffer large enough for the normalised string (*3 + 1)
* \param url A NetSurf URL object, to which components may be added
* \return NSERROR_OK on success, appropriate error otherwise
*
* The section of url_s is normalised appropriately.
*/
static nserror nsurl__create_from_section(const char * const url_s,
const enum url_sections section,
const struct url_markers *pegs,
char *pos_norm,
struct nsurl_components *url)
{
int ascii_offset;
int start = 0;
int end = 0;
const char *pos;
const char *pos_url_s;
char *norm_start = pos_norm;
size_t copy_len;
size_t length;
enum {
NSURL_F_NO_PORT = (1 << 0)
} flags = 0;
 
switch (section) {
case URL_SCHEME:
start = pegs->start;
end = pegs->scheme_end;
break;
 
case URL_CREDENTIALS:
start = pegs->authority;
end = pegs->at;
break;
 
case URL_HOST:
start = (pegs->at == pegs->authority &&
*(url_s + pegs->at) != '@') ?
pegs->at :
pegs->at + 1;
end = pegs->path;
break;
 
case URL_PATH:
start = pegs->path;
end = pegs->query;
break;
 
case URL_QUERY:
start = pegs->query;
end = pegs->fragment;
break;
 
case URL_FRAGMENT:
start = (*(url_s + pegs->fragment) != '#') ?
pegs->fragment :
pegs->fragment + 1;
end = pegs->end;
break;
}
 
if (end < start)
end = start;
 
length = end - start;
 
/* Stage 1: Normalise the required section */
 
pos = pos_url_s = url_s + start;
copy_len = 0;
for (; pos < url_s + end; pos++) {
if (*pos == '%' && (pos + 2 < url_s + end)) {
/* Might be an escaped character needing unescaped */
 
/* Find which character which was escaped */
ascii_offset = nsurl__get_ascii_offset(*(pos + 1),
*(pos + 2));
 
if (ascii_offset < 0) {
/* % with invalid hex digits. */
copy_len++;
continue;
}
 
if (nsurl__is_unreserved(ascii_offset) == false) {
/* This character should be escaped after all,
* just let it get copied */
copy_len += 3;
pos += 2;
continue;
}
 
if (copy_len > 0) {
/* Copy up to here */
memcpy(pos_norm, pos_url_s, copy_len);
pos_norm += copy_len;
copy_len = 0;
}
 
/* Put the unescaped character in the normalised URL */
*(pos_norm++) = (char)ascii_offset;
pos += 2;
pos_url_s = pos + 1;
 
length -= 2;
 
} else if (nsurl__is_no_escape(*pos) == false) {
 
/* This needs to be escaped */
if (copy_len > 0) {
/* Copy up to here */
memcpy(pos_norm, pos_url_s, copy_len);
pos_norm += copy_len;
copy_len = 0;
}
 
/* escape */
*(pos_norm++) = '%';
*(pos_norm++) = digit2uppercase_hex(
((unsigned char)*pos) >> 4);
*(pos_norm++) = digit2uppercase_hex(
((unsigned char)*pos) & 0xf);
pos_url_s = pos + 1;
 
length += 2;
 
} else if ((section == URL_SCHEME || section == URL_HOST) &&
isupper(*pos)) {
/* Lower case this letter */
 
if (copy_len > 0) {
/* Copy up to here */
memcpy(pos_norm, pos_url_s, copy_len);
pos_norm += copy_len;
copy_len = 0;
}
/* Copy lower cased letter into normalised URL */
*(pos_norm++) = tolower(*pos);
pos_url_s = pos + 1;
 
} else {
/* This character is safe in normalised URL */
copy_len++;
}
}
 
if (copy_len > 0) {
/* Copy up to here */
memcpy(pos_norm, pos_url_s, copy_len);
pos_norm += copy_len;
}
 
/* Mark end of section */
(*pos_norm) = '\0';
 
/* Stage 2: Create the URL components for the required section */
switch (section) {
case URL_SCHEME:
if (length == 0) {
/* No scheme, assuming http, and add to URL */
if (lwc_intern_string("http", SLEN("http"),
&url->scheme) != lwc_error_ok) {
return NSERROR_NOMEM;
}
} else {
/* Add scheme to URL */
if (lwc_intern_string(norm_start, length,
&url->scheme) != lwc_error_ok) {
return NSERROR_NOMEM;
}
}
 
break;
 
case URL_CREDENTIALS:
url->username = NULL;
url->password = NULL;
 
if (length != 0 && *norm_start != ':') {
char *sec_start = norm_start;
if (pegs->colon_first != pegs->authority &&
pegs->at > pegs->colon_first + 1) {
/* there's a password */
sec_start += pegs->colon_first -
pegs->authority + 1;
if (lwc_intern_string(sec_start,
pegs->at - pegs->colon_first -1,
&url->password) !=
lwc_error_ok) {
return NSERROR_NOMEM;
}
 
/* update start pos and length for username */
sec_start = norm_start;
length -= pegs->at - pegs->colon_first;
} else if (pegs->colon_first != pegs->authority &&
pegs->at == pegs->colon_first + 1) {
/* strip username colon */
length--;
}
 
/* Username */
if (lwc_intern_string(sec_start, length,
&url->username) != lwc_error_ok) {
return NSERROR_NOMEM;
}
}
 
break;
 
case URL_HOST:
url->host = NULL;
url->port = NULL;
 
if (length != 0) {
size_t colon = 0;
char *sec_start = norm_start;
if (pegs->at < pegs->colon_first &&
pegs->colon_last == pegs->authority) {
/* There's one colon and it's after @ marker */
colon = pegs->colon_first;
} else if (pegs->colon_last != pegs->authority) {
/* There's more than one colon */
colon = pegs->colon_last;
} else {
/* There's no colon that could be a port
* separator */
flags |= NSURL_F_NO_PORT;
}
 
if (!(flags & NSURL_F_NO_PORT)) {
/* Determine whether colon is a port separator
*/
sec_start += colon - pegs->at;
while (++sec_start < norm_start + length) {
if (!isdigit(*sec_start)) {
/* Character after port isn't a
* digit; not a port separator
*/
flags |= NSURL_F_NO_PORT;
break;
}
}
}
 
if (!(flags & NSURL_F_NO_PORT)) {
/* There's a port */
size_t skip = (pegs->at == pegs->authority) ?
1 : 0;
sec_start = norm_start + colon - pegs->at +
skip;
if (url->scheme != NULL &&
url->scheme_type ==
NSURL_SCHEME_HTTP &&
length -
(colon - pegs->at + skip) == 2 &&
*sec_start == '8' &&
*(sec_start + 1) == '0') {
/* Scheme is http, and port is default
* (80) */
flags |= NSURL_F_NO_PORT;
}
 
if (length - (colon - pegs->at + skip) <= 0) {
/* No space for a port after the colon
*/
flags |= NSURL_F_NO_PORT;
}
 
/* Add non-redundant ports to NetSurf URL */
sec_start = norm_start + colon - pegs->at +
skip;
if (!(flags & NSURL_F_NO_PORT) &&
lwc_intern_string(sec_start,
length -
(colon - pegs->at + skip),
&url->port) != lwc_error_ok) {
return NSERROR_NOMEM;
}
 
/* update length for host */
skip = (pegs->at == pegs->authority) ? 0 : 1;
length = colon - pegs->at - skip;
}
 
/* host */
if (lwc_intern_string(norm_start, length,
&url->host) != lwc_error_ok) {
return NSERROR_NOMEM;
}
}
 
break;
 
case URL_PATH:
if (length != 0) {
if (lwc_intern_string(norm_start, length,
&url->path) != lwc_error_ok) {
return NSERROR_NOMEM;
}
} else if (url->host != NULL &&
url->scheme_type != NSURL_SCHEME_MAILTO) {
/* Set empty path to "/", if there's a host */
if (lwc_intern_string("/", SLEN("/"),
&url->path) != lwc_error_ok) {
return NSERROR_NOMEM;
}
} else {
url->path = NULL;
}
 
break;
 
case URL_QUERY:
if (length != 0) {
if (lwc_intern_string(norm_start, length,
&url->query) != lwc_error_ok) {
return NSERROR_NOMEM;
}
} else {
url->query = NULL;
}
 
break;
 
case URL_FRAGMENT:
if (length != 0) {
if (lwc_intern_string(norm_start, length,
&url->fragment) != lwc_error_ok) {
return NSERROR_NOMEM;
}
} else {
url->fragment = NULL;
}
 
break;
}
 
return NSERROR_OK;
}
 
 
/**
* Get nsurl string info; total length, component lengths, & components present
*
* \param url NetSurf URL components
* \param parts Which parts of the URL are required in the string
* \param url_l Updated to total string length
* \param lengths Updated with individual component lengths
* \param pflags Updated to contain relevant string flags
*/
static void nsurl__get_string_data(const struct nsurl_components *url,
nsurl_component parts, size_t *url_l,
struct nsurl_component_lengths *lengths,
enum nsurl_string_flags *pflags)
{
enum nsurl_string_flags flags = *pflags;
*url_l = 0;
 
/* Intersection of required parts and available parts gives
* the output parts */
if (url->scheme && parts & NSURL_SCHEME) {
flags |= NSURL_F_SCHEME;
 
lengths->scheme = lwc_string_length(url->scheme);
*url_l += lengths->scheme;
}
 
if (url->username && parts & NSURL_USERNAME) {
flags |= NSURL_F_USERNAME;
 
lengths->username = lwc_string_length(url->username);
*url_l += lengths->username;
}
 
if (url->password && parts & NSURL_PASSWORD) {
flags |= NSURL_F_PASSWORD;
 
lengths->password = lwc_string_length(url->password);
*url_l += SLEN(":") + lengths->password;
}
 
if (url->host && parts & NSURL_HOST) {
flags |= NSURL_F_HOST;
 
lengths->host = lwc_string_length(url->host);
*url_l += lengths->host;
}
 
if (url->port && parts & NSURL_PORT) {
flags |= NSURL_F_PORT;
 
lengths->port = lwc_string_length(url->port);
*url_l += SLEN(":") + lengths->port;
}
 
if (url->path && parts & NSURL_PATH) {
flags |= NSURL_F_PATH;
 
lengths->path = lwc_string_length(url->path);
*url_l += lengths->path;
}
 
if (url->query && parts & NSURL_QUERY) {
flags |= NSURL_F_QUERY;
 
lengths->query = lwc_string_length(url->query);
*url_l += lengths->query;
}
 
if (url->fragment && parts & NSURL_FRAGMENT) {
flags |= NSURL_F_FRAGMENT;
 
lengths->fragment = lwc_string_length(url->fragment);
*url_l += lengths->fragment;
}
 
/* Turn on any spanned punctuation */
if ((flags & NSURL_F_SCHEME) && (parts > NSURL_SCHEME)) {
flags |= NSURL_F_SCHEME_PUNCTUATION;
 
*url_l += SLEN(":");
}
 
if ((flags & NSURL_F_SCHEME) && (flags > NSURL_F_SCHEME) &&
url->path && lwc_string_data(url->path)[0] == '/') {
flags |= NSURL_F_AUTHORITY_PUNCTUATION;
 
*url_l += SLEN("//");
}
 
if ((flags & (NSURL_F_USERNAME | NSURL_F_PASSWORD)) &&
flags & NSURL_F_HOST) {
flags |= NSURL_F_CREDENTIALS_PUNCTUATION;
 
*url_l += SLEN("@");
}
 
if ((flags & ~NSURL_F_FRAGMENT) && (flags & NSURL_F_FRAGMENT)) {
flags |= NSURL_F_FRAGMENT_PUNCTUATION;
 
*url_l += SLEN("#");
}
 
*pflags = flags;
}
 
 
/**
* Get nsurl string info; total length, component lengths, & components present
*
* \param url NetSurf URL components
* \param url_s Updated to contain the string
* \param l Individual component lengths
* \param flags String flags
*/
static void nsurl_get_string(const struct nsurl_components *url, char *url_s,
struct nsurl_component_lengths *l,
enum nsurl_string_flags flags)
{
char *pos;
 
/* Copy the required parts into the url string */
pos = url_s;
 
if (flags & NSURL_F_SCHEME) {
memcpy(pos, lwc_string_data(url->scheme), l->scheme);
pos += l->scheme;
}
 
if (flags & NSURL_F_SCHEME_PUNCTUATION) {
*(pos++) = ':';
}
 
if (flags & NSURL_F_AUTHORITY_PUNCTUATION) {
*(pos++) = '/';
*(pos++) = '/';
}
 
if (flags & NSURL_F_USERNAME) {
memcpy(pos, lwc_string_data(url->username), l->username);
pos += l->username;
}
 
if (flags & NSURL_F_PASSWORD) {
*(pos++) = ':';
memcpy(pos, lwc_string_data(url->password), l->password);
pos += l->password;
}
 
if (flags & NSURL_F_CREDENTIALS_PUNCTUATION) {
*(pos++) = '@';
}
 
if (flags & NSURL_F_HOST) {
memcpy(pos, lwc_string_data(url->host), l->host);
pos += l->host;
}
 
if (flags & NSURL_F_PORT) {
*(pos++) = ':';
memcpy(pos, lwc_string_data(url->port), l->port);
pos += l->port;
}
 
if (flags & NSURL_F_PATH) {
memcpy(pos, lwc_string_data(url->path), l->path);
pos += l->path;
}
 
if (flags & NSURL_F_QUERY) {
memcpy(pos, lwc_string_data(url->query), l->query);
pos += l->query;
}
 
if (flags & NSURL_F_FRAGMENT) {
if (flags & NSURL_F_FRAGMENT_PUNCTUATION)
*(pos++) = '#';
memcpy(pos, lwc_string_data(url->fragment), l->fragment);
pos += l->fragment;
}
 
*pos = '\0';
}
 
 
#ifdef NSURL_DEBUG
/**
* Dump a NetSurf URL's internal components
*
* \param url The NetSurf URL to dump components of
*/
static void nsurl__dump(const nsurl *url)
{
if (url->components.scheme)
LOG((" Scheme: %s", lwc_string_data(url->components.scheme)));
 
if (url->components.username)
LOG(("Username: %s",
lwc_string_data(url->components.username)));
 
if (url->components.password)
LOG(("Password: %s",
lwc_string_data(url->components.password)));
 
if (url->components.host)
LOG((" Host: %s", lwc_string_data(url->components.host)));
 
if (url->components.port)
LOG((" Port: %s", lwc_string_data(url->components.port)));
 
if (url->components.path)
LOG((" Path: %s", lwc_string_data(url->components.path)));
 
if (url->components.query)
LOG((" Query: %s", lwc_string_data(url->components.query)));
 
if (url->components.fragment)
LOG(("Fragment: %s",
lwc_string_data(url->components.fragment)));
}
#endif
 
/******************************************************************************
* NetSurf URL Public API *
******************************************************************************/
 
/* exported interface, documented in nsurl.h */
nserror nsurl_create(const char * const url_s, nsurl **url)
{
struct url_markers m;
struct nsurl_components c;
size_t length;
char *buff;
struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
enum nsurl_string_flags str_flags = 0;
nserror e = NSERROR_OK;
 
assert(url_s != NULL);
 
/* Peg out the URL sections */
nsurl__get_string_markers(url_s, &m, false);
 
/* Get the length of the longest section */
length = nsurl__get_longest_section(&m);
 
/* Allocate enough memory to url escape the longest section */
buff = malloc(length * 3 + 1);
if (buff == NULL)
return NSERROR_NOMEM;
 
/* Set scheme type */
c.scheme_type = m.scheme_type;
 
/* Build NetSurf URL object from sections */
e |= nsurl__create_from_section(url_s, URL_SCHEME, &m, buff, &c);
e |= nsurl__create_from_section(url_s, URL_CREDENTIALS, &m, buff, &c);
e |= nsurl__create_from_section(url_s, URL_HOST, &m, buff, &c);
e |= nsurl__create_from_section(url_s, URL_PATH, &m, buff, &c);
e |= nsurl__create_from_section(url_s, URL_QUERY, &m, buff, &c);
e |= nsurl__create_from_section(url_s, URL_FRAGMENT, &m, buff, &c);
 
/* Finished with buffer */
free(buff);
 
if (e != NSERROR_OK)
return NSERROR_NOMEM;
 
/* Get the string length and find which parts of url are present */
nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
&str_len, &str_flags);
 
/* Create NetSurf URL object */
*url = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
if (*url == NULL)
return NSERROR_NOMEM;
 
(*url)->components = c;
(*url)->length = length;
 
/* Fill out the url string */
nsurl_get_string(&c, (*url)->string, &str_len, str_flags);
 
/* Give the URL a reference */
(*url)->count = 1;
 
return NSERROR_OK;
}
 
 
/* exported interface, documented in nsurl.h */
nsurl *nsurl_ref(nsurl *url)
{
assert(url != NULL);
 
url->count++;
 
return url;
}
 
 
/* exported interface, documented in nsurl.h */
void nsurl_unref(nsurl *url)
{
assert(url != NULL);
assert(url->count > 0);
 
if (--url->count > 0)
return;
 
#ifdef NSURL_DEBUG
nsurl__dump(url);
#endif
 
/* Release lwc strings */
if (url->components.scheme)
lwc_string_unref(url->components.scheme);
 
if (url->components.username)
lwc_string_unref(url->components.username);
 
if (url->components.password)
lwc_string_unref(url->components.password);
 
if (url->components.host)
lwc_string_unref(url->components.host);
 
if (url->components.port)
lwc_string_unref(url->components.port);
 
if (url->components.path)
lwc_string_unref(url->components.path);
 
if (url->components.query)
lwc_string_unref(url->components.query);
 
if (url->components.fragment)
lwc_string_unref(url->components.fragment);
 
/* Free the NetSurf URL */
free(url);
}
 
 
/* exported interface, documented in nsurl.h */
bool nsurl_compare(const nsurl *url1, const nsurl *url2, nsurl_component parts)
{
bool match = true;
 
assert(url1 != NULL);
assert(url2 != NULL);
 
/* Compare URL components */
 
/* Path, host and query first, since they're most likely to differ */
 
if (parts & NSURL_PATH) {
nsurl__component_compare(url1->components.path,
url2->components.path, &match);
 
if (match == false)
return false;
}
 
if (parts & NSURL_HOST) {
nsurl__component_compare(url1->components.host,
url2->components.host, &match);
 
if (match == false)
return false;
}
 
if (parts & NSURL_QUERY) {
nsurl__component_compare(url1->components.query,
url2->components.query, &match);
 
if (match == false)
return false;
}
 
if (parts & NSURL_SCHEME) {
nsurl__component_compare(url1->components.scheme,
url2->components.scheme, &match);
 
if (match == false)
return false;
}
 
if (parts & NSURL_USERNAME) {
nsurl__component_compare(url1->components.username,
url2->components.username, &match);
 
if (match == false)
return false;
}
 
if (parts & NSURL_PASSWORD) {
nsurl__component_compare(url1->components.password,
url2->components.password, &match);
 
if (match == false)
return false;
}
 
if (parts & NSURL_PORT) {
nsurl__component_compare(url1->components.port,
url2->components.port, &match);
 
if (match == false)
return false;
}
 
if (parts & NSURL_FRAGMENT) {
nsurl__component_compare(url1->components.fragment,
url2->components.fragment, &match);
 
if (match == false)
return false;
}
 
return true;
}
 
 
/* exported interface, documented in nsurl.h */
nserror nsurl_get(const nsurl *url, nsurl_component parts,
char **url_s, size_t *url_l)
{
struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
enum nsurl_string_flags str_flags = 0;
 
/* Get the string length and find which parts of url need copied */
nsurl__get_string_data(&(url->components), parts, url_l,
&str_len, &str_flags);
 
if (*url_l == 0) {
return NSERROR_BAD_URL;
}
 
/* Allocate memory for url string */
*url_s = malloc(*url_l + 1); /* adding 1 for '\0' */
if (*url_s == NULL) {
return NSERROR_NOMEM;
}
 
/* Copy the required parts into the url string */
nsurl_get_string(&(url->components), *url_s, &str_len, str_flags);
 
return NSERROR_OK;
}
 
 
/* exported interface, documented in nsurl.h */
lwc_string *nsurl_get_component(const nsurl *url, nsurl_component part)
{
assert(url != NULL);
 
switch (part) {
case NSURL_SCHEME:
return (url->components.scheme != NULL) ?
lwc_string_ref(url->components.scheme) : NULL;
 
case NSURL_USERNAME:
return (url->components.username != NULL) ?
lwc_string_ref(url->components.username) : NULL;
 
case NSURL_PASSWORD:
return (url->components.password != NULL) ?
lwc_string_ref(url->components.password) : NULL;
 
case NSURL_HOST:
return (url->components.host != NULL) ?
lwc_string_ref(url->components.host) : NULL;
 
case NSURL_PORT:
return (url->components.port != NULL) ?
lwc_string_ref(url->components.port) : NULL;
 
case NSURL_PATH:
return (url->components.path != NULL) ?
lwc_string_ref(url->components.path) : NULL;
 
case NSURL_QUERY:
return (url->components.query != NULL) ?
lwc_string_ref(url->components.query) : NULL;
 
case NSURL_FRAGMENT:
return (url->components.fragment != NULL) ?
lwc_string_ref(url->components.fragment) : NULL;
 
default:
LOG(("Unsupported value passed to part param."));
assert(0);
}
 
return NULL;
}
 
 
/* exported interface, documented in nsurl.h */
bool nsurl_has_component(const nsurl *url, nsurl_component part)
{
assert(url != NULL);
 
switch (part) {
case NSURL_SCHEME:
if (url->components.scheme != NULL)
return true;
else
return false;
 
case NSURL_CREDENTIALS:
/* Only username required for credentials section */
/* Fall through */
case NSURL_USERNAME:
if (url->components.username != NULL)
return true;
else
return false;
 
case NSURL_PASSWORD:
if (url->components.password != NULL)
return true;
else
return false;
 
case NSURL_HOST:
if (url->components.host != NULL)
return true;
else
return false;
 
case NSURL_PORT:
if (url->components.port != NULL)
return true;
else
return false;
 
case NSURL_PATH:
if (url->components.path != NULL)
return true;
else
return false;
 
case NSURL_QUERY:
if (url->components.query != NULL)
return true;
else
return false;
 
case NSURL_FRAGMENT:
if (url->components.fragment != NULL)
return true;
else
return false;
 
default:
LOG(("Unsupported value passed to part param."));
assert(0);
}
 
return false;
}
 
 
/* exported interface, documented in nsurl.h */
const char *nsurl_access(const nsurl *url)
{
assert(url != NULL);
 
return url->string;
}
 
 
/* exported interface, documented in nsurl.h */
const char *nsurl_access_leaf(const nsurl *url)
{
size_t path_len;
const char *path;
const char *leaf;
 
if (url->components.path == NULL)
return "";
 
path = lwc_string_data(url->components.path);
path_len = lwc_string_length(url->components.path);
 
if (path_len == 0)
return "";
 
if (path_len == 1 && *path == '/')
return "/";
 
leaf = path + path_len;
 
do {
leaf--;
} while ((leaf != path) && (*leaf != '/'));
 
if (*leaf == '/')
leaf++;
 
return leaf;
}
 
 
/* exported interface, documented in nsurl.h */
size_t nsurl_length(const nsurl *url)
{
assert(url != NULL);
 
return url->length;
}
 
 
/* exported interface, documented in nsurl.h */
nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
{
struct url_markers m;
struct nsurl_components c;
size_t length;
char *buff;
char *buff_pos;
char *buff_start;
struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
enum nsurl_string_flags str_flags = 0;
nserror error = 0;
enum {
NSURL_F_REL = 0,
NSURL_F_BASE_SCHEME = (1 << 0),
NSURL_F_BASE_AUTHORITY = (1 << 1),
NSURL_F_BASE_PATH = (1 << 2),
NSURL_F_MERGED_PATH = (1 << 3),
NSURL_F_BASE_QUERY = (1 << 4)
} joined_parts;
 
assert(base != NULL);
assert(rel != NULL);
 
/* Peg out the URL sections */
nsurl__get_string_markers(rel, &m, true);
 
/* Get the length of the longest section */
length = nsurl__get_longest_section(&m);
 
/* Initially assume that the joined URL can be formed entierly from
* the relative URL. */
joined_parts = NSURL_F_REL;
 
/* Update joined_compnents to indicate any required parts from the
* base URL. */
if (m.scheme_end - m.start <= 0) {
/* The relative url has no scheme.
* Use base URL's scheme. */
joined_parts |= NSURL_F_BASE_SCHEME;
 
if (m.path - m.authority <= 0) {
/* The relative URL has no authority.
* Use base URL's authority. */
joined_parts |= NSURL_F_BASE_AUTHORITY;
 
if (m.query - m.path <= 0) {
/* The relative URL has no path.
* Use base URL's path. */
joined_parts |= NSURL_F_BASE_PATH;
 
if (m.fragment - m.query <= 0) {
/* The relative URL has no query.
* Use base URL's query. */
joined_parts |= NSURL_F_BASE_QUERY;
}
 
} else if (*(rel + m.path) != '/') {
/* Relative URL has relative path */
joined_parts |= NSURL_F_MERGED_PATH;
}
}
}
 
/* Allocate enough memory to url escape the longest section, plus
* space for path merging (if required). */
if (joined_parts & NSURL_F_MERGED_PATH) {
/* Need to merge paths */
length += (base->components.path != NULL) ?
lwc_string_length(base->components.path) : 0;
}
length *= 4;
/* Plus space for removing dots from path */
length += (m.query - m.path) + ((base->components.path != NULL) ?
lwc_string_length(base->components.path) : 0);
 
buff = malloc(length + 5);
if (buff == NULL)
return NSERROR_NOMEM;
 
buff_pos = buff;
 
/* Form joined URL from base or rel components, as appropriate */
 
if (joined_parts & NSURL_F_BASE_SCHEME) {
c.scheme_type = base->components.scheme_type;
 
c.scheme = nsurl__component_copy(base->components.scheme);
} else {
c.scheme_type = m.scheme_type;
 
error |= nsurl__create_from_section(rel, URL_SCHEME, &m,
buff, &c);
}
 
if (joined_parts & NSURL_F_BASE_AUTHORITY) {
c.username = nsurl__component_copy(base->components.username);
c.password = nsurl__component_copy(base->components.password);
c.host = nsurl__component_copy(base->components.host);
c.port = nsurl__component_copy(base->components.port);
} else {
error |= nsurl__create_from_section(rel, URL_CREDENTIALS, &m,
buff, &c);
error |= nsurl__create_from_section(rel, URL_HOST, &m,
buff, &c);
}
 
if (joined_parts & NSURL_F_BASE_PATH) {
c.path = nsurl__component_copy(base->components.path);
 
} else if (joined_parts & NSURL_F_MERGED_PATH) {
struct url_markers m_path;
size_t new_length;
 
if (base->components.host != NULL &&
base->components.path == NULL) {
/* Append relative path to "/". */
*(buff_pos++) = '/';
memcpy(buff_pos, rel + m.path, m.query - m.path);
buff_pos += m.query - m.path;
 
} else {
/* Append relative path to all but last segment of
* base path. */
size_t path_end = lwc_string_length(
base->components.path);
const char *path = lwc_string_data(
base->components.path);
 
while (*(path + path_end) != '/' &&
path_end != 0) {
path_end--;
}
if (*(path + path_end) == '/')
path_end++;
 
/* Copy the base part */
memcpy(buff_pos, path, path_end);
buff_pos += path_end;
 
/* Copy the relative part */
memcpy(buff_pos, rel + m.path, m.query - m.path);
buff_pos += m.query - m.path;
}
 
/* add termination to string */
*buff_pos++ = '\0';
 
new_length = nsurl__remove_dot_segments(buff, buff_pos);
 
m_path.path = 0;
m_path.query = new_length;
 
buff_start = buff_pos + new_length;
error |= nsurl__create_from_section(buff_pos, URL_PATH, &m_path,
buff_start, &c);
 
} else {
struct url_markers m_path;
size_t new_length;
 
memcpy(buff_pos, rel + m.path, m.query - m.path);
buff_pos += m.query - m.path;
*(buff_pos++) = '\0';
 
new_length = nsurl__remove_dot_segments(buff, buff_pos);
 
m_path.path = 0;
m_path.query = new_length;
 
buff_start = buff_pos + new_length;
error |= nsurl__create_from_section(buff_pos, URL_PATH, &m_path,
buff_start, &c);
}
 
if (joined_parts & NSURL_F_BASE_QUERY)
c.query = nsurl__component_copy(base->components.query);
else
error |= nsurl__create_from_section(rel, URL_QUERY, &m,
buff, &c);
 
error |= nsurl__create_from_section(rel, URL_FRAGMENT, &m,
buff, &c);
 
/* Free temporary buffer */
free(buff);
 
if (error != NSERROR_OK)
return NSERROR_NOMEM;
 
/* Get the string length and find which parts of url are present */
nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
&str_len, &str_flags);
 
/* Create NetSurf URL object */
*joined = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
if (*joined == NULL)
return NSERROR_NOMEM;
 
(*joined)->components = c;
(*joined)->length = length;
 
/* Fill out the url string */
nsurl_get_string(&c, (*joined)->string, &str_len, str_flags);
 
/* Give the URL a reference */
(*joined)->count = 1;
 
return NSERROR_OK;
}
 
 
/* exported interface, documented in nsurl.h */
nserror nsurl_defragment(const nsurl *url, nsurl **no_frag)
{
size_t length;
char *pos;
 
/* Find the change in length from url to new_url */
length = url->length;
if (url->components.fragment != NULL) {
length -= 1 + lwc_string_length(url->components.fragment);
}
 
/* Create NetSurf URL object */
*no_frag = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
if (*no_frag == NULL) {
return NSERROR_NOMEM;
}
 
/* Copy components */
(*no_frag)->components.scheme =
nsurl__component_copy(url->components.scheme);
(*no_frag)->components.username =
nsurl__component_copy(url->components.username);
(*no_frag)->components.password =
nsurl__component_copy(url->components.password);
(*no_frag)->components.host =
nsurl__component_copy(url->components.host);
(*no_frag)->components.port =
nsurl__component_copy(url->components.port);
(*no_frag)->components.path =
nsurl__component_copy(url->components.path);
(*no_frag)->components.query =
nsurl__component_copy(url->components.query);
(*no_frag)->components.fragment = NULL;
 
(*no_frag)->components.scheme_type = url->components.scheme_type;
 
(*no_frag)->length = length;
 
/* Fill out the url string */
pos = (*no_frag)->string;
memcpy(pos, url->string, length);
pos += length;
*pos = '\0';
 
/* Give the URL a reference */
(*no_frag)->count = 1;
 
return NSERROR_OK;
}
 
 
/* exported interface, documented in nsurl.h */
nserror nsurl_refragment(const nsurl *url, lwc_string *frag, nsurl **new_url)
{
int frag_len;
int base_len;
char *pos;
size_t len;
 
assert(url != NULL);
assert(frag != NULL);
 
/* Find the change in length from url to new_url */
base_len = url->length;
if (url->components.fragment != NULL) {
base_len -= 1 + lwc_string_length(url->components.fragment);
}
frag_len = lwc_string_length(frag);
 
/* Set new_url's length */
len = base_len + 1 /* # */ + frag_len;
 
/* Create NetSurf URL object */
*new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
if (*new_url == NULL) {
return NSERROR_NOMEM;
}
 
(*new_url)->length = len;
 
/* Set string */
pos = (*new_url)->string;
memcpy(pos, url->string, base_len);
pos += base_len;
*pos = '#';
memcpy(++pos, lwc_string_data(frag), frag_len);
pos += frag_len;
*pos = '\0';
 
/* Copy components */
(*new_url)->components.scheme =
nsurl__component_copy(url->components.scheme);
(*new_url)->components.username =
nsurl__component_copy(url->components.username);
(*new_url)->components.password =
nsurl__component_copy(url->components.password);
(*new_url)->components.host =
nsurl__component_copy(url->components.host);
(*new_url)->components.port =
nsurl__component_copy(url->components.port);
(*new_url)->components.path =
nsurl__component_copy(url->components.path);
(*new_url)->components.query =
nsurl__component_copy(url->components.query);
(*new_url)->components.fragment =
lwc_string_ref(frag);
 
(*new_url)->components.scheme_type = url->components.scheme_type;
 
/* Give the URL a reference */
(*new_url)->count = 1;
 
return NSERROR_OK;
}
 
 
/* exported interface, documented in nsurl.h */
nserror nsurl_replace_query(const nsurl *url, const char *query,
nsurl **new_url)
{
int query_len;
int base_len;
char *pos;
size_t len;
lwc_string *lwc_query;
 
assert(url != NULL);
assert(query != NULL);
assert(query[0] == '?');
 
/* Get the length of the new query */
query_len = strlen(query);
 
/* Find the change in length from url to new_url */
base_len = url->length;
if (url->components.query != NULL) {
base_len -= lwc_string_length(url->components.query);
}
if (url->components.fragment != NULL) {
base_len -= 1 + lwc_string_length(url->components.fragment);
}
 
/* Set new_url's length */
len = base_len + query_len;
 
/* Create NetSurf URL object */
*new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
if (*new_url == NULL) {
return NSERROR_NOMEM;
}
 
if (lwc_intern_string(query, query_len, &lwc_query) != lwc_error_ok) {
free(*new_url);
return NSERROR_NOMEM;
}
 
(*new_url)->length = len;
 
/* Set string */
pos = (*new_url)->string;
memcpy(pos, url->string, base_len);
pos += base_len;
memcpy(pos, query, query_len);
pos += query_len;
if (url->components.fragment != NULL) {
const char *frag = lwc_string_data(url->components.fragment);
size_t frag_len = lwc_string_length(url->components.fragment);
*pos = '#';
memcpy(++pos, frag, frag_len);
pos += frag_len;
}
*pos = '\0';
 
/* Copy components */
(*new_url)->components.scheme =
nsurl__component_copy(url->components.scheme);
(*new_url)->components.username =
nsurl__component_copy(url->components.username);
(*new_url)->components.password =
nsurl__component_copy(url->components.password);
(*new_url)->components.host =
nsurl__component_copy(url->components.host);
(*new_url)->components.port =
nsurl__component_copy(url->components.port);
(*new_url)->components.path =
nsurl__component_copy(url->components.path);
(*new_url)->components.query = lwc_query;
(*new_url)->components.fragment =
nsurl__component_copy(url->components.fragment);
 
(*new_url)->components.scheme_type = url->components.scheme_type;
 
/* Give the URL a reference */
(*new_url)->count = 1;
 
return NSERROR_OK;
}
 
 
/* exported interface, documented in nsurl.h */
nserror nsurl_parent(const nsurl *url, nsurl **new_url)
{
lwc_string *lwc_path;
size_t old_path_len, new_path_len;
size_t len;
const char* path = NULL;
char *pos;
 
assert(url != NULL);
 
old_path_len = (url->components.path == NULL) ? 0 :
lwc_string_length(url->components.path);
 
/* Find new path length */
if (old_path_len == 0) {
new_path_len = old_path_len;
} else {
path = lwc_string_data(url->components.path);
 
new_path_len = old_path_len;
if (old_path_len > 1) {
/* Skip over any trailing / */
if (path[new_path_len - 1] == '/')
new_path_len--;
 
/* Work back to next / */
while (new_path_len > 0 &&
path[new_path_len - 1] != '/')
new_path_len--;
}
}
 
/* Find the length of new_url */
len = url->length;
if (url->components.query != NULL) {
len -= lwc_string_length(url->components.query);
}
if (url->components.fragment != NULL) {
len -= 1; /* # */
len -= lwc_string_length(url->components.fragment);
}
len -= old_path_len - new_path_len;
 
/* Create NetSurf URL object */
*new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
if (*new_url == NULL) {
return NSERROR_NOMEM;
}
 
/* Make new path */
if (old_path_len == 0) {
lwc_path = NULL;
} else if (old_path_len == new_path_len) {
lwc_path = lwc_string_ref(url->components.path);
} else {
if (lwc_intern_string(path, old_path_len - new_path_len,
&lwc_path) != lwc_error_ok) {
free(*new_url);
return NSERROR_NOMEM;
}
}
 
(*new_url)->length = len;
 
/* Set string */
pos = (*new_url)->string;
memcpy(pos, url->string, len);
pos += len;
*pos = '\0';
 
/* Copy components */
(*new_url)->components.scheme =
nsurl__component_copy(url->components.scheme);
(*new_url)->components.username =
nsurl__component_copy(url->components.username);
(*new_url)->components.password =
nsurl__component_copy(url->components.password);
(*new_url)->components.host =
nsurl__component_copy(url->components.host);
(*new_url)->components.port =
nsurl__component_copy(url->components.port);
(*new_url)->components.path = lwc_path;
(*new_url)->components.query = NULL;
(*new_url)->components.fragment = NULL;
 
(*new_url)->components.scheme_type = url->components.scheme_type;
 
/* Give the URL a reference */
(*new_url)->count = 1;
 
return NSERROR_OK;
}
 
/programs/network/netsurf/netsurf/utils/nsurl.h
0,0 → 1,294
/*
* Copyright 2011 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* NetSurf URL handling (interface).
*/
 
#ifndef _NETSURF_UTILS_NSURL_H_
#define _NETSURF_UTILS_NSURL_H_
 
#include <libwapcaplet/libwapcaplet.h>
#include "utils/errors.h"
 
 
/** NetSurf URL object */
typedef struct nsurl nsurl;
 
 
typedef enum nsurl_component {
NSURL_SCHEME = (1 << 0),
NSURL_USERNAME = (1 << 1),
NSURL_PASSWORD = (1 << 2),
NSURL_CREDENTIALS = NSURL_USERNAME | NSURL_PASSWORD,
NSURL_HOST = (1 << 3),
NSURL_PORT = (1 << 4),
NSURL_AUTHORITY = NSURL_CREDENTIALS | NSURL_HOST | NSURL_PORT,
NSURL_PATH = (1 << 5),
NSURL_QUERY = (1 << 6),
NSURL_COMPLETE = NSURL_SCHEME | NSURL_AUTHORITY |
NSURL_PATH | NSURL_QUERY,
NSURL_FRAGMENT = (1 << 7),
NSURL_WITH_FRAGMENT = NSURL_COMPLETE | NSURL_FRAGMENT
} nsurl_component;
 
 
/**
* Create a NetSurf URL object from a URL string
*
* \param url_s String to create NetSurf URL from
* \param url Returns a NetSurf URL
* \return NSERROR_OK on success, appropriate error otherwise
*
* If return value != NSERROR_OK, nothing will be returned in url.
*
* It is up to the client to call nsurl_destroy when they are finished with
* the created object.
*/
nserror nsurl_create(const char * const url_s, nsurl **url);
 
 
/**
* Increment the reference count to a NetSurf URL object
*
* \param url NetSurf URL to create another reference to
* \return The NetSurf URL pointer to use as the copy
*
* Use this when copying a NetSurf URL into a persistent data structure.
*/
nsurl *nsurl_ref(nsurl *url);
 
 
/**
* Drop a reference to a NetSurf URL object
*
* \param url NetSurf URL to drop reference to
*
* When the reference count reaches zero then the NetSurf URL will be destroyed
*/
void nsurl_unref(nsurl *url);
 
 
/**
* Compare two URLs
*
* \param url1 First NetSurf URL
* \param url2 Second NetSurf URL
* \param parts The URL components to be compared
* \param match Returns true if url1 and url2 matched, else false
* \return NSERROR_OK on success, appropriate error otherwise
*
* If return value != NSERROR_OK, match will be false.
*/
bool nsurl_compare(const nsurl *url1, const nsurl *url2, nsurl_component parts);
 
 
/**
* Get URL (section) as a string, from a NetSurf URL object
*
* \param url NetSurf URL
* \param parts The required URL components.
* \param url_s Returns a url string
* \param url_l Returns length of url_s
* \return NSERROR_OK on success, appropriate error otherwise
*
* If return value != NSERROR_OK, nothing will be returned in url_s or url_l.
*
* The string returned in url_s is owned by the client and it is up to them
* to free it. It includes a trailing '\0'.
*
* The length returned in url_l excludes the trailing '\0'.
*
* That the required URL components be consecutive is not enforced, however,
* non-consecutive URL components generally make no sense. The exception
* is removal of credentials from a URL, such as for display in browser
* window URL bar. 'NSURL_COMPLETE &~ NSURL_PASSWORD' would remove the
* password from a complete URL.
*/
nserror nsurl_get(const nsurl *url, nsurl_component parts,
char **url_s, size_t *url_l);
 
 
/**
* Get part of a URL as a lwc_string, from a NetSurf URL object
*
* \param url NetSurf URL object
* \param part The URL component required
* \return the required component as an lwc_string, or NULL
*
* The caller owns the returned lwc_string and should call lwc_string_unref
* when they are done with it.
*
* The valid values for the part parameter are:
* NSURL_SCHEME
* NSURL_USERNAME
* NSURL_PASSWORD
* NSURL_HOST
* NSURL_PORT
* NSURL_PATH
* NSURL_QUERY
* NSURL_FRAGMENT
*/
lwc_string *nsurl_get_component(const nsurl *url, nsurl_component part);
 
 
/**
* Enquire about the existence of componenets in a given URL
*
* \param url NetSurf URL object
* \param part The URL components confirm existence of
* \return true iff the component in question exists in url
*
* The valid values for the part parameter are:
* NSURL_SCHEME
* NSURL_USERNAME
* NSURL_PASSWORD
* NSURL_CREDENTIALS
* NSURL_HOST
* NSURL_PORT
* NSURL_PATH
* NSURL_QUERY
* NSURL_FRAGMENT
*/
bool nsurl_has_component(const nsurl *url, nsurl_component part);
 
 
/**
* Access a NetSurf URL object as a string
*
* \param url NetSurf URL to retrieve a string pointer for.
* \return the required string
*
* The returned string is owned by the NetSurf URL object. It will die
* with the NetSurf URL object. Keep a reference to the URL if you need it.
*
* The returned string has a trailing '\0'.
*/
const char *nsurl_access(const nsurl *url);
 
 
/**
* Access a URL's path leaf as a string
*
* \param url NetSurf URL to retrieve a string pointer for.
* \return the required string
*
* The returned string is owned by the NetSurf URL object. It will die
* with the NetSurf URL object. Keep a reference to the URL if you need it.
*
* The returned string has a trailing '\0'.
*/
const char *nsurl_access_leaf(const nsurl *url);
 
 
/**
* Find the length of a NetSurf URL object's URL, as returned by nsurl_access
*
* \param url NetSurf URL to find length of.
* \return the required string
*
* The returned length excludes the trailing '\0'.
*/
size_t nsurl_length(const nsurl *url);
 
 
/**
* Join a base url to a relative link part, creating a new NetSurf URL object
*
* \param base NetSurf URL containing the base to join rel to
* \param rel String containing the relative link part
* \param joined Returns joined NetSurf URL
* \return NSERROR_OK on success, appropriate error otherwise
*
* If return value != NSERROR_OK, nothing will be returned in join.
*
* It is up to the client to call nsurl_destroy when they are finished with
* the created object.
*/
nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined);
 
 
/**
* Create a NetSurf URL object without a fragment from a NetSurf URL
*
* \param url NetSurf URL to create new NetSurf URL from
* \param no_frag Returns new NetSurf URL without fragment
* \return NSERROR_OK on success, appropriate error otherwise
*
* If return value != NSERROR_OK, nothing will be returned in no_frag.
*
* It is up to the client to call nsurl_destroy when they are finished with
* the created object.
*/
nserror nsurl_defragment(const nsurl *url, nsurl **no_frag);
 
 
/**
* Create a NetSurf URL object, adding a fragment to an existing URL object
*
* \param url NetSurf URL to create new NetSurf URL from
* \param frag Fragment to add
* \param new_url Returns new NetSurf URL without fragment
* \return NSERROR_OK on success, appropriate error otherwise
*
* If return value != NSERROR_OK, nothing will be returned in new_url.
*
* It is up to the client to call nsurl_destroy when they are finished with
* the created object.
*
* Any fragment in url is replaced with frag in new_url.
*/
nserror nsurl_refragment(const nsurl *url, lwc_string *frag, nsurl **new_url);
 
 
/**
* Create a NetSurf URL object, with query string replaced
*
* \param url NetSurf URL to create new NetSurf URL from
* \param query Query string to use
* \param new_url Returns new NetSurf URL with query string provided
* \return NSERROR_OK on success, appropriate error otherwise
*
* If return value != NSERROR_OK, nothing will be returned in new_url.
*
* It is up to the client to call nsurl_destroy when they are finished with
* the created object.
*
* Any query component in url is replaced with query in new_url.
*/
nserror nsurl_replace_query(const nsurl *url, const char *query,
nsurl **new_url);
 
 
/**
* Create a NetSurf URL object for URL with parent location of an existing URL.
*
* \param url NetSurf URL to create new NetSurf URL from
* \param new_url Returns new NetSurf URL with parent URL path
* \return NSERROR_OK on success, appropriate error otherwise
*
* If return value != NSERROR_OK, nothing will be returned in new_url.
*
* It is up to the client to call nsurl_destroy when they are finished with
* the created object.
*
* As well as stripping top most path segment, query and fragments are stripped.
*/
nserror nsurl_parent(const nsurl *url, nsurl **new_url);
 
#endif
/programs/network/netsurf/netsurf/utils/ring.h
0,0 → 1,174
/*
* Copyright 2006, 2007 Daniel Silverstone <dsilvers@digital-scurf.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Ring list structure.
*
* Rings are structures which have an r_next pointer and an r_prev
* pointer which are always initialised and always point at the next
* or previous element respectively.
*
* The degenerate case of a single element in the ring simply points
* at itself in both directions. A zero element ring is NULL.
*
* Some of the ring functions are specific to the fetcher but may be
* of use to others and are thus included here.
*/
 
#ifndef _NETSURF_UTILS_RING_H_
#define _NETSURF_UTILS_RING_H_
 
 
/** Insert the given item into the specified ring.
* Assumes that the element is zeroed as appropriate.
*/
#define RING_INSERT(ring,element) \
/*LOG(("RING_INSERT(%s, %p(%s))", #ring, element, element->host));*/ \
if (ring) { \
element->r_next = ring; \
element->r_prev = ring->r_prev; \
ring->r_prev = element; \
element->r_prev->r_next = element; \
} else \
ring = element->r_prev = element->r_next = element
 
/** Remove the given element from the specified ring.
* Will zero the element as needed
*/
#define RING_REMOVE(ring, element) \
/*LOG(("RING_REMOVE(%s, %p(%s)", #ring, element, element->host));*/ \
if (element->r_next != element ) { \
/* Not the only thing in the ring */ \
element->r_next->r_prev = element->r_prev; \
element->r_prev->r_next = element->r_next; \
if (ring == element) ring = element->r_next; \
} else { \
/* Only thing in the ring */ \
ring = 0; \
} \
element->r_next = element->r_prev = 0
 
/** Find the element (by hostname) in the given ring, leave it in the
* provided element variable
*/
#define RING_FINDBYHOST(ring, element, hostname) \
/*LOG(("RING_FINDBYHOST(%s, %s)", #ring, hostname));*/ \
if (ring) { \
bool found = false; \
element = ring; \
do { \
if (strcasecmp(element->host, hostname) == 0) { \
found = true; \
break; \
} \
element = element->r_next; \
} while (element != ring); \
if (!found) element = 0; \
} else element = 0
 
/** Find the element (by hostname) in the given ring, leave it in the
* provided element variable
*/
#define RING_FINDBYLWCHOST(ring, element, lwc_hostname) \
/*LOG(("RING_FINDBYHOST(%s, %s)", #ring, hostname));*/ \
if (ring) { \
bool found = false; \
element = ring; \
do { \
if (lwc_string_isequal(element->host, lwc_hostname, \
&found) == lwc_error_ok && \
found == true) { \
break; \
} \
element = element->r_next; \
} while (element != ring); \
if (!found) element = 0; \
} else element = 0
 
/** Measure the size of a ring and put it in the supplied variable */
#define RING_GETSIZE(ringtype, ring, sizevar) \
/*LOG(("RING_GETSIZE(%s)", #ring));*/ \
if (ring) { \
ringtype *p = ring; \
sizevar = 0; \
do { \
sizevar++; \
p = p->r_next; \
} while (p != ring); \
} else sizevar = 0
 
/** Count the number of elements in the ring which match the provided hostname */
#define RING_COUNTBYHOST(ringtype, ring, sizevar, hostname) \
/*LOG(("RING_COUNTBYHOST(%s, %s)", #ring, hostname));*/ \
if (ring) { \
ringtype *p = ring; \
sizevar = 0; \
do { \
if (strcasecmp(p->host, hostname) == 0) \
sizevar++; \
p = p->r_next; \
} while (p != ring); \
} else sizevar = 0
 
/** Count the number of elements in the ring which match the provided lwc_hostname */
#define RING_COUNTBYLWCHOST(ringtype, ring, sizevar, lwc_hostname) \
/*LOG(("RING_COUNTBYHOST(%s, %s)", #ring, hostname));*/ \
if (ring) { \
ringtype *p = ring; \
sizevar = 0; \
do { \
bool matches = false; \
/* nsurl guarantees lowercase host */ \
if (lwc_string_isequal(p->host, lwc_hostname, \
&matches) == lwc_error_ok) \
if (matches) \
sizevar++; \
p = p->r_next; \
} while (p != ring); \
} else sizevar = 0
 
/*
* Ring iteration works as follows:
*
* RING_ITERATE_START(ringtype, ring, iteratorptr) {
* code_using(iteratorptr);
* } RING_ITERATE_END(ring, iteratorptr);
*
* If you want to stop iterating (e.g. you found your answer)
* RING_ITERATE_STOP(ring, iteratorptr);
* You *MUST* abort the iteration if you do something to modify
* the ring such as deleting or adding an element.
*/
 
#define RING_ITERATE_START(ringtype, ring, iteratorptr) \
if (ring != NULL) { \
ringtype *iteratorptr = ring; \
do { \
do { \
#define RING_ITERATE_STOP(ring, iteratorptr) \
goto iteration_end_ring##_##iteratorptr
 
#define RING_ITERATE_END(ring, iteratorptr) \
} while (false); \
iteratorptr = iteratorptr->r_next; \
} while (iteratorptr != ring); \
} \
iteration_end_ring##_##iteratorptr:
 
#endif
/programs/network/netsurf/netsurf/utils/schedule.h
0,0 → 1,32
/*
* Copyright 2011 Daniel Silverstone <dsilvers@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Job scheduler (interface).
*/
 
#ifndef _NETSURF_UTILS_SCHEDULE_H_
#define _NETSURF_UTILS_SCHEDULE_H_
 
/* In platform specific schedule.c. */
typedef void (*schedule_callback_fn)(void *p);
 
void schedule(int t, schedule_callback_fn callback, void *p);
void schedule_remove(schedule_callback_fn callback, void *p);
 
#endif
/programs/network/netsurf/netsurf/utils/split-messages.pl
0,0 → 1,23
#!/usr/bin/perl -w
 
use strict;
 
die "usage: split-messages <langname> <platname> < FatMessages > ThinMessages" if ($#ARGV != 1);
 
my $langname = $ARGV[0];
my $platname = $ARGV[1];
 
my $allprefix = $langname . ".all.";
my $platprefix = $langname . "." . $platname . ".";
 
print "# This messages file is automatically generated from FatMessages\n";
print "# at build-time. Please go and edit that instead of this.\n\n";
 
foreach (<STDIN>) {
if (not /^#/ and not /^\s*$/) {
if (/^$allprefix/ or /^$platprefix/) {
s/^$langname\.(all|$platname)\.//;
print "$_";
}
}
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/programs/network/netsurf/netsurf/utils/talloc.c
0,0 → 1,1435
/*
Samba Unix SMB/CIFS implementation.
 
Samba trivial allocation library - new interface
 
NOTE: Please read talloc_guide.txt for full documentation
 
Copyright (C) Andrew Tridgell 2004
Copyright (C) Stefan Metzmacher 2006
** NOTE! The following LGPL license applies to the talloc
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
 
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
 
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
 
/*
inspired by http://swapped.cc/halloc/
*/
 
#ifdef _SAMBA_BUILD_
#include "version.h"
#if (SAMBA_VERSION_MAJOR<4)
#include "includes.h"
/* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file
* we trust ourselves... */
#ifdef malloc
#undef malloc
#endif
#ifdef realloc
#undef realloc
#endif
#define _TALLOC_SAMBA3
#endif /* (SAMBA_VERSION_MAJOR<4) */
#endif /* _SAMBA_BUILD_ */
 
/* jmb -- allow this to build standalone */
#define STANDALONE
 
#ifndef _TALLOC_SAMBA3
#ifndef STANDALONE
#include "replace.h"
#else
#include <stdarg.h>
#if !defined(__BEOS__) && !defined(__HAIKU__) && __GNUC__ > 2
/* Assume we've got va_copy */
#define HAVE_VA_COPY
#include <string.h>
#endif
#endif
#include "talloc.h"
#endif /* not _TALLOC_SAMBA3 */
 
/* use this to force every realloc to change the pointer, to stress test
code that might not cope */
#define ALWAYS_REALLOC 0
 
 
#define MAX_TALLOC_SIZE 0x10000000
#define TALLOC_MAGIC 0xe814ec70
#define TALLOC_FLAG_FREE 0x01
#define TALLOC_FLAG_LOOP 0x02
#define TALLOC_MAGIC_REFERENCE ((const char *)1)
 
/* by default we abort when given a bad pointer (such as when talloc_free() is called
on a pointer that came from malloc() */
#ifndef TALLOC_ABORT
#define TALLOC_ABORT(reason) abort()
#endif
 
#ifndef discard_const_p
#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
#else
# define discard_const_p(type, ptr) ((type *)(ptr))
#endif
#endif
 
/* these macros gain us a few percent of speed on gcc */
#if (__GNUC__ >= 3)
/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
as its first argument */
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) x
#define unlikely(x) x
#endif
 
/* this null_context is only used if talloc_enable_leak_report() or
talloc_enable_leak_report_full() is called, otherwise it remains
NULL
*/
static void *null_context;
static void *autofree_context;
 
struct talloc_reference_handle {
struct talloc_reference_handle *next, *prev;
void *ptr;
};
 
typedef int (*talloc_destructor_t)(void *);
 
struct talloc_chunk {
struct talloc_chunk *next, *prev;
struct talloc_chunk *parent, *child;
struct talloc_reference_handle *refs;
talloc_destructor_t destructor;
const char *name;
size_t size;
unsigned flags;
};
 
/* 16 byte alignment seems to keep everyone happy */
#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
 
/* panic if we get a bad magic value */
static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
{
const void *pp = ((const char *)ptr) - TC_HDR_SIZE;
struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp);
if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) {
if (tc->flags & TALLOC_FLAG_FREE) {
TALLOC_ABORT("Bad talloc magic value - double free");
} else {
TALLOC_ABORT("Bad talloc magic value - unknown value");
}
}
return tc;
}
 
/* hook into the front of the list */
#define _TLIST_ADD(list, p) \
do { \
if (!(list)) { \
(list) = (p); \
(p)->next = (p)->prev = NULL; \
} else { \
(list)->prev = (p); \
(p)->next = (list); \
(p)->prev = NULL; \
(list) = (p); \
}\
} while (0)
 
/* remove an element from a list - element doesn't have to be in list. */
#define _TLIST_REMOVE(list, p) \
do { \
if ((p) == (list)) { \
(list) = (p)->next; \
if (list) (list)->prev = NULL; \
} else { \
if ((p)->prev) (p)->prev->next = (p)->next; \
if ((p)->next) (p)->next->prev = (p)->prev; \
} \
if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
} while (0)
 
 
/*
return the parent chunk of a pointer
*/
static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
{
struct talloc_chunk *tc;
 
if (unlikely(ptr == NULL)) {
return NULL;
}
 
tc = talloc_chunk_from_ptr(ptr);
while (tc->prev) tc=tc->prev;
 
return tc->parent;
}
 
void *talloc_parent(const void *ptr)
{
struct talloc_chunk *tc = talloc_parent_chunk(ptr);
return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
}
 
/*
find parents name
*/
const char *talloc_parent_name(const void *ptr)
{
struct talloc_chunk *tc = talloc_parent_chunk(ptr);
return tc? tc->name : NULL;
}
 
/*
Allocate a bit of memory as a child of an existing pointer
*/
static inline void *__talloc(const void *context, size_t size)
{
struct talloc_chunk *tc;
 
if (unlikely(context == NULL)) {
context = null_context;
}
 
if (unlikely(size >= MAX_TALLOC_SIZE)) {
return NULL;
}
 
tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
if (unlikely(tc == NULL)) return NULL;
 
tc->size = size;
tc->flags = TALLOC_MAGIC;
tc->destructor = NULL;
tc->child = NULL;
tc->name = NULL;
tc->refs = NULL;
 
if (likely(context)) {
struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
 
if (parent->child) {
parent->child->parent = NULL;
tc->next = parent->child;
tc->next->prev = tc;
} else {
tc->next = NULL;
}
tc->parent = parent;
tc->prev = NULL;
parent->child = tc;
} else {
tc->next = tc->prev = tc->parent = NULL;
}
 
return TC_PTR_FROM_CHUNK(tc);
}
 
/*
setup a destructor to be called on free of a pointer
the destructor should return 0 on success, or -1 on failure.
if the destructor fails then the free is failed, and the memory can
be continued to be used
*/
void _talloc_set_destructor(const void *ptr, int (*destructor)(void *))
{
struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
tc->destructor = destructor;
}
 
/*
increase the reference count on a piece of memory.
*/
int talloc_increase_ref_count(const void *ptr)
{
if (unlikely(!talloc_reference(null_context, ptr))) {
return -1;
}
return 0;
}
 
/*
helper for talloc_reference()
 
this is referenced by a function pointer and should not be inline
*/
static int talloc_reference_destructor(struct talloc_reference_handle *handle)
{
struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
_TLIST_REMOVE(ptr_tc->refs, handle);
return 0;
}
 
/*
more efficient way to add a name to a pointer - the name must point to a
true string constant
*/
static inline void _talloc_set_name_const(const void *ptr, const char *name)
{
struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
tc->name = name;
}
 
/*
internal talloc_named_const()
*/
static inline void *_talloc_named_const(const void *context, size_t size, const char *name)
{
void *ptr;
 
ptr = __talloc(context, size);
if (unlikely(ptr == NULL)) {
return NULL;
}
 
_talloc_set_name_const(ptr, name);
 
return ptr;
}
 
/*
make a secondary reference to a pointer, hanging off the given context.
the pointer remains valid until both the original caller and this given
context are freed.
the major use for this is when two different structures need to reference the
same underlying data, and you want to be able to free the two instances separately,
and in either order
*/
void *_talloc_reference(const void *context, const void *ptr)
{
struct talloc_chunk *tc;
struct talloc_reference_handle *handle;
if (unlikely(ptr == NULL)) return NULL;
 
tc = talloc_chunk_from_ptr(ptr);
handle = (struct talloc_reference_handle *)_talloc_named_const(context,
sizeof(struct talloc_reference_handle),
TALLOC_MAGIC_REFERENCE);
if (unlikely(handle == NULL)) return NULL;
 
/* note that we hang the destructor off the handle, not the
main context as that allows the caller to still setup their
own destructor on the context if they want to */
talloc_set_destructor(handle, talloc_reference_destructor);
handle->ptr = discard_const_p(void, ptr);
_TLIST_ADD(tc->refs, handle);
return handle->ptr;
}
 
 
/*
internal talloc_free call
*/
static inline int _talloc_free(void *ptr)
{
struct talloc_chunk *tc;
 
if (unlikely(ptr == NULL)) {
return -1;
}
 
tc = talloc_chunk_from_ptr(ptr);
 
if (unlikely(tc->refs)) {
int is_child;
/* check this is a reference from a child or grantchild
* back to it's parent or grantparent
*
* in that case we need to remove the reference and
* call another instance of talloc_free() on the current
* pointer.
*/
is_child = talloc_is_parent(tc->refs, ptr);
_talloc_free(tc->refs);
if (is_child) {
return _talloc_free(ptr);
}
return -1;
}
 
if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
/* we have a free loop - stop looping */
return 0;
}
 
if (unlikely(tc->destructor)) {
talloc_destructor_t d = tc->destructor;
if (d == (talloc_destructor_t)-1) {
return -1;
}
tc->destructor = (talloc_destructor_t)-1;
if (d(ptr) == -1) {
tc->destructor = d;
return -1;
}
tc->destructor = NULL;
}
 
if (tc->parent) {
_TLIST_REMOVE(tc->parent->child, tc);
if (tc->parent->child) {
tc->parent->child->parent = tc->parent;
}
} else {
if (tc->prev) tc->prev->next = tc->next;
if (tc->next) tc->next->prev = tc->prev;
}
 
tc->flags |= TALLOC_FLAG_LOOP;
 
while (tc->child) {
/* we need to work out who will own an abandoned child
if it cannot be freed. In priority order, the first
choice is owner of any remaining reference to this
pointer, the second choice is our parent, and the
final choice is the null context. */
void *child = TC_PTR_FROM_CHUNK(tc->child);
const void *new_parent = null_context;
if (unlikely(tc->child->refs)) {
struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
if (p) new_parent = TC_PTR_FROM_CHUNK(p);
}
if (unlikely(_talloc_free(child) == -1)) {
if (new_parent == null_context) {
struct talloc_chunk *p = talloc_parent_chunk(ptr);
if (p) new_parent = TC_PTR_FROM_CHUNK(p);
}
(void) talloc_steal(new_parent, child);
}
}
 
tc->flags |= TALLOC_FLAG_FREE;
free(tc);
return 0;
}
 
/*
move a lump of memory from one talloc context to another return the
ptr on success, or NULL if it could not be transferred.
passing NULL as ptr will always return NULL with no side effects.
*/
void *_talloc_steal(const void *new_ctx, const void *ptr)
{
struct talloc_chunk *tc, *new_tc;
 
if (unlikely(!ptr)) {
return NULL;
}
 
if (unlikely(new_ctx == NULL)) {
new_ctx = null_context;
}
 
tc = talloc_chunk_from_ptr(ptr);
 
if (unlikely(new_ctx == NULL)) {
if (tc->parent) {
_TLIST_REMOVE(tc->parent->child, tc);
if (tc->parent->child) {
tc->parent->child->parent = tc->parent;
}
} else {
if (tc->prev) tc->prev->next = tc->next;
if (tc->next) tc->next->prev = tc->prev;
}
tc->parent = tc->next = tc->prev = NULL;
return discard_const_p(void, ptr);
}
 
new_tc = talloc_chunk_from_ptr(new_ctx);
 
if (unlikely(tc == new_tc || tc->parent == new_tc)) {
return discard_const_p(void, ptr);
}
 
if (tc->parent) {
_TLIST_REMOVE(tc->parent->child, tc);
if (tc->parent->child) {
tc->parent->child->parent = tc->parent;
}
} else {
if (tc->prev) tc->prev->next = tc->next;
if (tc->next) tc->next->prev = tc->prev;
}
 
tc->parent = new_tc;
if (new_tc->child) new_tc->child->parent = NULL;
_TLIST_ADD(new_tc->child, tc);
 
return discard_const_p(void, ptr);
}
 
 
 
/*
remove a secondary reference to a pointer. This undo's what
talloc_reference() has done. The context and pointer arguments
must match those given to a talloc_reference()
*/
static inline int talloc_unreference(const void *context, const void *ptr)
{
struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
struct talloc_reference_handle *h;
 
if (unlikely(context == NULL)) {
context = null_context;
}
 
for (h=tc->refs;h;h=h->next) {
struct talloc_chunk *p = talloc_parent_chunk(h);
if (p == NULL) {
if (context == NULL) break;
} else if (TC_PTR_FROM_CHUNK(p) == context) {
break;
}
}
if (h == NULL) {
return -1;
}
 
return _talloc_free(h);
}
 
/*
remove a specific parent context from a pointer. This is a more
controlled varient of talloc_free()
*/
int talloc_unlink(const void *context, void *ptr)
{
struct talloc_chunk *tc_p, *new_p;
void *new_parent;
 
if (ptr == NULL) {
return -1;
}
 
if (context == NULL) {
context = null_context;
}
 
if (talloc_unreference(context, ptr) == 0) {
return 0;
}
 
if (context == NULL) {
if (talloc_parent_chunk(ptr) != NULL) {
return -1;
}
} else {
if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
return -1;
}
}
tc_p = talloc_chunk_from_ptr(ptr);
 
if (tc_p->refs == NULL) {
return _talloc_free(ptr);
}
 
new_p = talloc_parent_chunk(tc_p->refs);
if (new_p) {
new_parent = TC_PTR_FROM_CHUNK(new_p);
} else {
new_parent = NULL;
}
 
if (talloc_unreference(new_parent, ptr) != 0) {
return -1;
}
 
(void) talloc_steal(new_parent, ptr);
 
return 0;
}
 
/*
add a name to an existing pointer - va_list version
*/
static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
 
static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
{
struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
tc->name = talloc_vasprintf(ptr, fmt, ap);
if (likely(tc->name)) {
_talloc_set_name_const(tc->name, ".name");
}
return tc->name;
}
 
/*
add a name to an existing pointer
*/
const char *talloc_set_name(const void *ptr, const char *fmt, ...)
{
const char *name;
va_list ap;
va_start(ap, fmt);
name = talloc_set_name_v(ptr, fmt, ap);
va_end(ap);
return name;
}
 
 
/*
create a named talloc pointer. Any talloc pointer can be named, and
talloc_named() operates just like talloc() except that it allows you
to name the pointer.
*/
void *talloc_named(const void *context, size_t size, const char *fmt, ...)
{
va_list ap;
void *ptr;
const char *name;
 
ptr = __talloc(context, size);
if (unlikely(ptr == NULL)) return NULL;
 
va_start(ap, fmt);
name = talloc_set_name_v(ptr, fmt, ap);
va_end(ap);
 
if (unlikely(name == NULL)) {
_talloc_free(ptr);
return NULL;
}
 
return ptr;
}
 
/*
return the name of a talloc ptr, or "UNNAMED"
*/
const char *talloc_get_name(const void *ptr)
{
struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
return ".reference";
}
if (likely(tc->name)) {
return tc->name;
}
return "UNNAMED";
}
 
 
/*
check if a pointer has the given name. If it does, return the pointer,
otherwise return NULL
*/
void *talloc_check_name(const void *ptr, const char *name)
{
const char *pname;
if (unlikely(ptr == NULL)) return NULL;
pname = talloc_get_name(ptr);
if (likely(pname == name || strcmp(pname, name) == 0)) {
return discard_const_p(void, ptr);
}
return NULL;
}
 
 
/*
this is for compatibility with older versions of talloc
*/
void *talloc_init(const char *fmt, ...)
{
va_list ap;
void *ptr;
const char *name;
 
/*
* samba3 expects talloc_report_depth_cb(NULL, ...)
* reports all talloc'ed memory, so we need to enable
* null_tracking
*/
talloc_enable_null_tracking();
 
ptr = __talloc(NULL, 0);
if (unlikely(ptr == NULL)) return NULL;
 
va_start(ap, fmt);
name = talloc_set_name_v(ptr, fmt, ap);
va_end(ap);
 
if (unlikely(name == NULL)) {
_talloc_free(ptr);
return NULL;
}
 
return ptr;
}
 
/*
this is a replacement for the Samba3 talloc_destroy_pool functionality. It
should probably not be used in new code. It's in here to keep the talloc
code consistent across Samba 3 and 4.
*/
void talloc_free_children(void *ptr)
{
struct talloc_chunk *tc;
 
if (unlikely(ptr == NULL)) {
return;
}
 
tc = talloc_chunk_from_ptr(ptr);
 
while (tc->child) {
/* we need to work out who will own an abandoned child
if it cannot be freed. In priority order, the first
choice is owner of any remaining reference to this
pointer, the second choice is our parent, and the
final choice is the null context. */
void *child = TC_PTR_FROM_CHUNK(tc->child);
const void *new_parent = null_context;
if (unlikely(tc->child->refs)) {
struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
if (p) new_parent = TC_PTR_FROM_CHUNK(p);
}
if (unlikely(_talloc_free(child) == -1)) {
if (new_parent == null_context) {
struct talloc_chunk *p = talloc_parent_chunk(ptr);
if (p) new_parent = TC_PTR_FROM_CHUNK(p);
}
(void) talloc_steal(new_parent, child);
}
}
}
 
/*
Allocate a bit of memory as a child of an existing pointer
*/
void *_talloc(const void *context, size_t size)
{
return __talloc(context, size);
}
 
/*
externally callable talloc_set_name_const()
*/
void talloc_set_name_const(const void *ptr, const char *name)
{
_talloc_set_name_const(ptr, name);
}
 
/*
create a named talloc pointer. Any talloc pointer can be named, and
talloc_named() operates just like talloc() except that it allows you
to name the pointer.
*/
void *talloc_named_const(const void *context, size_t size, const char *name)
{
return _talloc_named_const(context, size, name);
}
 
/*
free a talloc pointer. This also frees all child pointers of this
pointer recursively
 
return 0 if the memory is actually freed, otherwise -1. The memory
will not be freed if the ref_count is > 1 or the destructor (if
any) returns non-zero
*/
int talloc_free(void *ptr)
{
return _talloc_free(ptr);
}
 
 
 
/*
A talloc version of realloc. The context argument is only used if
ptr is NULL
*/
void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
{
struct talloc_chunk *tc;
void *new_ptr;
 
/* size zero is equivalent to free() */
if (unlikely(size == 0)) {
_talloc_free(ptr);
return NULL;
}
 
if (unlikely(size >= MAX_TALLOC_SIZE)) {
return NULL;
}
 
/* realloc(NULL) is equivalent to malloc() */
if (ptr == NULL) {
return _talloc_named_const(context, size, name);
}
 
tc = talloc_chunk_from_ptr(ptr);
 
/* don't allow realloc on referenced pointers */
if (unlikely(tc->refs)) {
return NULL;
}
 
/* by resetting magic we catch users of the old memory */
tc->flags |= TALLOC_FLAG_FREE;
 
#if ALWAYS_REALLOC
new_ptr = malloc(size + TC_HDR_SIZE);
if (new_ptr) {
memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
free(tc);
}
#else
new_ptr = realloc(tc, size + TC_HDR_SIZE);
#endif
if (unlikely(!new_ptr)) {
tc->flags &= ~TALLOC_FLAG_FREE;
return NULL;
}
 
tc = (struct talloc_chunk *)new_ptr;
tc->flags &= ~TALLOC_FLAG_FREE;
if (tc->parent) {
tc->parent->child = tc;
}
if (tc->child) {
tc->child->parent = tc;
}
 
if (tc->prev) {
tc->prev->next = tc;
}
if (tc->next) {
tc->next->prev = tc;
}
 
tc->size = size;
_talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
 
return TC_PTR_FROM_CHUNK(tc);
}
 
/*
a wrapper around talloc_steal() for situations where you are moving a pointer
between two structures, and want the old pointer to be set to NULL
*/
void *_talloc_move(const void *new_ctx, const void *_pptr)
{
const void **pptr = discard_const_p(const void *,_pptr);
void *ret = _talloc_steal(new_ctx, *pptr);
(*pptr) = NULL;
return ret;
}
 
/*
return the total size of a talloc pool (subtree)
*/
size_t talloc_total_size(const void *ptr)
{
size_t total = 0;
struct talloc_chunk *c, *tc;
 
if (ptr == NULL) {
ptr = null_context;
}
if (ptr == NULL) {
return 0;
}
 
tc = talloc_chunk_from_ptr(ptr);
 
if (tc->flags & TALLOC_FLAG_LOOP) {
return 0;
}
 
tc->flags |= TALLOC_FLAG_LOOP;
 
total = tc->size;
for (c=tc->child;c;c=c->next) {
total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
}
 
tc->flags &= ~TALLOC_FLAG_LOOP;
 
return total;
}
 
/*
return the total number of blocks in a talloc pool (subtree)
*/
size_t talloc_total_blocks(const void *ptr)
{
size_t total = 0;
struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
 
if (tc->flags & TALLOC_FLAG_LOOP) {
return 0;
}
 
tc->flags |= TALLOC_FLAG_LOOP;
 
total++;
for (c=tc->child;c;c=c->next) {
total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
}
 
tc->flags &= ~TALLOC_FLAG_LOOP;
 
return total;
}
 
/*
return the number of external references to a pointer
*/
size_t talloc_reference_count(const void *ptr)
{
struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
struct talloc_reference_handle *h;
size_t ret = 0;
 
for (h=tc->refs;h;h=h->next) {
ret++;
}
return ret;
}
 
/*
report on memory usage by all children of a pointer, giving a full tree view
*/
void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
void (*callback)(const void *ptr,
int depth, int max_depth,
int is_ref,
void *private_data),
void *private_data)
{
struct talloc_chunk *c, *tc;
 
if (ptr == NULL) {
ptr = null_context;
}
if (ptr == NULL) return;
 
tc = talloc_chunk_from_ptr(ptr);
 
if (tc->flags & TALLOC_FLAG_LOOP) {
return;
}
 
callback(ptr, depth, max_depth, 0, private_data);
 
if (max_depth >= 0 && depth >= max_depth) {
return;
}
 
tc->flags |= TALLOC_FLAG_LOOP;
for (c=tc->child;c;c=c->next) {
if (c->name == TALLOC_MAGIC_REFERENCE) {
struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c);
callback(h->ptr, depth + 1, max_depth, 1, private_data);
} else {
talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
}
}
tc->flags &= ~TALLOC_FLAG_LOOP;
}
 
static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f)
{
const char *name = talloc_get_name(ptr);
FILE *f = (FILE *)_f;
 
if (is_ref) {
fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
return;
}
 
if (depth == 0) {
fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n",
(max_depth < 0 ? "full " :""), name,
(unsigned long)talloc_total_size(ptr),
(unsigned long)talloc_total_blocks(ptr));
return;
}
 
fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n",
depth*4, "",
name,
(unsigned long)talloc_total_size(ptr),
(unsigned long)talloc_total_blocks(ptr),
(int)talloc_reference_count(ptr), ptr);
 
#if 0
fprintf(f, "content: ");
if (talloc_total_size(ptr)) {
int tot = talloc_total_size(ptr);
int i;
 
for (i = 0; i < tot; i++) {
if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
fprintf(f, "%c", ((char *)ptr)[i]);
} else {
fprintf(f, "~%02x", ((char *)ptr)[i]);
}
}
}
fprintf(f, "\n");
#endif
}
 
/*
report on memory usage by all children of a pointer, giving a full tree view
*/
void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f)
{
talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
fflush(f);
}
 
/*
report on memory usage by all children of a pointer, giving a full tree view
*/
void talloc_report_full(const void *ptr, FILE *f)
{
talloc_report_depth_file(ptr, 0, -1, f);
}
 
/*
report on memory usage by all children of a pointer
*/
void talloc_report(const void *ptr, FILE *f)
{
talloc_report_depth_file(ptr, 0, 1, f);
}
 
/*
report on any memory hanging off the null context
*/
static void talloc_report_null(void)
{
if (talloc_total_size(null_context) != 0) {
talloc_report(null_context, stderr);
}
}
 
/*
report on any memory hanging off the null context
*/
static void talloc_report_null_full(void)
{
if (talloc_total_size(null_context) != 0) {
talloc_report_full(null_context, stderr);
}
}
 
/*
enable tracking of the NULL context
*/
void talloc_enable_null_tracking(void)
{
if (null_context == NULL) {
null_context = _talloc_named_const(NULL, 0, "null_context");
}
}
 
/*
disable tracking of the NULL context
*/
void talloc_disable_null_tracking(void)
{
_talloc_free(null_context);
null_context = NULL;
}
 
/*
enable leak reporting on exit
*/
void talloc_enable_leak_report(void)
{
talloc_enable_null_tracking();
atexit(talloc_report_null);
}
 
/*
enable full leak reporting on exit
*/
void talloc_enable_leak_report_full(void)
{
talloc_enable_null_tracking();
atexit(talloc_report_null_full);
}
 
/*
talloc and zero memory.
*/
void *_talloc_zero(const void *ctx, size_t size, const char *name)
{
void *p = _talloc_named_const(ctx, size, name);
 
if (p) {
memset(p, '\0', size);
}
 
return p;
}
 
/*
memdup with a talloc.
*/
void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
{
void *newp = _talloc_named_const(t, size, name);
 
if (likely(newp)) {
memcpy(newp, p, size);
}
 
return newp;
}
 
/*
strdup with a talloc
*/
char *talloc_strdup(const void *t, const char *p)
{
char *ret;
if (!p) {
return NULL;
}
ret = (char *)talloc_memdup(t, p, strlen(p) + 1);
if (likely(ret)) {
_talloc_set_name_const(ret, ret);
}
return ret;
}
 
/*
append to a talloced string
*/
char *talloc_append_string(const void *t, char *orig, const char *append)
{
char *ret;
size_t olen = strlen(orig);
size_t alenz;
 
if (!append)
return orig;
 
alenz = strlen(append) + 1;
 
ret = talloc_realloc(t, orig, char, olen + alenz);
if (!ret)
return NULL;
 
/* append the string with the trailing \0 */
memcpy(&ret[olen], append, alenz);
 
_talloc_set_name_const(ret, ret);
 
return ret;
}
 
/*
strndup with a talloc
*/
char *talloc_strndup(const void *t, const char *p, size_t n)
{
size_t len;
char *ret;
 
for (len=0; len<n && p[len]; len++) ;
 
ret = (char *)__talloc(t, len + 1);
if (!ret) { return NULL; }
memcpy(ret, p, len);
ret[len] = 0;
_talloc_set_name_const(ret, ret);
return ret;
}
 
#ifndef HAVE_VA_COPY
#ifdef HAVE___VA_COPY
#define va_copy(dest, src) __va_copy(dest, src)
#else
#define va_copy(dest, src) (dest) = (src)
#endif
#endif
 
char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
{
int len;
char *ret;
va_list ap2;
char c;
/* this call looks strange, but it makes it work on older solaris boxes */
va_copy(ap2, ap);
len = vsnprintf(&c, 1, fmt, ap2);
va_end(ap2);
if (len < 0) {
return NULL;
}
 
ret = (char *)__talloc(t, len+1);
if (ret) {
va_copy(ap2, ap);
vsnprintf(ret, len+1, fmt, ap2);
va_end(ap2);
_talloc_set_name_const(ret, ret);
}
 
return ret;
}
 
 
/*
Perform string formatting, and return a pointer to newly allocated
memory holding the result, inside a memory pool.
*/
char *talloc_asprintf(const void *t, const char *fmt, ...)
{
va_list ap;
char *ret;
 
va_start(ap, fmt);
ret = talloc_vasprintf(t, fmt, ap);
va_end(ap);
return ret;
}
 
 
/**
* Realloc @p s to append the formatted result of @p fmt and @p ap,
* and return @p s, which may have moved. Good for gradually
* accumulating output into a string buffer.
**/
char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
{
struct talloc_chunk *tc;
int len, s_len;
va_list ap2;
char c;
 
if (s == NULL) {
return talloc_vasprintf(NULL, fmt, ap);
}
 
tc = talloc_chunk_from_ptr(s);
 
s_len = tc->size - 1;
 
va_copy(ap2, ap);
len = vsnprintf(&c, 1, fmt, ap2);
va_end(ap2);
 
if (len <= 0) {
/* Either the vsnprintf failed or the format resulted in
* no characters being formatted. In the former case, we
* ought to return NULL, in the latter we ought to return
* the original string. Most current callers of this
* function expect it to never return NULL.
*/
return s;
}
 
s = talloc_realloc(NULL, s, char, s_len + len+1);
if (!s) return NULL;
 
va_copy(ap2, ap);
vsnprintf(s+s_len, len+1, fmt, ap2);
va_end(ap2);
_talloc_set_name_const(s, s);
 
return s;
}
 
/*
Realloc @p s to append the formatted result of @p fmt and return @p
s, which may have moved. Good for gradually accumulating output
into a string buffer.
*/
char *talloc_asprintf_append(char *s, const char *fmt, ...)
{
va_list ap;
 
va_start(ap, fmt);
s = talloc_vasprintf_append(s, fmt, ap);
va_end(ap);
return s;
}
 
/*
alloc an array, checking for integer overflow in the array size
*/
void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
{
if (count >= MAX_TALLOC_SIZE/el_size) {
return NULL;
}
return _talloc_named_const(ctx, el_size * count, name);
}
 
/*
alloc an zero array, checking for integer overflow in the array size
*/
void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
{
if (count >= MAX_TALLOC_SIZE/el_size) {
return NULL;
}
return _talloc_zero(ctx, el_size * count, name);
}
 
/*
realloc an array, checking for integer overflow in the array size
*/
void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
{
if (count >= MAX_TALLOC_SIZE/el_size) {
return NULL;
}
return _talloc_realloc(ctx, ptr, el_size * count, name);
}
 
/*
a function version of talloc_realloc(), so it can be passed as a function pointer
to libraries that want a realloc function (a realloc function encapsulates
all the basic capabilities of an allocation library, which is why this is useful)
*/
void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
{
return _talloc_realloc(context, ptr, size, NULL);
}
 
 
static int talloc_autofree_destructor(void *ptr)
{
autofree_context = NULL;
return 0;
}
 
static void talloc_autofree(void)
{
_talloc_free(autofree_context);
}
 
/*
return a context which will be auto-freed on exit
this is useful for reducing the noise in leak reports
*/
void *talloc_autofree_context(void)
{
if (autofree_context == NULL) {
autofree_context = _talloc_named_const(NULL, 0, "autofree_context");
talloc_set_destructor(autofree_context, talloc_autofree_destructor);
atexit(talloc_autofree);
}
return autofree_context;
}
 
size_t talloc_get_size(const void *context)
{
struct talloc_chunk *tc;
 
if (context == NULL)
return 0;
 
tc = talloc_chunk_from_ptr(context);
 
return tc->size;
}
 
/*
find a parent of this context that has the given name, if any
*/
void *talloc_find_parent_byname(const void *context, const char *name)
{
struct talloc_chunk *tc;
 
if (context == NULL) {
return NULL;
}
 
tc = talloc_chunk_from_ptr(context);
while (tc) {
if (tc->name && strcmp(tc->name, name) == 0) {
return TC_PTR_FROM_CHUNK(tc);
}
while (tc && tc->prev) tc = tc->prev;
if (tc) {
tc = tc->parent;
}
}
return NULL;
}
 
/*
show the parentage of a context
*/
void talloc_show_parents(const void *context, FILE *file)
{
struct talloc_chunk *tc;
 
if (context == NULL) {
fprintf(file, "talloc no parents for NULL\n");
return;
}
 
tc = talloc_chunk_from_ptr(context);
fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
while (tc) {
fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
while (tc && tc->prev) tc = tc->prev;
if (tc) {
tc = tc->parent;
}
}
fflush(file);
}
 
/*
return 1 if ptr is a parent of context
*/
int talloc_is_parent(const void *context, const void *ptr)
{
struct talloc_chunk *tc;
 
if (context == NULL) {
return 0;
}
 
tc = talloc_chunk_from_ptr(context);
while (tc) {
if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
while (tc && tc->prev) tc = tc->prev;
if (tc) {
tc = tc->parent;
}
}
return 0;
}
/programs/network/netsurf/netsurf/utils/talloc.h
0,0 → 1,173
#ifndef _TALLOC_H_
#define _TALLOC_H_
/*
Unix SMB/CIFS implementation.
Samba temporary memory allocation functions
 
Copyright (C) Andrew Tridgell 2004-2005
Copyright (C) Stefan Metzmacher 2006
** NOTE! The following LGPL license applies to the talloc
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
 
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
 
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
 
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
 
/* this is only needed for compatibility with the old talloc */
typedef void TALLOC_CTX;
 
/*
this uses a little trick to allow __LINE__ to be stringified
*/
#ifndef __location__
#define __TALLOC_STRING_LINE1__(s) #s
#define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s)
#define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__)
#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__
#endif
 
#ifndef TALLOC_DEPRECATED
#define TALLOC_DEPRECATED 0
#endif
 
#ifndef PRINTF_ATTRIBUTE
#if (__GNUC__ >= 3)
/** Use gcc attribute to check printf fns. a1 is the 1-based index of
* the parameter containing the format, and a2 the index of the first
* argument. Note that some gcc 2.x versions don't handle this
* properly **/
#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
#else
#define PRINTF_ATTRIBUTE(a1, a2)
#endif
#endif
 
/* try to make talloc_set_destructor() and talloc_steal() type safe,
if we have a recent gcc */
#if (__GNUC__ >= 3)
#define _TALLOC_TYPEOF(ptr) __typeof__(ptr)
#define talloc_set_destructor(ptr, function) \
do { \
int (*_talloc_destructor_fn)(_TALLOC_TYPEOF(ptr)) = (function); \
_talloc_set_destructor((ptr), (int (*)(void *))_talloc_destructor_fn); \
} while(0)
/* this extremely strange macro is to avoid some braindamaged warning
stupidity in gcc 4.1.x */
#define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) __talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr)); __talloc_steal_ret; })
#else
#define talloc_set_destructor(ptr, function) \
_talloc_set_destructor((ptr), (int (*)(void *))(function))
#define _TALLOC_TYPEOF(ptr) void *
#define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr))
#endif
 
#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference((ctx),(ptr))
#define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr))
 
/* useful macros for creating type checked pointers */
#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr)))
 
#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__)
 
#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
 
#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count)
 
#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
 
#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__)
 
#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
 
#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type)
 
#if TALLOC_DEPRECATED
#define talloc_zero_p(ctx, type) talloc_zero(ctx, type)
#define talloc_p(ctx, type) talloc(ctx, type)
#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count)
#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count)
#define talloc_destroy(ctx) talloc_free(ctx)
#endif
 
/* The following definitions come from talloc.c */
void *_talloc(const void *context, size_t size);
void _talloc_set_destructor(const void *ptr, int (*destructor)(void *));
int talloc_increase_ref_count(const void *ptr);
size_t talloc_reference_count(const void *ptr);
void *_talloc_reference(const void *context, const void *ptr);
int talloc_unlink(const void *context, void *ptr);
const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
void talloc_set_name_const(const void *ptr, const char *name);
void *talloc_named(const void *context, size_t size,
const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
void *talloc_named_const(const void *context, size_t size, const char *name);
const char *talloc_get_name(const void *ptr);
void *talloc_check_name(const void *ptr, const char *name);
void *talloc_parent(const void *ptr);
const char *talloc_parent_name(const void *ptr);
void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
int talloc_free(void *ptr);
void talloc_free_children(void *ptr);
void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
void *_talloc_steal(const void *new_ctx, const void *ptr);
void *_talloc_move(const void *new_ctx, const void *pptr);
size_t talloc_total_size(const void *ptr);
size_t talloc_total_blocks(const void *ptr);
void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
void (*callback)(const void *ptr,
int depth, int max_depth,
int is_ref,
void *private_data),
void *private_data);
void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
void talloc_report_full(const void *ptr, FILE *f);
void talloc_report(const void *ptr, FILE *f);
void talloc_enable_null_tracking(void);
void talloc_disable_null_tracking(void);
void talloc_enable_leak_report(void);
void talloc_enable_leak_report_full(void);
void *_talloc_zero(const void *ctx, size_t size, const char *name);
void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
char *talloc_strdup(const void *t, const char *p);
char *talloc_strndup(const void *t, const char *p, size_t n);
char *talloc_append_string(const void *t, char *orig, const char *append);
char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name);
void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
void *talloc_autofree_context(void);
size_t talloc_get_size(const void *ctx);
void *talloc_find_parent_byname(const void *ctx, const char *name);
void talloc_show_parents(const void *context, FILE *file);
int talloc_is_parent(const void *context, const void *ptr);
 
#endif
/programs/network/netsurf/netsurf/utils/testament.h
0,0 → 1,41
/* utils/testament.h
*
* Revision testament.
*
* *WARNING* this file is automatically generated by git-testament.pl
*
* Copyright 2012 NetSurf Browser Project
*/
 
#ifndef NETSURF_REVISION_TESTAMENT
#define NETSURF_REVISION_TESTAMENT "178a6caf6b7896579100426d2e86272e"
 
/* Revision testament checksum:
* MD5:178a6caf6b7896579100426d2e86272e
*/
 
/* Revision testament: */
#define USERNAME "sourcerer"
#define GECOS "sourcerer"
#define WT_ROOT "/home/sourcerer/kos_src/netsurf/unix/netsurf/"
#define WT_HOSTNAME "debian"
#define WT_COMPILEDATE "04.02.2013"
#define WT_BRANCHPATH "master"
#define WT_BRANCHISMASTER 1
#define WT_REVID "43fe4490d3152ccecd7fd8065c09faaa893fb09e"
#define WT_MODIFIED 11
#define WT_MODIFICATIONS {\
{ "buildsystem/", "??" }, \
{ "libcss/", "??" }, \
{ "libdom/", "??" }, \
{ "libhubbub/", "??" }, \
{ "libmng-1.0.10/", "??" }, \
{ "libnsbmp/", "??" }, \
{ "libnsfb/", "??" }, \
{ "libnsgif/", "??" }, \
{ "libparserutils/", "??" }, \
{ "libwapcaplet/", "??" }, \
{ "nsgenbind", "??" } \
}
 
#endif
/programs/network/netsurf/netsurf/utils/types.h
0,0 → 1,62
/*
* Copyright 2011 Michael Drake <tlsa@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* Core types.
*/
 
#ifndef _NETSURF_UTILS_TYPES_H_
#define _NETSURF_UTILS_TYPES_H_
 
struct plotter_table;
struct hlcache_handle;
 
/* Rectangle coordinates */
struct rect {
int x0, y0; /* Top left */
int x1, y1; /* Bottom right */
};
 
 
/* Redraw context */
struct redraw_context {
/** Redraw to show interactive features, such as active selections
* etc. Should be off for printing. */
bool interactive;
 
/** Render background images. May want it off for printing. */
bool background_images;
 
/** Current plotters, must be assigned before use. */
const struct plotter_table *plot;
};
 
 
/* Content located at a specific spatial location */
struct contextual_content {
const char *link_url;
struct hlcache_handle *object;
struct hlcache_handle *main;
enum {
CTX_FORM_NONE,
CTX_FORM_TEXT,
CTX_FORM_FILE
} form_features;
};
 
#endif
/programs/network/netsurf/netsurf/utils/url.c
0,0 → 1,942
/*
* Copyright 2006 Richard Wilson <info@tinct.net>
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
* Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* URL parsing and joining (implementation).
*/
 
#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
#include "curl/curl.h"
#include "utils/config.h"
#include "utils/log.h"
#include "utils/url.h"
#include "utils/utils.h"
 
struct url_components_internal {
char *buffer; /* buffer used for all the following data */
char *scheme;
char *authority;
char *path;
char *query;
char *fragment;
};
 
 
regex_t url_re, url_up_re;
 
/**
* Initialise URL routines.
*
* Compiles regular expressions required by the url_ functions.
*/
 
void url_init(void)
{
/* regex from RFC 2396 */
regcomp_wrapper(&url_re, "^[[:space:]]*"
#define URL_RE_SCHEME 2
"(([a-zA-Z][-a-zA-Z0-9+.]*):)?"
#define URL_RE_AUTHORITY 4
"(//([^/?#[:space:]]*))?"
#define URL_RE_PATH 5
"([^?#[:space:]]*)"
#define URL_RE_QUERY 7
"(\\?([^#[:space:]]*))?"
#define URL_RE_FRAGMENT 9
"(#([^[:space:]]*))?"
"[[:space:]]*$", REG_EXTENDED);
regcomp_wrapper(&url_up_re,
"/([^/]?|[.][^./]|[^./][.]|[^./][^./]|[^/][^/][^/]+)"
"/[.][.](/|$)",
REG_EXTENDED);
}
 
 
/**
* Check whether a host string is an IP address. It should support and
* detect IPv4 addresses (all of dotted-quad or subsets, decimal or
* hexadecimal notations) and IPv6 addresses (including those containing
* embedded IPv4 addresses.)
*
* \param host a hostname terminated by '\0'
* \return true if the hostname is an IP address, false otherwise
*/
bool url_host_is_ip_address(const char *host)
{
struct in_addr ipv4;
size_t host_len = strlen(host);
const char *sane_host;
const char *slash;
#ifndef NO_IPV6
struct in6_addr ipv6;
char ipv6_addr[64];
#endif
/* FIXME TODO: Some parts of urldb.c (and perhaps other parts of
* NetSurf) make confusions between hosts and "prefixes", we can
* sometimes be erroneously passed more than just a host. Sometimes
* we may be passed trailing slashes, or even whole path segments.
* A specific criminal in this class is urldb_iterate_partial, which
* takes a prefix to search for, but passes that prefix to functions
* that expect only hosts.
*
* For the time being, we will accept such calls; we check if there
* is a / in the host parameter, and if there is, we take a copy and
* replace the / with a \0. This is not a permanent solution; we
* should search through NetSurf and find all the callers that are
* in error and fix them. When doing this task, it might be wise
* to replace the hideousness below with code that doesn't have to do
* this, and add assert(strchr(host, '/') == NULL); somewhere.
* -- rjek - 2010-11-04
*/
 
slash = strchr(host, '/');
if (slash == NULL) {
sane_host = host;
} else {
char *c = strdup(host);
c[slash - host] = '\0';
sane_host = c;
host_len = slash - host - 1;
LOG(("WARNING: called with non-host '%s'", host));
}
 
if (strspn(sane_host, "0123456789abcdefABCDEF[].:") < host_len)
goto out_false;
 
if (inet_aton(sane_host, &ipv4) != 0) {
/* This can only be a sane IPv4 address if it contains 3 dots.
* Helpfully, inet_aton is happy to treat "a", "a.b", "a.b.c",
* and "a.b.c.d" as valid IPv4 address strings where we only
* support the full, dotted-quad, form.
*/
int num_dots = 0;
size_t index;
 
for (index = 0; index < host_len; index++) {
if (sane_host[index] == '.')
num_dots++;
}
 
if (num_dots == 3)
goto out_true;
else
goto out_false;
}
 
#ifndef NO_IPV6
if (sane_host[0] != '[' || sane_host[host_len] != ']')
goto out_false;
 
strncpy(ipv6_addr, sane_host + 1, sizeof(ipv6_addr));
ipv6_addr[sizeof(ipv6_addr) - 1] = '\0';
 
if (inet_pton(AF_INET6, ipv6_addr, &ipv6) == 1)
goto out_true;
#endif
 
out_false:
if (slash != NULL) free((void *)sane_host);
return false;
 
out_true:
if (slash != NULL) free((void *)sane_host);
return true;
}
 
/**
* Split a URL into separate components
*
* URLs passed to this function are assumed to be valid and no error checking
* or recovery is attempted.
*
* See RFC 3986 for reference.
*
* \param url a valid absolute or relative URL
* \param result pointer to buffer to hold components
* \return URL_FUNC_OK on success
*/
 
static url_func_result url_get_components(const char *url,
struct url_components *result)
{
int storage_length;
char *storage_end;
const char *scheme;
const char *authority;
const char *path;
const char *query;
const char *fragment;
struct url_components_internal *internal;
 
assert(url);
 
/* clear our return value */
internal = (struct url_components_internal *)result;
memset(result, 0x00, sizeof(struct url_components));
 
/* get enough storage space for a URL with termination at each node */
storage_length = strlen(url) + 8;
internal->buffer = malloc(storage_length);
if (!internal->buffer)
return URL_FUNC_NOMEM;
storage_end = internal->buffer;
 
/* look for a valid scheme */
scheme = url;
if (isalpha(*scheme)) {
for (scheme = url + 1;
((*scheme != ':') && (*scheme != '\0'));
scheme++) {
if (!isalnum(*scheme) && (*scheme != '+') &&
(*scheme != '-') && (*scheme != '.'))
break;
}
 
if (*scheme == ':') {
memcpy(storage_end, url, scheme - url);
storage_end[scheme - url] = '\0';
result->scheme = storage_end;
storage_end += scheme - url + 1;
scheme++;
} else {
scheme = url;
}
}
 
 
/* look for an authority */
authority = scheme;
if ((authority[0] == '/') && (authority[1] == '/')) {
authority = strpbrk(scheme + 2, "/?#");
if (!authority)
authority = scheme + strlen(scheme);
memcpy(storage_end, scheme + 2, authority - scheme - 2);
storage_end[authority - scheme - 2] = '\0';
result->authority = storage_end;
storage_end += authority - scheme - 1;
}
 
 
/* look for a path */
path = authority;
if ((*path != '?') && (*path != '#') && (*path != '\0')) {
path = strpbrk(path, "?#");
if (!path)
path = authority + strlen(authority);
memcpy(storage_end, authority, path - authority);
storage_end[path - authority] = '\0';
result->path = storage_end;
storage_end += path - authority + 1;
}
 
 
/* look for a query */
query = path;
if (*query == '?') {
query = strchr(query, '#');
if (!query)
query = path + strlen(path);
memcpy(storage_end, path + 1, query - path - 1);
storage_end[query - path - 1] = '\0';
result->query = storage_end;
storage_end += query - path;
}
 
 
/* look for a fragment */
fragment = query;
if (*fragment == '#') {
fragment = query + strlen(query);
 
/* make a copy of the result for the caller */
memcpy(storage_end, query + 1, fragment - query - 1);
storage_end[fragment - query - 1] = '\0';
result->fragment = storage_end;
storage_end += fragment - query;
}
 
assert((result->buffer + storage_length) >= storage_end);
return URL_FUNC_OK;
}
 
 
/**
* Reform a URL from separate components
*
* See RFC 3986 for reference.
*
* \param components the components to reform into a URL
* \return a new URL allocated on the heap, or NULL on failure
*/
 
static char *url_reform_components(const struct url_components *components)
{
int scheme_len = 0, authority_len = 0, path_len = 0, query_len = 0,
fragment_len = 0;
char *result, *url;
 
/* 5.3 */
if (components->scheme)
scheme_len = strlen(components->scheme) + 1;
if (components->authority)
authority_len = strlen(components->authority) + 2;
if (components->path)
path_len = strlen(components->path);
if (components->query)
query_len = strlen(components->query) + 1;
if (components->fragment)
fragment_len = strlen(components->fragment) + 1;
 
/* claim memory */
url = result = malloc(scheme_len + authority_len + path_len +
query_len + fragment_len + 1);
if (!url) {
LOG(("malloc failed"));
return NULL;
}
 
/* rebuild URL */
if (components->scheme) {
sprintf(url, "%s:", components->scheme);
url += scheme_len;
}
if (components->authority) {
sprintf(url, "//%s", components->authority);
url += authority_len;
}
if (components->path) {
sprintf(url, "%s", components->path);
url += path_len;
}
if (components->query) {
sprintf(url, "?%s", components->query);
url += query_len;
}
if (components->fragment)
sprintf(url, "#%s", components->fragment);
return result;
}
 
 
/**
* Release some url components from memory
*
* \param result pointer to buffer containing components
*/
static void url_destroy_components(const struct url_components *components)
{
const struct url_components_internal *internal;
 
assert(components);
 
internal = (const struct url_components_internal *)components;
if (internal->buffer)
free(internal->buffer);
}
 
 
/**
* Resolve a relative URL to absolute form.
*
* \param rel relative URL
* \param base base URL, must be absolute and cleaned as by nsurl_create()
* \param result pointer to pointer to buffer to hold absolute url
* \return URL_FUNC_OK on success
*/
 
url_func_result url_join(const char *rel, const char *base, char **result)
{
url_func_result status = URL_FUNC_NOMEM;
struct url_components_internal base_components = {0,0,0,0,0,0};
struct url_components_internal *base_ptr = &base_components;
struct url_components_internal rel_components = {0,0,0,0,0,0};
struct url_components_internal *rel_ptr = &rel_components;
struct url_components_internal merged_components = {0,0,0,0,0,0};
struct url_components_internal *merged_ptr = &merged_components;
char *merge_path = NULL, *split_point;
char *input, *output, *start = NULL;
int len, buf_len;
 
(*result) = 0;
 
assert(base);
assert(rel);
 
 
/* break down the relative URL (not cached, corruptable) */
status = url_get_components(rel, (struct url_components *) rel_ptr);
if (status != URL_FUNC_OK) {
LOG(("relative url '%s' failed to get components", rel));
return URL_FUNC_FAILED;
}
 
/* [1] relative URL is absolute, use it entirely */
merged_components = rel_components;
if (rel_components.scheme)
goto url_join_reform_url;
 
/* break down the base URL (possibly cached, not corruptable) */
status = url_get_components(base, (struct url_components *) base_ptr);
if (status != URL_FUNC_OK) {
url_destroy_components((struct url_components *) rel_ptr);
LOG(("base url '%s' failed to get components", base));
return URL_FUNC_FAILED;
}
 
/* [2] relative authority takes presidence */
merged_components.scheme = base_components.scheme;
if (rel_components.authority)
goto url_join_reform_url;
 
/* [3] handle empty paths */
merged_components.authority = base_components.authority;
if (!rel_components.path) {
merged_components.path = base_components.path;
if (!rel_components.query)
merged_components.query = base_components.query;
goto url_join_reform_url;
}
 
/* [4] handle valid paths */
if (rel_components.path[0] == '/')
merged_components.path = rel_components.path;
else {
/* 5.2.3 */
if ((base_components.authority) && (!base_components.path)) {
merge_path = malloc(strlen(rel_components.path) + 2);
if (!merge_path) {
LOG(("malloc failed"));
goto url_join_no_mem;
}
sprintf(merge_path, "/%s", rel_components.path);
merged_components.path = merge_path;
} else {
split_point = base_components.path ?
strrchr(base_components.path, '/') :
NULL;
if (!split_point) {
merged_components.path = rel_components.path;
} else {
len = ++split_point - base_components.path;
buf_len = len + 1 + strlen(rel_components.path);
merge_path = malloc(buf_len);
if (!merge_path) {
LOG(("malloc failed"));
goto url_join_no_mem;
}
memcpy(merge_path, base_components.path, len);
memcpy(merge_path + len, rel_components.path,
strlen(rel_components.path));
merge_path[buf_len - 1] = '\0';
merged_components.path = merge_path;
}
}
}
 
url_join_reform_url:
/* 5.2.4 */
input = merged_components.path;
if ((input) && (strchr(input, '.'))) {
/* [1] remove all dot references */
output = start = malloc(strlen(input) + 1);
if (!output) {
LOG(("malloc failed"));
goto url_join_no_mem;
}
merged_components.path = output;
*output = '\0';
 
while (*input != '\0') {
/* [2A] */
if (input[0] == '.') {
if (input[1] == '/') {
input = input + 2;
continue;
} else if ((input[1] == '.') &&
(input[2] == '/')) {
input = input + 3;
continue;
}
}
 
/* [2B] */
if ((input[0] == '/') && (input[1] == '.')) {
if (input[2] == '/') {
input = input + 2;
continue;
} else if (input[2] == '\0') {
input = input + 1;
*input = '/';
continue;
}
 
/* [2C] */
if ((input[2] == '.') && ((input[3] == '/') ||
(input[3] == '\0'))) {
if (input[3] == '/') {
input = input + 3;
} else {
input = input + 2;
*input = '/';
}
 
if ((output > start) &&
(output[-1] == '/'))
*--output = '\0';
split_point = strrchr(start, '/');
if (!split_point)
output = start;
else
output = split_point;
*output = '\0';
continue;
}
}
 
 
/* [2D] */
if (input[0] == '.') {
if (input[1] == '\0') {
input = input + 1;
continue;
} else if ((input[1] == '.') &&
(input[2] == '\0')) {
input = input + 2;
continue;
}
}
 
/* [2E] */
if (*input == '/')
*output++ = *input++;
while ((*input != '/') && (*input != '\0'))
*output++ = *input++;
*output = '\0';
}
/* [3] */
merged_components.path = start;
}
 
/* 5.3 */
*result = url_reform_components((struct url_components *) merged_ptr);
if (!(*result))
goto url_join_no_mem;
 
/* return success */
status = URL_FUNC_OK;
 
url_join_no_mem:
free(start);
free(merge_path);
url_destroy_components((struct url_components *) base_ptr);
url_destroy_components((struct url_components *) rel_ptr);
return status;
}
 
 
/**
* Return the host name from an URL.
*
* \param url an absolute URL
* \param result pointer to pointer to buffer to hold host name
* \return URL_FUNC_OK on success
*/
 
url_func_result url_host(const char *url, char **result)
{
url_func_result status;
struct url_components components;
const char *host_start, *host_end;
 
assert(url);
 
status = url_get_components(url, &components);
if (status == URL_FUNC_OK) {
if (!components.authority) {
url_destroy_components(&components);
return URL_FUNC_FAILED;
}
host_start = strchr(components.authority, '@');
host_start = host_start ? host_start + 1 : components.authority;
 
/* skip over an IPv6 address if there is one */
if (host_start[0] == '[') {
host_end = strchr(host_start, ']') + 1;
} else {
host_end = strchr(host_start, ':');
}
 
if (!host_end)
host_end = components.authority +
strlen(components.authority);
 
*result = malloc(host_end - host_start + 1);
if (!(*result)) {
url_destroy_components(&components);
return URL_FUNC_FAILED;
}
memcpy((*result), host_start, host_end - host_start);
(*result)[host_end - host_start] = '\0';
}
url_destroy_components(&components);
return status;
}
 
 
/**
* Return the scheme name from an URL.
*
* See RFC 3986, 3.1 for reference.
*
* \param url an absolute URL
* \param result pointer to pointer to buffer to hold scheme name
* \return URL_FUNC_OK on success
*/
 
url_func_result url_scheme(const char *url, char **result)
{
url_func_result status;
struct url_components components;
 
assert(url);
 
status = url_get_components(url, &components);
if (status == URL_FUNC_OK) {
if (!components.scheme) {
status = URL_FUNC_FAILED;
} else {
*result = strdup(components.scheme);
if (!(*result))
status = URL_FUNC_NOMEM;
}
}
url_destroy_components(&components);
return status;
}
 
 
/**
* Extract path segment from an URL
*
* \param url an absolute URL
* \param result pointer to pointer to buffer to hold result
* \return URL_FUNC_OK on success
*/
 
url_func_result url_path(const char *url, char **result)
{
url_func_result status;
struct url_components components;
 
assert(url);
 
status = url_get_components(url, &components);
if (status == URL_FUNC_OK) {
if (!components.path) {
status = URL_FUNC_FAILED;
} else {
*result = strdup(components.path);
if (!(*result))
status = URL_FUNC_NOMEM;
}
}
url_destroy_components(&components);
return status;
}
 
/**
* Attempt to find a nice filename for a URL.
*
* \param url an absolute URL
* \param result pointer to pointer to buffer to hold filename
* \param remove_extensions remove any extensions from the filename
* \return URL_FUNC_OK on success
*/
 
url_func_result url_nice(const char *url, char **result,
bool remove_extensions)
{
int m;
regmatch_t match[10];
regoff_t start, end;
size_t i;
char *dot;
 
*result = 0;
 
m = regexec(&url_re, url, 10, match, 0);
if (m) {
LOG(("url '%s' failed to match regex", url));
return URL_FUNC_FAILED;
}
 
/* extract the last component of the path, if possible */
if (match[URL_RE_PATH].rm_so == -1 || match[URL_RE_PATH].rm_so ==
match[URL_RE_PATH].rm_eo)
goto no_path; /* no path, or empty */
for (end = match[URL_RE_PATH].rm_eo - 1;
end != match[URL_RE_PATH].rm_so && url[end] == '/';
end--)
;
if (end == match[URL_RE_PATH].rm_so)
goto no_path; /* path is a string of '/' */
end++;
for (start = end - 1;
start != match[URL_RE_PATH].rm_so && url[start] != '/';
start--)
;
if (url[start] == '/')
start++;
 
if (!strncasecmp(url + start, "index.", 6) ||
!strncasecmp(url + start, "default.", 8)) {
/* try again */
if (start == match[URL_RE_PATH].rm_so)
goto no_path;
for (end = start - 1;
end != match[URL_RE_PATH].rm_so &&
url[end] == '/';
end--)
;
if (end == match[URL_RE_PATH].rm_so)
goto no_path;
end++;
for (start = end - 1;
start != match[URL_RE_PATH].rm_so &&
url[start] != '/';
start--)
;
if (url[start] == '/')
start++;
}
 
*result = malloc(end - start + 1);
if (!*result) {
LOG(("malloc failed"));
return URL_FUNC_NOMEM;
}
strncpy(*result, url + start, end - start);
(*result)[end - start] = 0;
 
if (remove_extensions) {
dot = strchr(*result, '.');
if (dot && dot != *result)
*dot = 0;
}
 
return URL_FUNC_OK;
 
no_path:
 
/* otherwise, use the host name, with '.' replaced by '_' */
if (match[URL_RE_AUTHORITY].rm_so != -1 &&
match[URL_RE_AUTHORITY].rm_so !=
match[URL_RE_AUTHORITY].rm_eo) {
*result = malloc(match[URL_RE_AUTHORITY].rm_eo -
match[URL_RE_AUTHORITY].rm_so + 1);
if (!*result) {
LOG(("malloc failed"));
return URL_FUNC_NOMEM;
}
strncpy(*result, url + match[URL_RE_AUTHORITY].rm_so,
match[URL_RE_AUTHORITY].rm_eo -
match[URL_RE_AUTHORITY].rm_so);
(*result)[match[URL_RE_AUTHORITY].rm_eo -
match[URL_RE_AUTHORITY].rm_so] = 0;
 
for (i = 0; (*result)[i]; i++)
if ((*result)[i] == '.')
(*result)[i] = '_';
 
return URL_FUNC_OK;
}
 
return URL_FUNC_FAILED;
}
 
/**
* Convert an escaped string to plain.
* \param result unescaped string owned by caller must be freed with free()
* \return URL_FUNC_OK on success
*/
url_func_result url_unescape(const char *str, char **result)
{
char *curlstr;
char *retstr;
 
curlstr = curl_unescape(str, 0);
if (curlstr == NULL) {
return URL_FUNC_NOMEM;
}
 
retstr = strdup(curlstr);
curl_free(curlstr);
 
if (retstr == NULL) {
return URL_FUNC_NOMEM;
}
 
*result = retstr;
return URL_FUNC_OK;
}
 
/**
* Escape a string suitable for inclusion in an URL.
*
* \param unescaped the unescaped string
* \param toskip number of bytes to skip in unescaped string
* \param sptoplus true iff spaces should be converted to +
* \param escexceptions NULL or a string of characters excluded to be escaped
* \param result pointer to pointer to buffer to hold escaped string
* \return URL_FUNC_OK on success
*/
 
url_func_result url_escape(const char *unescaped, size_t toskip,
bool sptoplus, const char *escexceptions, char **result)
{
size_t len;
char *escaped, *d, *tmpres;
const char *c;
 
if (!unescaped || !result)
return URL_FUNC_FAILED;
 
*result = NULL;
 
len = strlen(unescaped);
if (len < toskip)
return URL_FUNC_FAILED;
len -= toskip;
 
escaped = malloc(len * 3 + 1);
if (!escaped)
return URL_FUNC_NOMEM;
 
for (c = unescaped + toskip, d = escaped; *c; c++) {
/* Check if we should escape this byte.
* '~' is unreserved and should not be percent encoded, if
* you believe the spec; however, leaving it unescaped
* breaks a bunch of websites, so we escape it anyway. */
if (!isascii(*c)
|| (strchr(":/?#[]@" /* gen-delims */
"!$&'()*+,;=" /* sub-delims */
"<>%\"{}|\\^`~" /* others */, *c)
&& (!escexceptions || !strchr(escexceptions, *c)))
|| *c <= 0x20 || *c == 0x7f) {
if (*c == 0x20 && sptoplus) {
*d++ = '+';
} else {
*d++ = '%';
*d++ = "0123456789ABCDEF"[((*c >> 4) & 0xf)];
*d++ = "0123456789ABCDEF"[(*c & 0xf)];
}
} else {
/* unreserved characters: [a-zA-Z0-9-._] */
*d++ = *c;
}
}
*d++ = '\0';
 
tmpres = malloc(d - escaped + toskip);
if (!tmpres) {
free(escaped);
return URL_FUNC_NOMEM;
}
 
memcpy(tmpres, unescaped, toskip);
memcpy(tmpres + toskip, escaped, d - escaped);
*result = tmpres;
 
free(escaped);
 
return URL_FUNC_OK;
}
 
 
#ifdef TEST
 
int main(int argc, char *argv[])
{
int i;
url_func_result res;
char *s;
url_init();
for (i = 1; i != argc; i++) {
/* printf("==> '%s'\n", argv[i]);
res = url_normalize(argv[i], &s);
if (res == URL_FUNC_OK) {
printf("<== '%s'\n", s);
free(s);
}*/
/* printf("==> '%s'\n", argv[i]);
res = url_host(argv[i], &s);
if (res == URL_FUNC_OK) {
printf("<== '%s'\n", s);
free(s);
}*/
if (1 != i) {
res = url_join(argv[i], argv[1], &s);
if (res == URL_FUNC_OK) {
printf("'%s' + '%s' \t= '%s'\n", argv[1],
argv[i], s);
free(s);
}
}
/* printf("'%s' => ", argv[i]);
res = url_nice(argv[i], &s, true);
if (res == URL_FUNC_OK) {
printf("'%s', ", s);
free(s);
} else {
printf("failed %u, ", res);
}
res = url_nice(argv[i], &s, false);
if (res == URL_FUNC_OK) {
printf("'%s', ", s);
free(s);
} else {
printf("failed %u, ", res);
}
printf("\n");*/
}
return 0;
}
 
void regcomp_wrapper(regex_t *preg, const char *regex, int cflags)
{
char errbuf[200];
int r;
r = regcomp(preg, regex, cflags);
if (r) {
regerror(r, preg, errbuf, sizeof errbuf);
fprintf(stderr, "Failed to compile regexp '%s'\n", regex);
fprintf(stderr, "error: %s\n", errbuf);
exit(1);
}
}
 
#endif
/programs/network/netsurf/netsurf/utils/url.h
0,0 → 1,64
/*
* Copyright 2005 James Bursa <bursa@users.sourceforge.net>
* Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/**
* \file utils/url.h
* \brief URL parsing and joining (interface).
*/
 
#ifndef _NETSURF_UTILS_URL_H_
#define _NETSURF_UTILS_URL_H_
 
/** File url prefix */
#define FILE_SCHEME_PREFIX "file:///"
/** File url prefix length */
#define FILE_SCHEME_PREFIX_LEN 8
 
/** URL utility function return codes */
typedef enum {
URL_FUNC_OK, /**< No error */
URL_FUNC_NOMEM, /**< Insufficient memory */
URL_FUNC_FAILED /**< Non fatal error (eg failed to match regex) */
} url_func_result;
 
struct url_components {
const char *buffer;
const char *scheme;
const char *authority;
const char *path;
const char *query;
const char *fragment;
};
 
void url_init(void);
bool url_host_is_ip_address(const char *host);
url_func_result url_join(const char *rel, const char *base, char **result);
url_func_result url_host(const char *url, char **result);
url_func_result url_scheme(const char *url, char **result);
url_func_result url_nice(const char *url, char **result,
bool remove_extensions);
url_func_result url_escape(const char *unescaped, size_t toskip,
bool sptoplus, const char *escexceptions, char **result);
url_func_result url_unescape(const char *str, char **result);
url_func_result url_path(const char *url, char **result);
 
char *path_to_url(const char *path);
char *url_to_path(const char *url);
 
#endif
/programs/network/netsurf/netsurf/utils/useragent.c
0,0 → 1,79
/*
* Copyright 2007 Daniel Silverstone <dsilvers@digital-scurf.org>
* Copyright 2007 Rob Kendrick <rjek@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <stdio.h>
#include <stdlib.h>
 
#include "utils/config.h"
#include "utils/utsname.h"
#include "desktop/netsurf.h"
#include "utils/log.h"
#include "utils/useragent.h"
 
static const char *core_user_agent_string = NULL;
 
#ifndef NETSURF_UA_FORMAT_STRING
#define NETSURF_UA_FORMAT_STRING "NetSurf/%d.%d (%s)"
#endif
 
/**
* Prepare core_user_agent_string with a string suitable for use as a
* user agent in HTTP requests.
*/
static void
user_agent_build_string(void)
{
struct utsname un;
const char *sysname = "Unknown";
char *ua_string;
int len;
 
if (uname(&un) >= 0) {
sysname = un.sysname;
}
 
len = snprintf(NULL, 0, NETSURF_UA_FORMAT_STRING,
netsurf_version_major,
netsurf_version_minor,
sysname);
ua_string = malloc(len + 1);
if (!ua_string) {
/** \todo this needs handling better */
return;
}
snprintf(ua_string, len + 1,
NETSURF_UA_FORMAT_STRING,
netsurf_version_major,
netsurf_version_minor,
sysname);
 
core_user_agent_string = ua_string;
 
LOG(("Built user agent \"%s\"", core_user_agent_string));
}
 
/* This is a function so that later we can override it trivially */
const char *
user_agent_string(void)
{
if (core_user_agent_string == NULL)
user_agent_build_string();
return core_user_agent_string;
}
 
/programs/network/netsurf/netsurf/utils/useragent.h
0,0 → 1,30
/*
* Copyright 2007 Daniel Silverstone <dsilvers@digital-scurf.org>
* Copyright 2007 Rob Kendrick <rjek@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef _NETSURF_UTILS_USERAGENT_H_
#define _NETSURF_UTILS_USERAGENT_H_
 
/** Retrieve the core user agent for this release.
*
* The string returned can be relied upon to exist for the duration of
* the execution of the program. There is no need to copy it.
*/
const char * user_agent_string(void);
 
#endif
/programs/network/netsurf/netsurf/utils/utf8.c
0,0 → 1,484
/*
* Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* UTF-8 manipulation functions (implementation).
*/
 
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <iconv.h>
 
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
 
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
 
#include <parserutils/charset/utf8.h>
 
#include "utils/config.h"
#include "utils/log.h"
#include "utils/utf8.h"
 
static utf8_convert_ret utf8_convert(const char *string, size_t len,
const char *from, const char *to, char **result);
 
/**
* Convert a UTF-8 multibyte sequence into a single UCS4 character
*
* Encoding of UCS values outside the UTF-16 plane has been removed from
* RFC3629. This function conforms to RFC2279, however.
*
* \param s_in The sequence to process
* \param l Length of sequence
* \return UCS4 character
*/
uint32_t utf8_to_ucs4(const char *s_in, size_t l)
{
uint32_t ucs4;
size_t len;
parserutils_error perror;
 
perror = parserutils_charset_utf8_to_ucs4((const uint8_t *) s_in, l,
&ucs4, &len);
if (perror != PARSERUTILS_OK)
ucs4 = 0xfffd;
 
return ucs4;
}
 
/**
* Convert a single UCS4 character into a UTF-8 multibyte sequence
*
* Encoding of UCS values outside the UTF-16 plane has been removed from
* RFC3629. This function conforms to RFC2279, however.
*
* \param c The character to process (0 <= c <= 0x7FFFFFFF)
* \param s Pointer to 6 byte long output buffer
* \return Length of multibyte sequence
*/
size_t utf8_from_ucs4(uint32_t c, char *s)
{
uint8_t *in = (uint8_t *) s;
size_t len = 6;
parserutils_error perror;
 
perror = parserutils_charset_utf8_from_ucs4(c, &in, &len);
if (perror != PARSERUTILS_OK) {
s[0] = 0xef;
s[1] = 0xbf;
s[2] = 0xbd;
return 3;
}
 
return 6 - len;
}
 
/**
* Calculate the length (in characters) of a NULL-terminated UTF-8 string
*
* \param s The string
* \return Length of string
*/
size_t utf8_length(const char *s)
{
return utf8_bounded_length(s, strlen(s));
}
 
/**
* Calculated the length (in characters) of a bounded UTF-8 string
*
* \param s The string
* \param l Maximum length of input (in bytes)
* \return Length of string, in characters
*/
size_t utf8_bounded_length(const char *s, size_t l)
{
size_t len;
parserutils_error perror;
 
perror = parserutils_charset_utf8_length((const uint8_t *) s, l, &len);
if (perror != PARSERUTILS_OK)
return 0;
 
return len;
}
 
/**
* Calculate the length (in bytes) of a UTF-8 character
*
* \param s Pointer to start of character
* \return Length of character, in bytes
*/
size_t utf8_char_byte_length(const char *s)
{
size_t len;
parserutils_error perror;
 
perror = parserutils_charset_utf8_char_byte_length((const uint8_t *) s,
&len);
assert(perror == PARSERUTILS_OK);
 
return len;
}
 
/**
* Find previous legal UTF-8 char in string
*
* \param s The string
* \param o Offset in the string to start at
* \return Offset of first byte of previous legal character
*/
size_t utf8_prev(const char *s, size_t o)
{
uint32_t prev;
parserutils_error perror;
 
perror = parserutils_charset_utf8_prev((const uint8_t *) s, o, &prev);
assert(perror == PARSERUTILS_OK);
 
return prev;
}
 
/**
* Find next legal UTF-8 char in string
*
* \param s The string
* \param l Maximum offset in string
* \param o Offset in the string to start at
* \return Offset of first byte of next legal character
*/
size_t utf8_next(const char *s, size_t l, size_t o)
{
uint32_t next;
parserutils_error perror;
 
perror = parserutils_charset_utf8_next((const uint8_t *) s, l, o,
&next);
assert(perror == PARSERUTILS_OK);
 
return next;
}
 
/* Cache of previous iconv conversion descriptor used by utf8_convert */
static struct {
char from[32]; /**< Encoding name to convert from */
char to[32]; /**< Encoding name to convert to */
iconv_t cd; /**< Iconv conversion descriptor */
} last_cd;
 
/**
* Finalise the UTF-8 library
*/
void utf8_finalise(void)
{
if (last_cd.cd != 0)
iconv_close(last_cd.cd);
 
/* paranoia follows */
last_cd.from[0] = '\0';
last_cd.to[0] = '\0';
last_cd.cd = 0;
}
 
/**
* Convert a UTF8 string into the named encoding
*
* \param string The NULL-terminated string to convert
* \param encname The encoding name (suitable for passing to iconv)
* \param len Length of input string to consider (in bytes), or 0
* \param result Pointer to location to store result (allocated on heap)
* \return Appropriate utf8_convert_ret value
*/
utf8_convert_ret utf8_to_enc(const char *string, const char *encname,
size_t len, char **result)
{
return utf8_convert(string, len, "UTF-8", encname, result);
}
 
/**
* Convert a string in the named encoding into a UTF-8 string
*
* \param string The NULL-terminated string to convert
* \param encname The encoding name (suitable for passing to iconv)
* \param len Length of input string to consider (in bytes), or 0
* \param result Pointer to location to store result (allocated on heap)
* \return Appropriate utf8_convert_ret value
*/
utf8_convert_ret utf8_from_enc(const char *string, const char *encname,
size_t len, char **result)
{
return utf8_convert(string, len, encname, "UTF-8", result);
}
 
/**
* Convert a string from one encoding to another
*
* \param string The NULL-terminated string to convert
* \param len Length of input string to consider (in bytes), or 0
* \param from The encoding name to convert from
* \param to The encoding name to convert to
* \param result Pointer to location in which to store result
* \return Appropriate utf8_convert_ret value
*/
utf8_convert_ret utf8_convert(const char *string, size_t len,
const char *from, const char *to, char **result)
{
iconv_t cd;
char *temp, *out, *in;
size_t slen, rlen;
 
assert(string && from && to && result);
 
if (string[0] == '\0') {
/* On AmigaOS, iconv() returns an error if we pass an
* empty string. This prevents iconv() being called as
* there is no conversion necessary anyway. */
*result = strdup("");
if (!(*result)) {
*result = NULL;
return UTF8_CONVERT_NOMEM;
}
 
return UTF8_CONVERT_OK;
}
 
if (strcasecmp(from, to) == 0) {
/* conversion from an encoding to itself == strdup */
slen = len ? len : strlen(string);
*(result) = strndup(string, slen);
if (!(*result)) {
*(result) = NULL;
return UTF8_CONVERT_NOMEM;
}
 
return UTF8_CONVERT_OK;
}
 
in = (char *)string;
 
/* we cache the last used conversion descriptor,
* so check if we're trying to use it here */
if (strncasecmp(last_cd.from, from, sizeof(last_cd.from)) == 0 &&
strncasecmp(last_cd.to, to, sizeof(last_cd.to)) == 0) {
cd = last_cd.cd;
}
else {
/* no match, so create a new cd */
cd = iconv_open(to, from);
if (cd == (iconv_t)-1) {
if (errno == EINVAL)
return UTF8_CONVERT_BADENC;
/* default to no memory */
return UTF8_CONVERT_NOMEM;
}
 
/* close the last cd - we don't care if this fails */
if (last_cd.cd)
iconv_close(last_cd.cd);
 
/* and copy the to/from/cd data into last_cd */
strncpy(last_cd.from, from, sizeof(last_cd.from));
strncpy(last_cd.to, to, sizeof(last_cd.to));
last_cd.cd = cd;
}
 
slen = len ? len : strlen(string);
/* Worst case = ASCII -> UCS4, so allocate an output buffer
* 4 times larger than the input buffer, and add 4 bytes at
* the end for the NULL terminator
*/
rlen = slen * 4 + 4;
 
temp = out = malloc(rlen);
if (!out)
return UTF8_CONVERT_NOMEM;
 
/* perform conversion */
if (iconv(cd, (void *) &in, &slen, &out, &rlen) == (size_t)-1) {
free(temp);
/* clear the cached conversion descriptor as it's invalid */
if (last_cd.cd)
iconv_close(last_cd.cd);
last_cd.from[0] = '\0';
last_cd.to[0] = '\0';
last_cd.cd = 0;
/** \todo handle the various cases properly
* There are 3 possible error cases:
* a) Insufficiently large output buffer
* b) Invalid input byte sequence
* c) Incomplete input sequence */
return UTF8_CONVERT_NOMEM;
}
 
*(result) = realloc(temp, out - temp + 4);
if (!(*result)) {
free(temp);
*(result) = NULL; /* for sanity's sake */
return UTF8_CONVERT_NOMEM;
}
 
/* NULL terminate - needs 4 characters as we may have
* converted to UTF-32 */
memset((*result) + (out - temp), 0, 4);
 
return UTF8_CONVERT_OK;
}
 
static utf8_convert_ret utf8_convert_html_chunk(iconv_t cd,
const char *chunk, size_t inlen,
char **out, size_t *outlen)
{
size_t ret, esclen;
uint32_t ucs4;
char *pescape, escape[11];
 
while (inlen > 0) {
ret = iconv(cd, (void *) &chunk, &inlen, (void *) out, outlen);
if (ret != (size_t) -1)
break;
 
if (errno != EILSEQ)
return UTF8_CONVERT_NOMEM;
 
ucs4 = utf8_to_ucs4(chunk, inlen);
esclen = snprintf(escape, sizeof(escape), "&#x%06x;", ucs4);
pescape = escape;
ret = iconv(cd, (void *) &pescape, &esclen,
(void *) out, outlen);
if (ret == (size_t) -1)
return UTF8_CONVERT_NOMEM;
 
esclen = utf8_next(chunk, inlen, 0);
chunk += esclen;
inlen -= esclen;
}
 
return UTF8_CONVERT_OK;
}
 
/**
* Convert a UTF-8 encoded string into a string of the given encoding,
* applying HTML escape sequences where necessary.
*
* \param string String to convert (NUL-terminated)
* \param encname Name of encoding to convert to
* \param len Length, in bytes, of the input string, or 0
* \param result Pointer to location to receive result
* \return Appropriate utf8_convert_ret value
*/
utf8_convert_ret utf8_to_html(const char *string, const char *encname,
size_t len, char **result)
{
iconv_t cd;
const char *in;
char *out, *origout;
size_t off, prev_off, inlen, outlen, origoutlen, esclen;
utf8_convert_ret ret;
char *pescape, escape[11];
 
if (len == 0)
len = strlen(string);
 
cd = iconv_open(encname, "UTF-8");
if (cd == (iconv_t) -1) {
if (errno == EINVAL)
return UTF8_CONVERT_BADENC;
/* default to no memory */
return UTF8_CONVERT_NOMEM;
}
 
/* Worst case is ASCII -> UCS4, with all characters escaped:
* "&#xYYYYYY;", thus each input character may become a string
* of 10 UCS4 characters, each 4 bytes in length */
origoutlen = outlen = len * 10 * 4;
origout = out = malloc(outlen);
if (out == NULL) {
iconv_close(cd);
return UTF8_CONVERT_NOMEM;
}
 
/* Process input in chunks between characters we must escape */
prev_off = off = 0;
while (off < len) {
/* Must escape '&', '<', and '>' */
if (string[off] == '&' || string[off] == '<' ||
string[off] == '>') {
if (off - prev_off > 0) {
/* Emit chunk */
in = string + prev_off;
inlen = off - prev_off;
ret = utf8_convert_html_chunk(cd, in, inlen,
&out, &outlen);
if (ret != UTF8_CONVERT_OK) {
free(origout);
iconv_close(cd);
return ret;
}
}
 
/* Emit mandatory escape */
esclen = snprintf(escape, sizeof(escape),
"&#x%06x;", string[off]);
pescape = escape;
ret = utf8_convert_html_chunk(cd, pescape, esclen,
&out, &outlen);
if (ret != UTF8_CONVERT_OK) {
free(origout);
iconv_close(cd);
return ret;
}
 
prev_off = off = utf8_next(string, len, off);
} else {
off = utf8_next(string, len, off);
}
}
 
/* Process final chunk */
if (prev_off < len) {
in = string + prev_off;
inlen = len - prev_off;
ret = utf8_convert_html_chunk(cd, in, inlen, &out, &outlen);
if (ret != UTF8_CONVERT_OK) {
free(origout);
iconv_close(cd);
return ret;
}
}
 
iconv_close(cd);
 
/* Shrink-wrap */
*result = realloc(origout, origoutlen - outlen + 4);
if (*result == NULL) {
free(origout);
return UTF8_CONVERT_NOMEM;
}
memset(*result + (origoutlen - outlen), 0, 4);
 
return UTF8_CONVERT_OK;
}
 
 
/programs/network/netsurf/netsurf/utils/utf8.h
0,0 → 1,70
/*
* Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
/** \file
* UTF-8 manipulation functions (interface).
*/
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
 
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
 
 
#ifndef _NETSURF_UTILS_UTF8_H_
#define _NETSURF_UTILS_UTF8_H_
 
#include <stdint.h>
 
typedef enum {
UTF8_CONVERT_OK,
UTF8_CONVERT_NOMEM,
UTF8_CONVERT_BADENC
} utf8_convert_ret;
 
uint32_t utf8_to_ucs4(const char *s, size_t l);
size_t utf8_from_ucs4(uint32_t c, char *s);
 
size_t utf8_length(const char *s);
size_t utf8_bounded_length(const char *s, size_t l);
 
size_t utf8_char_byte_length(const char *s);
 
size_t utf8_prev(const char *s, size_t o);
size_t utf8_next(const char *s, size_t l, size_t o);
 
utf8_convert_ret utf8_to_enc(const char *string, const char *encname,
size_t len, char **result);
utf8_convert_ret utf8_from_enc(const char *string, const char *encname,
size_t len, char **result);
 
utf8_convert_ret utf8_to_html(const char *string, const char *encname,
size_t len, char **result);
 
/* These two are platform specific */
utf8_convert_ret utf8_to_local_encoding(const char *string, size_t len,
char **result);
utf8_convert_ret utf8_from_local_encoding(const char *string, size_t len,
char **result);
 
void utf8_finalise(void);
 
#endif
/programs/network/netsurf/netsurf/utils/utils.c
0,0 → 1,433
/*
* Copyright 2007 Rob Kendrick <rjek@netsurf-browser.org>
* Copyright 2004-2007 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2004 John Tytgat <joty@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <regex.h>
#include <time.h>
 
#include "utils/config.h"
#include "utils/messages.h"
#include "utils/utf8.h"
#include "utils/utils.h"
#include "utils/log.h"
 
void *
ns_realloc(void *ptr, size_t size, void *pw)
{
(void)pw;
if (ptr == NULL)
return size > 0 ? malloc(size) : NULL;
if (size == 0) {
free(ptr);
return NULL;
}
return realloc(ptr, size);
}
 
char * strip(char * const s)
{
size_t i;
for (i = strlen(s);
i != 0 && (s[i - 1] == ' ' || s[i - 1] == '\n' ||
s[i - 1] == '\r' || s[i - 1] == '\t');
i--)
;
s[i] = 0;
return s + strspn(s, " \t\r\n");
}
 
int whitespace(const char * str)
{
unsigned int i;
for (i = 0; i < strlen(str); i++)
if (!isspace(str[i]))
return 0;
return 1;
}
 
/**
* returns a string without its underscores
* \param replacespace true to insert a space where there was an underscore
*/
 
char *remove_underscores(const char *s, bool replacespace)
{
size_t i, ii, len;
char *ret;
len = strlen(s);
ret = malloc(len + 1);
if (ret == NULL)
return NULL;
for (i = 0, ii = 0; i < len; i++) {
if (s[i] != '_')
ret[ii++] = s[i];
else if (replacespace)
ret[ii++] = ' ';
}
ret[ii] = '\0';
return ret;
}
 
/**
* Replace consecutive whitespace with a single space.
*
* \param s source string
* \return heap allocated result, or 0 on memory exhaustion
*/
 
char * squash_whitespace(const char *s)
{
char *c = malloc(strlen(s) + 1);
int i = 0, j = 0;
if (!c)
return 0;
do {
if (s[i] == ' ' || s[i] == '\n' || s[i] == '\r' ||
s[i] == '\t') {
c[j++] = ' ';
while (s[i] == ' ' || s[i] == '\n' || s[i] == '\r' ||
s[i] == '\t')
i++;
}
c[j++] = s[i++];
} while (s[i - 1] != 0);
return c;
}
 
 
/**
* Converts NUL terminated UTF-8 encoded string s containing zero or more
* spaces (char 32) or TABs (char 9) to non-breaking spaces
* (0xC2 + 0xA0 in UTF-8 encoding).
*
* Caller needs to free() result. Returns NULL in case of error. No
* checking is done on validness of the UTF-8 input string.
*/
char *cnv_space2nbsp(const char *s)
{
const char *srcP;
char *d, *d0;
unsigned int numNBS;
/* Convert space & TAB into non breaking space character (0xA0) */
for (numNBS = 0, srcP = (const char *)s; *srcP != '\0'; ++srcP)
if (*srcP == ' ' || *srcP == '\t')
++numNBS;
if ((d = (char *)malloc((srcP - s) + numNBS + 1)) == NULL)
return NULL;
for (d0 = d, srcP = (const char *)s; *srcP != '\0'; ++srcP) {
if (*srcP == ' ' || *srcP == '\t') {
*d0++ = 0xC2;
*d0++ = 0xA0;
} else
*d0++ = *srcP;
}
*d0 = '\0';
return d;
}
 
/**
* Check if a directory exists.
*/
 
bool is_dir(const char *path)
{
struct stat s;
 
if (stat(path, &s))
return false;
 
return S_ISDIR(s.st_mode) ? true : false;
}
 
 
/**
* Compile a regular expression, handling errors.
*
* Parameters as for regcomp(), see man regex.
*/
 
void regcomp_wrapper(regex_t *preg, const char *regex, int cflags)
{
int r;
r = regcomp(preg, regex, cflags);
if (r) {
char errbuf[200];
regerror(r, preg, errbuf, sizeof errbuf);
fprintf(stderr, "Failed to compile regexp '%s'\n", regex);
die(errbuf);
}
}
 
/** We can have a fairly good estimate of how long the buffer needs to
* be. The unsigned long can store a value representing a maximum size
* of around 4 GB. Therefore the greatest space required is to
* represent 1023MB. Currently that would be represented as "1023MB" so 12
* including a null terminator.
* Ideally we would be able to know this value for sure, in the mean
* time the following should suffice.
**/
 
#define BYTESIZE_BUFFER_SIZE 20
 
/**
* Does a simple conversion which assumes the user speaks English. The buffer
* returned is one of three static ones so may change each time this call is
* made. Don't store the buffer for later use. It's done this way for
* convenience and to fight possible memory leaks, it is not necessarily pretty.
**/
 
char *human_friendly_bytesize(unsigned long bsize) {
static char buffer1[BYTESIZE_BUFFER_SIZE];
static char buffer2[BYTESIZE_BUFFER_SIZE];
static char buffer3[BYTESIZE_BUFFER_SIZE];
static char *curbuffer = buffer3;
enum {bytes, kilobytes, megabytes, gigabytes} unit = bytes;
static char units[][7] = {"Bytes", "kBytes", "MBytes", "GBytes"};
 
float bytesize = (float)bsize;
 
if (curbuffer == buffer1)
curbuffer = buffer2;
else if (curbuffer == buffer2)
curbuffer = buffer3;
else
curbuffer = buffer1;
 
if (bytesize > 1024) {
bytesize /= 1024;
unit = kilobytes;
}
 
if (bytesize > 1024) {
bytesize /= 1024;
unit = megabytes;
}
 
if (bytesize > 1024) {
bytesize /= 1024;
unit = gigabytes;
}
 
sprintf(curbuffer, "%3.2f%s", bytesize, messages_get(units[unit]));
 
return curbuffer;
}
 
/**
* Create an RFC 1123 compliant date string from a Unix timestamp
*
* \param t The timestamp to consider
* \return Pointer to buffer containing string - invalidated by next call.
*/
const char *rfc1123_date(time_t t)
{
static char ret[30];
 
struct tm *tm = gmtime(&t);
const char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" },
*months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
 
snprintf(ret, sizeof ret, "%s, %02d %s %d %02d:%02d:%02d GMT",
days[tm->tm_wday], tm->tm_mday, months[tm->tm_mon],
tm->tm_year + 1900, tm->tm_hour, tm->tm_min,
tm->tm_sec);
 
return ret;
}
 
/**
* Returns a number of centiseconds, that increases in real time, for the
* purposes of measuring how long something takes in wall-clock terms. It uses
* gettimeofday() for this. Should the call to gettimeofday() fail, it returns
* zero.
*
* \return number of centiseconds that increases monotonically
*/
unsigned int wallclock(void)
{
struct timeval tv;
 
LOG(("WALLCLOCK IS HERE"));
if (gettimeofday(&tv, NULL) == -1)
{LOG(("And -1"));return 0;}
 
LOG(("And time"));
return ((tv.tv_sec * 100) + (tv.tv_usec / 10000));
}
 
#ifndef HAVE_STRCASESTR
 
/**
* Case insensitive strstr implementation
*
* \param haystack String to search in
* \param needle String to look for
* \return Pointer to start of found substring, or NULL if not found
*/
char *strcasestr(const char *haystack, const char *needle)
{
size_t needle_len = strlen(needle);
const char * last_start = haystack + (strlen(haystack) - needle_len);
 
while (haystack <= last_start) {
if (strncasecmp(haystack, needle, needle_len) == 0)
return (char *)haystack;
haystack++;
}
 
return NULL;
}
 
#endif
 
#ifndef HAVE_STRNDUP
 
/**
* Duplicate up to n characters of a string.
*/
 
char *strndup(const char *s, size_t n)
{
size_t len;
char *s2;
 
for (len = 0; len != n && s[len]; len++)
continue;
 
s2 = malloc(len + 1);
if (!s2)
return 0;
 
memcpy(s2, s, len);
s2[len] = 0;
return s2;
}
 
#endif
 
#ifndef HAVE_STRCHRNUL
 
/**
* Find the first occurrence of C in S or the final NUL byte.
*/
char *strchrnul (const char *s, int c_in)
{
const unsigned char *us = (const unsigned char *) s;
 
while (*us != c_in && *us != '\0')
us++;
 
return (void *) us;
}
 
#endif
 
#ifndef HAVE_UTSNAME
#include "utils/utsname.h"
 
int uname(struct utsname *buf) {
strcpy(buf->sysname,"windows");
strcpy(buf->nodename,"nodename");
strcpy(buf->release,"release");
strcpy(buf->version,"version");
strcpy(buf->machine,"pc");
return 0;
}
#endif
 
#ifndef HAVE_REALPATH
char *realpath(const char *path, char *resolved_path)
{
char *ret;
if (resolved_path == NULL) {
ret=strdup(path);
} else {
ret = resolved_path;
strcpy(resolved_path, path);
}
return ret;
}
 
#ifndef HAVE_INETATON
 
 
int inet_aton(const char *cp, struct in_addr *inp)
{
unsigned int b1, b2, b3, b4;
unsigned char c;
 
if (strspn(cp, "0123456789.") < strlen(cp))
return 0;
 
if (sscanf(cp, "%3u.%3u.%3u.%3u%c", &b1, &b2, &b3, &b4, &c) != 4)
return 0;
 
if ((b1 > 255) || (b2 > 255) || (b3 > 255) || (b4 > 255))
return 0;
 
inp->s_addr = b4 << 24 | b3 << 16 | b2 << 8 | b1;
 
return 1;
}
 
#endif
 
#ifndef HAVE_INETPTON
 
int inet_pton(int af, const char *src, void *dst)
{
int ret;
 
if (af == AF_INET) {
ret = inet_aton(src, dst);
}
#if !defined(NO_IPV6)
else if (af == AF_INET6) {
/* TODO: implement v6 address support */
ret = -1;
errno = EAFNOSUPPORT;
}
#endif
else {
ret = -1;
errno = EAFNOSUPPORT;
}
 
return ret;
}
 
#endif
 
 
#endif
/programs/network/netsurf/netsurf/utils/utils.h
0,0 → 1,190
/*
* Copyright 2004-2007 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004 John Tytgat <joty@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef _NETSURF_UTILS_UTILS_H_
#define _NETSURF_UTILS_UTILS_H_
 
#include <inttypes.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <regex.h>
#include <assert.h>
 
#ifndef NOF_ELEMENTS
#define NOF_ELEMENTS(array) (sizeof(array)/sizeof(*(array)))
#endif
 
#ifndef ABS
#define ABS(x) (((x)>0)?(x):(-(x)))
#endif
 
#ifdef __MINT__ /* avoid using GCCs builtin min/max functions */
#undef min
#undef max
#endif
 
#ifndef min
#define min(x,y) (((x)<(y))?(x):(y))
#endif
 
#ifndef max
#define max(x,y) (((x)>(y))?(x):(y))
#endif
 
#ifndef PRIxPTR
#define PRIxPTR "x"
#endif
 
#ifndef PRId64
#define PRId64 "lld"
#endif
 
#if defined(_WIN32)
#define SSIZET_FMT "Iu"
#else
#define SSIZET_FMT "zd"
#endif
 
#if defined(__GNUC__) && (__GNUC__ < 3)
#define FLEX_ARRAY_LEN_DECL 0
#else
#define FLEX_ARRAY_LEN_DECL
#endif
 
#if defined(__HAIKU__) || defined(__BEOS__)
#define strtof(s,p) ((float)(strtod((s),(p))))
#endif
 
#if !defined(ceilf) && defined(__MINT__)
#define ceilf(x) (float)ceil((double)x)
#endif
 
/**
* Calculate length of constant C string.
*
* \param x a constant C string.
* \return the length of C string without its terminating NUL accounted.
*/
#define SLEN(x) (sizeof((x)) - 1)
 
enum query_response {
QUERY_CONTINUE,
QUERY_YES,
QUERY_NO,
QUERY_ESCAPE
};
 
typedef int query_id;
 
#define QUERY_INVALID ((query_id)-1)
 
typedef struct
{
void (*confirm)(query_id id, enum query_response res, void *pw);
void (*cancel)(query_id, enum query_response res, void *pw);
} query_callback;
 
#ifdef HAVE_MKDIR
#define nsmkdir(dir, mode) mkdir((dir), (mode))
#else
#define nsmkdir(dir, mode) mkdir((dir))
#endif
 
#ifndef timeradd
#define timeradd(a, aa, result) \
do { \
(result)->tv_sec = (a)->tv_sec + (aa)->tv_sec; \
(result)->tv_usec = (a)->tv_usec + (aa)->tv_usec; \
if ((result)->tv_usec >= 1000000) { \
++(result)->tv_sec; \
(result)->tv_usec -= 1000000; \
} \
} while (0)
#endif
 
#ifndef timersub
#define timersub(a, aa, result) \
do { \
(result)->tv_sec = (a)->tv_sec - (aa)->tv_sec; \
(result)->tv_usec = (a)->tv_usec - (aa)->tv_usec; \
if ((result)->tv_usec < 0) { \
--(result)->tv_sec; \
(result)->tv_usec += 1000000; \
} \
} while (0)
#endif
 
 
/**
* Private-word-capable realloc() implementation which
* behaves as most NS libraries expect in the face of
* realloc(ptr, 0) and realloc(NULL, size).
*
* \param ptr The pointer for reallocation
* \param size The number of bytes for the allocation
* \param pw A "private word" which we ignore.
* \return The new pointer (NULL on frees or errors)
*/
void *ns_realloc(void *ptr, size_t size, void *pw);
 
char * strip(char * const s);
int whitespace(const char * str);
char * squash_whitespace(const char * s);
char *remove_underscores(const char *s, bool replacespace);
char *cnv_space2nbsp(const char *s);
bool is_dir(const char *path);
void regcomp_wrapper(regex_t *preg, const char *regex, int cflags);
char *human_friendly_bytesize(unsigned long bytesize);
const char *rfc1123_date(time_t t);
unsigned int wallclock(void);
 
/**
* Return a hex digit for the given numerical value.
*
* \return character in range 0-9a-f
*/
inline static char digit2lowcase_hex(unsigned char digit) {
assert(digit < 16);
return "0123456789abcdef"[digit];
}
 
/**
* Return a hex digit for the given numerical value.
*
* \return character in range 0-9A-F
*/
inline static char digit2uppercase_hex(unsigned char digit) {
assert(digit < 16);
return "0123456789ABCDEF"[digit];
}
 
 
/* Platform specific functions */
void die(const char * const error);
void warn_user(const char *warning, const char *detail);
query_id query_user(const char *query, const char *detail,
const query_callback *cb, void *pw, const char *yes, const char *no);
void query_close(query_id);
void PDF_Password(char **owner_pass, char **user_pass, char *path);
char *filename_from_path(char *path);
bool path_add_part(char *path, int length, const char *newpart);
#endif
/programs/network/netsurf/netsurf/utils/utsname.h
0,0 → 1,39
/*
* Copyright 2010 Vincent Sanders <vince@kyllikki.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
 
#ifndef _NETSURF_UTILS_UTSNAME_H_
#define _NETSURF_UTILS_UTSNAME_H_
 
#ifdef HAVE_UTSNAME
#include <sys/utsname.h>
#else
/* from posix spec */
struct utsname {
char sysname[65]; /* Operating system name (e.g., "Linux") */
char nodename[65]; /* Name within "some implementation-defined
network" */
char release[65]; /* OS release (e.g., "2.6.28") */
char version[65]; /* OS version */
char machine[65]; /* Hardware identifier */
};
 
int uname(struct utsname *buf);
 
#endif
 
#endif
/programs/network/netsurf/netsurf/utils/valgrind.supp
0,0 → 1,14
# Valgrind suppression file for NetSurf
 
# Suppress a valgrind message about use of uninitialized memory in strchrnul().
# This use is OK because it provides only a speedup.
{
strchrnul-addr4
Memcheck:Addr4
fun:strchrnul
}
{
strchrnul-addr8
Memcheck:Addr8
fun:strchrnul
}
/programs/network/netsurf/netsurf/utils/warning-blame.sh
0,0 → 1,64
#!/bin/sh
 
# Copyright 2007 Vincent Sanders <vince@debian.org>
# All rights reserved.
 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the Author nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
 
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
 
 
# where to store the processed list of warnings
WARNING_LIST=/tmp/warning-list
 
if [ $# -gt 1 ]; then
if [ -f $1 ]; then
cp $1 ${WARNING_LIST}
else
echo "Need a valid warning file"
exit 1
fi
else
make clean 2>&1 >/dev/null
make 2>&1 |grep "warning:" | sort | uniq > ${WARNING_LIST}
fi
 
for blamefile in $(cat ${WARNING_LIST} | cut -f 1 -d ':' | sort | uniq ); do
if [ -f ${blamefile} ]; then
svn blame ${blamefile} >/tmp/blame
 
cat ${WARNING_LIST} | grep "^${blamefile}" >/tmp/blame-warnings
 
while read warning; do
echo ${warning}
 
lineno=$(echo ${warning} | cut -f 2 -d ':' ; )
 
cat /tmp/blame | head -n ${lineno} | tail -n 1
 
done < /tmp/blame-warnings
rm /tmp/blame-warnings
else
echo "Unable to find ${blamefile}"
fi
done
Property changes:
Added: svn:executable
+*
\ No newline at end of property