netsurf: branch vince/pdf updated. release/3.8-10-gbae4db1
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/bae4db1b59737e95bd11c...
...commit http://git.netsurf-browser.org/netsurf.git/commit/bae4db1b59737e95bd11c60...
...tree http://git.netsurf-browser.org/netsurf.git/tree/bae4db1b59737e95bd11c60ca...
The branch, vince/pdf has been updated
discards 8bd19b1cf342085998364bc403a3af5febfdde0c (commit)
discards 4953bd0fe1914860ede6c80c0d6c7fcb5492f613 (commit)
discards 5b02a041fab685098e11fe14f9e6486b60730661 (commit)
discards f0af2265fff4a451ed98ff90fdbe22c3b40dd173 (commit)
discards bbb144bcbd8545948cea2ec1973c8203e0b07906 (commit)
discards 0d486a1ffe457478d4303ebc72fc000b853bfcb3 (commit)
via bae4db1b59737e95bd11c60ca7f0abe7f1b6d994 (commit)
via 6f543d129bf6f73baefacf9ae5af19c0d2a74c2e (commit)
via 689faa4fbb3d07dd4277f138b0c9b75c96577978 (commit)
via 7eea4ef0b049a751506b7021264290cea07dc85c (commit)
via 57a45534c988e0bc83affee2a890d8ee60692e8f (commit)
via 1b4614b66a8adfecba244c4fa4dfa9b2ecbfac47 (commit)
via e6a2ff5bba7adc092a7af8f9604d0a440e535624 (commit)
via f45d84631cf68bb14164139823154097329384d0 (commit)
via ba4b06dc04e01a7fe61852c11035a873148d969d (commit)
via dd5d97b61c2a56742de4090659ff78eda4c0cdc3 (commit)
via 66fe825c8df84da71ec3b2a69bf4ad3283c6159b (commit)
via 7fae41b6d3f88f99a812f7364b5805dfd95e0fec (commit)
via 912aa3774e2889070b28ecd94df11ac228666457 (commit)
via 9142bab7363095e538d1f24bed6ae32a9b1d5820 (commit)
via 026fb31d2df8faee43eedf2e45dfddf1425b80df (commit)
via 9d8f37ca10c35fea81caa08369c236722ebff9d5 (commit)
via d54e0461adafd79ca5d56e57e7816e2b9b56878c (commit)
via 487309a1e673c406f97cdd3cfd64b77f7d2e5582 (commit)
via 4765c68a15545a2c5465781f2957d771e5c7eb77 (commit)
via f4620a3f68cf386394cbdd595827a2b60525b26f (commit)
via eee67a65e8336b05de504db07f3c9d93879f0ca8 (commit)
via 5dd5d5da4b1cc8cdb780559f8e1ea0d058b27b20 (commit)
via 865796486d979a26a0c5e31fd046918d44c58899 (commit)
via 7d645bee91efa9174c0b3dca1102cbb1b4ad246b (commit)
via 579465df5003dfdecf74228557bd927557fb3b7a (commit)
via bec6428c6c1ad720cc41a7b3428b9b2d26c1dbeb (commit)
via 2f663987c558077f34505ea28dce183678d8175e (commit)
via 16cc1121e30d3194cbf04d23cb5b11273e45250d (commit)
via a8248a7bb9555e558cb8c7eed1146c62ab024130 (commit)
via 650ac58604104c3097c83718d32331f06779b52f (commit)
via 2f3c7e24c022d4588856b8bae4d41482a7e9b41e (commit)
via 5f1defd4a7700f8f39f8b30c25fada31c8bb1b71 (commit)
via a6c595f4f305c43d9da825ad31c0011fe02d0684 (commit)
via c938d1962bed31f0723707fc978bb65ab5a47ef2 (commit)
via 0f18440fd5e4296e90152744838110932c017969 (commit)
via b46f1257c3db75cdaa0794f96e3802f4c13bb4e6 (commit)
via 7964629914cd955a48c3ed52e27cf79ee1ece3f6 (commit)
via 122f09af5d1786d1c0b6ae6175e5eb91170dea7f (commit)
via 7d22759f5ee22c839b943455369fa270dd884753 (commit)
via c1fb25e0746e02a2252d65f8ac5e46824c6d446c (commit)
via 35f28f0c9a9b791773d851870c17e5555000d30d (commit)
via 9c29935f3ca274d002517ed09e17921e42dbaf21 (commit)
via 097f8dcde5c212d91bf25ed9256860cb2b8bfa3d (commit)
via 10033267a2a0a457f58faf76c3d1a7b813132eb0 (commit)
via 423b04d4069c013733aa99f06bf9a5beefd552fd (commit)
via cd0309fa836c3d7846f6f009ba50b66b78c47ffa (commit)
via cf17ecbbc7281729b1780ef7e1d65f9a75138cc0 (commit)
via 1cdacf8ae5834c2705ff0e1e021d42dd624ed19e (commit)
via 58240e4967129214c82b2592be1391c41f653994 (commit)
via d9dacf9bb2ef38faa602e73911227a9db721f1bf (commit)
via 297236ae0ca2e7cab8849242286c57efbb9c1750 (commit)
via 77ae1ed7581e80691fc9e5bafd910a3f36a7d12a (commit)
via 5e97a3cb26e99ceac27f95be7a7527c630910ebf (commit)
via 66a97b863ce450bb0932ea4813b81c9b62d84b83 (commit)
via c55a31aa110cd5f469a7758f63c0f0dbb26da2c9 (commit)
via 97810d0c1aeab995d0b27c976c8d3e9e1a0c8b3f (commit)
via e41e558c5faeac4c9619362ac441f0e0ac831d25 (commit)
via 6144993c8a9e93332c47e9b57da190ad57ac28fb (commit)
via 42d596bc11d920f953a8d19a46981cb359cf9144 (commit)
via 81a59f2f7c7cf06c1457893880ebfeba82e902cc (commit)
via 9fa6c1e0fb2d6f5a0c95e7680b0ad24f9f7615db (commit)
via 7458cfa9992f66b87f3effef5c86405888f9410b (commit)
via 982ca8753769b34fea23bc1df77de4357ee6fda9 (commit)
via 92424b69464dfc2f917e90183b2eaddd737ccec8 (commit)
via 0601b7dbec3c416aec475a98d419b85045e6cc49 (commit)
via 80e8c74a698f2063199972b88226fb115249b1cc (commit)
via ad0a75af8fff0d6444bdf14b711f794b3f165c73 (commit)
via e5f2ea9d7ae2182a499c68f25ae66b331d114046 (commit)
via c986c212bf1a7a31382b0a43428ef32392364f87 (commit)
via f5f2ebb37a6ba75b4447f6ad817d06f81524045e (commit)
via ae126cfdd5ca2ed8e32ce5ba1d3d9e6d3c49ce87 (commit)
via 19eb0517278f6e7a533903cc50037932a8cfbfb9 (commit)
via 97f9e2d9f57048f524492392ad13b8806ee2b94f (commit)
via 9fecbc655474bef3001c1c424c2e7c8c92c6010e (commit)
via fa546661ad7365507f8dde5d75fb27fae63f27a2 (commit)
via add6dcc0158526bde3cb0785083c0761153fad57 (commit)
via bc280f0e3fb4fbbea868fb4b17f1ea71ecd90ead (commit)
via ca0514ea9218d3b419071056d954bbff9f18a1ac (commit)
via 0df7ceb8f1483f5764d46c3c1da3fc51c04639bf (commit)
via 527541ddbda27d330fa3f87533cea80314f974a7 (commit)
via 3d20a3974c62a284325f8e6f12b7fbb50b4607b7 (commit)
via 42459f72c1f0e3dcdc1686447f1522c4fe9e3134 (commit)
via 341cfc115b6a022ef9d3d9e8f909bdd4539f0f93 (commit)
via 57a6328b141f1f46099ee3c9379b43205c8771d0 (commit)
via eeb7be1cbf8069cc1304dac4136e7c2090d49e89 (commit)
via 09b015bf11be087bdc50e740c2f8ce6a6ff5853e (commit)
via aa95a75332e274d102e6e9946d4c16ba27f7b532 (commit)
via 3afa1ce48f4dd7901e5f8646c38581c7f2e89d7a (commit)
via 62e3ee6c7ec751674c6ff1d4b5235cb1ab482e55 (commit)
via 049695fa070c23580291949053b6d1faf8ffd749 (commit)
via 948207472ac1d405e6e6552eb51c6ed1a67ee32e (commit)
via 97007d095e25af302abeb32662353f84f720863c (commit)
via 169a91ace945ca0c0747ffa0f7db5ee550188c87 (commit)
via a40dca49e8493802d7064bd8e6aaab03436568ee (commit)
via 8a931f01b958ad5862433ece6024bbde0aa4ecb8 (commit)
via 8332bf6b2a42fd03b864e46f60eeaa76b51da496 (commit)
via 5f4f23f11a1c2aaa85df6bb58f0be6e66fa7cc7b (commit)
via 66493421e65d8cbda3e17fdbe43824387e3d51a7 (commit)
via a58d97a41a6192038573da6862571dc72a560458 (commit)
via 6cabd4cd628833afa32aeb7c614ef153b4a1c985 (commit)
via 7c3da95a07f0d21860e6803567b0603127c517c1 (commit)
via 216fb88f58227f94e87d9e9926b599161a8e65bb (commit)
via dc9e7c989f1a259a8fee9a6e1a4c6be6186f7c31 (commit)
via 2a03ea30490892ac52b3da325ab78e1aa888f83e (commit)
via 1b892391d7859398c212b9fda5b532308fa6e8fd (commit)
via 2290c208ba69bb9f98d33c470712f9df5cc6c040 (commit)
via 6e0e3ea81f44c294d5f7300eb7a92483babcae49 (commit)
via 8319ead5304bb04e90dd7f473ac60e5c2a58fdeb (commit)
via 0ee536b083e19a5f2c5c9ed2932ced17dbb5eb5b (commit)
via dcb12cab5120efc6ef8f10fc5cce64990b2892bd (commit)
via 4bf20cc69389133a5b8ccea50943ac12a8470536 (commit)
via f6073cd6999de7cd734e13687efcd78c9062806d (commit)
via af8bde62148912f90df6807eeda5b9bfb40a329e (commit)
via b16b525cd380ef345c6b2faa5531532118b480a4 (commit)
via 86ac9f1331aca1c0e1b9eef03557ce7d6421f9e6 (commit)
via 1255ee3af451c8b864e44b14af8f82a22fe316b8 (commit)
via 5c20642b7ef5736bf9dc6fe57a816fad3d8cd16d (commit)
via 9b04d79e60c590e5b3c1f2566c1db75824a8c572 (commit)
via 0569fbf1709fcd7101586c9de5fb17686394a827 (commit)
via 2c7d24c5bc8b99738c25fce68c5b3e485530b5cc (commit)
via 43582c50552021bbced0ea11f0ff6c4b2b618529 (commit)
via d196ea7795ada760dbc243fe640769eb9bc65dff (commit)
via b94b96e272140f17a82ce0847e1634d081b5dc6c (commit)
via cfa5856eea7c0d840a19590baf1e66f6fee06b83 (commit)
via a8bf9b05aa94392b391d6015ed037e5c241ab172 (commit)
via 7d4349035d7981067d26dc02f750a36a9adc52cd (commit)
via 842513f10b61c799d94a0b088d656517a82f255b (commit)
via 70b6ca4376cb822487b61692187283c528fb426c (commit)
via 5efc6407d35fb47885ae6234a6e76bb3badd1b31 (commit)
via 103c015784a73e86b120e2e26b3906c6787209ef (commit)
via ec1936cc93f2f2f40d26a2913e31952e6ed24d77 (commit)
via 83f5332708d7b8cbb6a2efb76eef4bdeec318b5a (commit)
via f2121d1c0f36ef3951e0570552e70f9450f0fab5 (commit)
via a6014cae157107ec868816fcccf8689a5d6cc766 (commit)
via 1c05280b5cd23c94ed10c2a9415a500393100285 (commit)
via badc0d437adff453f046cd8f0eb46c4fa5afe2bf (commit)
via 9c164e591f7101ccafb6656cc9c8b286e2c76ca1 (commit)
via 942ef0df03df8ada109c4dd8a8802b16eeb0e8c8 (commit)
via de806db28e91e0c216200eef130d4672e29efb01 (commit)
via e864997842e157172211ee0dc749590d7547b594 (commit)
via c1e30c0c3a077fff59389b5d7f6debfece704889 (commit)
via 5094a3fd048e06a49bb232ae7eb09821c512c8a0 (commit)
via 83e8f377ad4fd99bab6da6eca0228762bc4e630e (commit)
via 42f5bb6182f90313eceb3c1b60bfd4792bbba3d5 (commit)
via 5e52c6a233bd597f1d370287239f4122044ec849 (commit)
via 256ffca9a75974f46e44cbd375937bce5575dad2 (commit)
via f3eb366679282f1db9cc2ae793bd8bc485026b21 (commit)
via fb6f33129df6d03a780b1d98f01d7095f3808373 (commit)
via d670e28d4cd98fc2566e0b4a1505c6b26aeab412 (commit)
via 911467dcbe395fa0fe16a34f11a990a6a89d8964 (commit)
via a72771f8ebdb7ec5474dcb039c92661d97dd4678 (commit)
via 3c3685eb9635cc46fe78b31d54967b62b948581e (commit)
via 473a40bc114d70d84610d40b425cf1e9bc548359 (commit)
via af554fcedf8a3c209350ccb1acfd5b233081bd18 (commit)
via d884e0e53303c22e747c8d769189e21785b7f753 (commit)
via 470dce645bc9cfca1d438f62a8ffe7a6db80a278 (commit)
via 89baae16b47fad0dcb50402e9a2ba887b05242c0 (commit)
via 29e36cdf1a6f4404f804e5c2b46d38dad929416d (commit)
via 08c275ed2c843441aad23d38646083de7a130753 (commit)
via 790d30b7888d5818a4e2521aabe2f31f04d59341 (commit)
via 110cc9fb3e098100a7ed91340a82e351a220bce1 (commit)
via 7a75ec1576fc2a4f3d445b33b1d9f00e0007643d (commit)
via fe45bc1dbea417c2258a22797ace09926b33a481 (commit)
via 17ae38771df50a81f49eebead84ff8914fb947e4 (commit)
via 328a29d22f81b838a0a6b2f1d3d5fc4dbfe5e6e7 (commit)
via f04cedef1c7742f38b0b561efcd77e0476fcbf60 (commit)
via c03405b3b3b28942d50f672e897be5cfc0f6c540 (commit)
via 128753cdcf0719b1afc919cb841fbc22bb9715aa (commit)
via 891758bb6f363f10f9a673b167230735a9183244 (commit)
via 6be6fa1b2197ffe6e511c5eff9abe14d883f8478 (commit)
via a67973f312b7cba8a6d56f9841a542a731a9ddb4 (commit)
via ae286be5a9a5c1150dfa7627f2b30a73238b506c (commit)
via cf3eba081a048d413158350000352ff2b5e5f220 (commit)
via 5776d3448c50d58af0eac8f3960200aa1b5fc1a0 (commit)
via d1c656b55f7c21b5fb96bf5e1bd8fedaa55c4fc2 (commit)
via 7bd1fb50c6415a21fae22f7bd534894e02b512bf (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (8bd19b1cf342085998364bc403a3af5febfdde0c)
\
N -- N -- N (bae4db1b59737e95bd11c60ca7f0abe7f1b6d994)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=bae4db1b59737e95bd1...
commit bae4db1b59737e95bd11c60ca7f0abe7f1b6d994
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
fix plot style float to fix path width
diff --git a/content/handlers/pdf/pdf.c b/content/handlers/pdf/pdf.c
index 89548cd..ec283aa 100644
--- a/content/handlers/pdf/pdf.c
+++ b/content/handlers/pdf/pdf.c
@@ -1,6 +1,5 @@
/*
- * Copyright 2004 James Bursa <bursa(a)users.sourceforge.net>
- * Copyright 2004 John M Bell <jmb202(a)ecs.soton.ac.uk>
+ * Copyright 2018 Vincent Sanders <vince(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -154,7 +153,7 @@ static bool pdf_convert(struct content *c)
}
/** \todo extract documents starting page number */
- pdfc->current_page = 16;
+ pdfc->current_page = 0;
pdfres = nspdf_get_page_dimensions(pdfc->doc,
pdfc->current_page,
@@ -180,12 +179,16 @@ pdf_path(const struct nspdf_style *style,
{
const struct redraw_context *ctx = ctxin;
- ctx->plot->path(ctx,
- (const struct plot_style_s *)style,
- path,
- path_length,
- style->stroke_width,
- transform);
+ struct plot_style_s nsstyle;
+
+ nsstyle.stroke_type = style->stroke_type;
+ nsstyle.stroke_width = plot_style_float_to_fixed(style->stroke_width);
+ nsstyle.stroke_colour = style->stroke_colour;
+ nsstyle.fill_type = style->fill_type;
+ nsstyle.fill_colour = style->fill_colour;
+
+ ctx->plot->path(ctx, &nsstyle, path, path_length, transform);
+
return NSPDFERROR_OK;
}
diff --git a/include/netsurf/plot_style.h b/include/netsurf/plot_style.h
index f1b6172..11d506d 100644
--- a/include/netsurf/plot_style.h
+++ b/include/netsurf/plot_style.h
@@ -50,6 +50,9 @@ typedef int32_t plot_style_fixed;
/* Convert an int to fixed point */
#define plot_style_int_to_fixed(v) ((v) << PLOT_STYLE_RADIX)
+/* Convert an float to fixed point */
+#define plot_style_float_to_fixed(v) ((v) * (1<<PLOT_STYLE_RADIX))
+
/* Convert fixed point to int */
#define plot_style_fixed_to_int(v) ((v) >> PLOT_STYLE_RADIX)
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=6f543d129bf6f73baef...
commit 6f543d129bf6f73baefacf9ae5af19c0d2a74c2e
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
allow moving forward and back clicking in window
diff --git a/content/handlers/pdf/pdf.c b/content/handlers/pdf/pdf.c
index d8c4d61..89548cd 100644
--- a/content/handlers/pdf/pdf.c
+++ b/content/handlers/pdf/pdf.c
@@ -33,8 +33,10 @@
#include "utils/messages.h"
#include "utils/utils.h"
+#include "utils/log.h"
#include "netsurf/plotters.h"
#include "netsurf/content.h"
+#include "netsurf/browser_window.h"
#include "content/llcache.h"
#include "content/content_protected.h"
@@ -46,6 +48,7 @@ typedef struct pdf_content {
struct nspdf_doc *doc;
unsigned int current_page;
+ unsigned int page_count;
} pdf_content;
static nserror nspdf2nserr(nspdferror nspdferr)
@@ -139,13 +142,19 @@ static bool pdf_convert(struct content *c)
return false;
}
+ pdfres = nspdf_page_count(pdfc->doc, &pdfc->page_count);
+ if (pdfres != NSPDFERROR_OK) {
+ content_broadcast_errorcode(c, NSERROR_INVALID);
+ return false;
+ }
+
pdfres = nspdf_get_title(pdfc->doc, &title);
if (pdfres == NSPDFERROR_OK) {
content__set_title(c, lwc_string_data(title));
}
/** \todo extract documents starting page number */
- pdfc->current_page = 0;
+ pdfc->current_page = 16;
pdfres = nspdf_get_page_dimensions(pdfc->doc,
pdfc->current_page,
@@ -172,7 +181,7 @@ pdf_path(const struct nspdf_style *style,
const struct redraw_context *ctx = ctxin;
ctx->plot->path(ctx,
- style,
+ (const struct plot_style_s *)style,
path,
path_length,
style->stroke_width,
@@ -191,7 +200,8 @@ pdf_redraw(struct content *c,
nspdferror pdfres;
struct nspdf_render_ctx render_ctx;
- printf("data x:%d y:%d w:%d h:%d\nclip %d %d %d %d\n",
+ NSLOG(netsurf, DEBUG,
+ "data x:%d y:%d w:%d h:%d\nclip %d %d %d %d\n",
data->x, data->y, data->width, data->height,
clip->x0, clip->y0, clip->x1, clip->y1);
@@ -206,7 +216,6 @@ pdf_redraw(struct content *c,
pdfres = nspdf_page_render(pdfc->doc, pdfc->current_page, &render_ctx);
-
return true;
}
@@ -224,32 +233,56 @@ static content_type pdf_content_type(void)
}
static void
+pdf_change_page(struct pdf_content *pdfc,
+ struct browser_window *bw,
+ unsigned int page_number)
+{
+ float page_width;
+ float page_height;
+ nspdferror pdfres;
+
+ /* ensure page stays in bounds */
+ if (page_number >= pdfc->page_count) {
+ return;
+ }
+
+ pdfc->current_page = page_number;
+
+ pdfres = nspdf_get_page_dimensions(pdfc->doc,
+ pdfc->current_page,
+ &page_width,
+ &page_height);
+ if (pdfres == NSPDFERROR_OK) {
+ pdfc->base.width = page_width;
+ pdfc->base.height = page_height;
+ NSLOG(netsurf, DEBUG,
+ "page %d w:%f h:%f\n",
+ pdfc->current_page,
+ page_width,
+ page_height);
+ }
+
+ browser_window_update(bw, false);
+}
+
+static void
pdf_mouse_action(struct content *c,
struct browser_window *bw,
browser_mouse_state mouse,
int x, int y)
{
struct pdf_content *pdfc = (struct pdf_content *)c;
- nspdferror pdfres;
- printf("ici\n");
+
if (mouse & BROWSER_MOUSE_CLICK_1) {
- float page_width;
- float page_height;
-
- pdfc->current_page++;
-
- pdfres = nspdf_get_page_dimensions(pdfc->doc,
- pdfc->current_page,
- &page_width,
- &page_height);
- if (pdfres == NSPDFERROR_OK) {
- pdfc->base.width = page_width;
- pdfc->base.height = page_height;
- printf("page $d w:%f h:%f\n",pdfc->current_page, page_width, page_height);
+ int bwwidth;
+ int bwheight;
+ browser_window_get_extents(bw, false, &bwwidth, &bwheight);
+
+ if (x < (bwwidth / 2)) {
+ pdf_change_page(pdfc, bw, pdfc->current_page - 1);
+ } else {
+ pdf_change_page(pdfc, bw, pdfc->current_page + 1);
}
-
- browser_window_update(bw, false);
-
}
}
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=689faa4fbb3d07dd427...
commit 689faa4fbb3d07dd4277f138b0c9b75c96577978
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
allow clicking to change page
diff --git a/content/content.c b/content/content.c
index a04051b..3cf38b7 100644
--- a/content/content.c
+++ b/content/content.c
@@ -544,7 +544,7 @@ void content__request_redraw(struct content *c,
}
-/* exported interface, documented in content/content.h */
+/* exported interface, documented in content/content_protected.h */
bool content_redraw(hlcache_handle *h, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx)
{
diff --git a/content/handlers/pdf/pdf.c b/content/handlers/pdf/pdf.c
index d62f1ff..d8c4d61 100644
--- a/content/handlers/pdf/pdf.c
+++ b/content/handlers/pdf/pdf.c
@@ -31,7 +31,10 @@
#include <nspdf/meta.h>
#include <nspdf/page.h>
+#include "utils/messages.h"
#include "utils/utils.h"
+#include "netsurf/plotters.h"
+#include "netsurf/content.h"
#include "content/llcache.h"
#include "content/content_protected.h"
@@ -41,6 +44,8 @@ typedef struct pdf_content {
struct content base;
struct nspdf_doc *doc;
+
+ unsigned int current_page;
} pdf_content;
static nserror nspdf2nserr(nspdferror nspdferr)
@@ -120,6 +125,8 @@ static bool pdf_convert(struct content *c)
const uint8_t *content_data;
unsigned long content_length;
struct lwc_string_s *title;
+ float page_width;
+ float page_height;
content_data = (const uint8_t *)content__get_source_data(c,
&content_length);
@@ -137,6 +144,18 @@ static bool pdf_convert(struct content *c)
content__set_title(c, lwc_string_data(title));
}
+ /** \todo extract documents starting page number */
+ pdfc->current_page = 0;
+
+ pdfres = nspdf_get_page_dimensions(pdfc->doc,
+ pdfc->current_page,
+ &page_width,
+ &page_height);
+ if (pdfres == NSPDFERROR_OK) {
+ pdfc->base.width = page_width;
+ pdfc->base.height = page_height;
+ }
+
content_set_ready(c);
content_set_done(c);
@@ -145,11 +164,19 @@ static bool pdf_convert(struct content *c)
static nspdferror
pdf_path(const struct nspdf_style *style,
- const float *p,
- unsigned int n,
+ const float *path,
+ unsigned int path_length,
const float transform[6],
- const void *ctx)
+ const void *ctxin)
{
+ const struct redraw_context *ctx = ctxin;
+
+ ctx->plot->path(ctx,
+ style,
+ path,
+ path_length,
+ style->stroke_width,
+ transform);
return NSPDFERROR_OK;
}
@@ -164,16 +191,20 @@ pdf_redraw(struct content *c,
nspdferror pdfres;
struct nspdf_render_ctx render_ctx;
+ printf("data x:%d y:%d w:%d h:%d\nclip %d %d %d %d\n",
+ data->x, data->y, data->width, data->height,
+ clip->x0, clip->y0, clip->x1, clip->y1);
+
render_ctx.ctx = ctx;
- render_ctx.device_space[0] = 1;
+ render_ctx.device_space[0] = 1; /* scale x */
render_ctx.device_space[1] = 0;
render_ctx.device_space[2] = 0;
- render_ctx.device_space[3] = 1;
+ render_ctx.device_space[3] = -1; /* scale y */
render_ctx.device_space[4] = 0; /* x offset */
- render_ctx.device_space[5] = -200; /* y offset */
+ render_ctx.device_space[5] = data->height; /* y offset */
render_ctx.path = pdf_path;
- pdfres = nspdf_page_render(pdfc->doc, 0, &render_ctx);
+ pdfres = nspdf_page_render(pdfc->doc, pdfc->current_page, &render_ctx);
return true;
@@ -192,12 +223,42 @@ static content_type pdf_content_type(void)
return CONTENT_PDF;
}
+static void
+pdf_mouse_action(struct content *c,
+ struct browser_window *bw,
+ browser_mouse_state mouse,
+ int x, int y)
+{
+ struct pdf_content *pdfc = (struct pdf_content *)c;
+ nspdferror pdfres;
+ printf("ici\n");
+ if (mouse & BROWSER_MOUSE_CLICK_1) {
+ float page_width;
+ float page_height;
+
+ pdfc->current_page++;
+
+ pdfres = nspdf_get_page_dimensions(pdfc->doc,
+ pdfc->current_page,
+ &page_width,
+ &page_height);
+ if (pdfres == NSPDFERROR_OK) {
+ pdfc->base.width = page_width;
+ pdfc->base.height = page_height;
+ printf("page $d w:%f h:%f\n",pdfc->current_page, page_width, page_height);
+ }
+
+ browser_window_update(bw, false);
+
+ }
+}
static const content_handler nspdf_content_handler = {
.create = pdf_create,
.data_complete = pdf_convert,
.destroy = pdf_destroy,
.redraw = pdf_redraw,
+ .mouse_action = pdf_mouse_action,
.clone = pdf_clone,
.type = pdf_content_type,
.no_share = false,
diff --git a/desktop/browser.c b/desktop/browser.c
index 1c8aa95..eec90bf 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -3293,6 +3293,7 @@ void browser_window_mouse_click(struct browser_window *bw,
switch (content_get_type(c)) {
case CONTENT_HTML:
+ case CONTENT_PDF:
case CONTENT_TEXTPLAIN:
{
/* Give bw focus */
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=7eea4ef0b049a751506...
commit 7eea4ef0b049a751506b7021264290cea07dc85c
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
call page render interface
diff --git a/content/handlers/pdf/pdf.c b/content/handlers/pdf/pdf.c
index 288aa58..d62f1ff 100644
--- a/content/handlers/pdf/pdf.c
+++ b/content/handlers/pdf/pdf.c
@@ -29,6 +29,7 @@
#include <nspdf/document.h>
#include <nspdf/meta.h>
+#include <nspdf/page.h>
#include "utils/utils.h"
#include "content/llcache.h"
@@ -142,6 +143,16 @@ static bool pdf_convert(struct content *c)
return true;
}
+static nspdferror
+pdf_path(const struct nspdf_style *style,
+ const float *p,
+ unsigned int n,
+ const float transform[6],
+ const void *ctx)
+{
+ return NSPDFERROR_OK;
+}
+
/* exported interface documented in image_cache.h */
static bool
pdf_redraw(struct content *c,
@@ -149,6 +160,22 @@ pdf_redraw(struct content *c,
const struct rect *clip,
const struct redraw_context *ctx)
{
+ struct pdf_content *pdfc = (struct pdf_content *)c;
+ nspdferror pdfres;
+ struct nspdf_render_ctx render_ctx;
+
+ render_ctx.ctx = ctx;
+ render_ctx.device_space[0] = 1;
+ render_ctx.device_space[1] = 0;
+ render_ctx.device_space[2] = 0;
+ render_ctx.device_space[3] = 1;
+ render_ctx.device_space[4] = 0; /* x offset */
+ render_ctx.device_space[5] = -200; /* y offset */
+ render_ctx.path = pdf_path;
+
+ pdfres = nspdf_page_render(pdfc->doc, 0, &render_ctx);
+
+
return true;
}
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=57a45534c988e0bc83a...
commit 57a45534c988e0bc83affee2a890d8ee60692e8f
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
set the pdf title if available
diff --git a/content/handlers/pdf/pdf.c b/content/handlers/pdf/pdf.c
index 657a5e9..288aa58 100644
--- a/content/handlers/pdf/pdf.c
+++ b/content/handlers/pdf/pdf.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <nspdf/document.h>
+#include <nspdf/meta.h>
#include "utils/utils.h"
#include "content/llcache.h"
@@ -117,6 +118,7 @@ static bool pdf_convert(struct content *c)
nspdferror pdfres;
const uint8_t *content_data;
unsigned long content_length;
+ struct lwc_string_s *title;
content_data = (const uint8_t *)content__get_source_data(c,
&content_length);
@@ -129,8 +131,14 @@ static bool pdf_convert(struct content *c)
return false;
}
+ pdfres = nspdf_get_title(pdfc->doc, &title);
+ if (pdfres == NSPDFERROR_OK) {
+ content__set_title(c, lwc_string_data(title));
+ }
+
content_set_ready(c);
content_set_done(c);
+
return true;
}
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=1b4614b66a8adfecba2...
commit 1b4614b66a8adfecba244c4fa4dfa9b2ecbfac47
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
use nspdf library to parse document
diff --git a/content/handlers/pdf/pdf.c b/content/handlers/pdf/pdf.c
index 23457a2..657a5e9 100644
--- a/content/handlers/pdf/pdf.c
+++ b/content/handlers/pdf/pdf.c
@@ -27,12 +27,39 @@
#include <stdbool.h>
#include <stdlib.h>
+#include <nspdf/document.h>
+
#include "utils/utils.h"
#include "content/llcache.h"
#include "content/content_protected.h"
#include "pdf.h"
+typedef struct pdf_content {
+ struct content base;
+
+ struct nspdf_doc *doc;
+} pdf_content;
+
+static nserror nspdf2nserr(nspdferror nspdferr)
+{
+ nserror res;
+ switch (nspdferr) {
+ case NSPDFERROR_OK:
+ res = NSERROR_OK;
+ break;
+
+ case NSPDFERROR_NOMEM:
+ res = NSERROR_NOMEM;
+ break;
+
+ default:
+ res = NSERROR_UNKNOWN;
+ break;
+ }
+ return res;
+}
+
/**
* Content create entry point.
*/
@@ -45,32 +72,63 @@ pdf_create(const content_handler *handler,
bool quirks,
struct content **c)
{
- struct content *jpeg;
- nserror error;
+ struct pdf_content *pdfc;
+ nserror res;
+ nspdferror pdfres;
- jpeg = calloc(1, sizeof(struct content));
- if (jpeg == NULL)
+ pdfc = calloc(1, sizeof(struct pdf_content));
+ if (pdfc == NULL) {
return NSERROR_NOMEM;
+ }
+
+ res = content__init(&pdfc->base,
+ handler,
+ imime_type,
+ params,
+ llcache,
+ fallback_charset,
+ quirks);
+ if (res != NSERROR_OK) {
+ free(pdfc);
+ return res;
+ }
- error = content__init(jpeg, handler, imime_type, params,
- llcache, fallback_charset, quirks);
- if (error != NSERROR_OK) {
- free(jpeg);
- return error;
+ pdfres = nspdf_document_create(&pdfc->doc);
+ if (pdfres != NSPDFERROR_OK) {
+ free(pdfc);
+ return nspdf2nserr(res);
}
- *c = jpeg;
+ *c = (struct content *)pdfc;
return NSERROR_OK;
}
/* exported interface documented in image_cache.h */
-static void pdf_destroy(struct content *content)
+static void pdf_destroy(struct content *c)
{
+ struct pdf_content *pdfc = (struct pdf_content *)c;
+ nspdf_document_destroy(pdfc->doc);
}
static bool pdf_convert(struct content *c)
{
+ struct pdf_content *pdfc = (struct pdf_content *)c;
+ nspdferror pdfres;
+ const uint8_t *content_data;
+ unsigned long content_length;
+
+ content_data = (const uint8_t *)content__get_source_data(c,
+ &content_length);
+
+ pdfres = nspdf_document_parse(pdfc->doc,
+ content_data,
+ content_length);
+ if (pdfres != NSPDFERROR_OK) {
+ content_broadcast_errorcode(c, NSERROR_INVALID);
+ return false;
+ }
+
content_set_ready(c);
content_set_done(c);
return true;
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=e6a2ff5bba7adc092a7...
commit e6a2ff5bba7adc092a7af8f9604d0a440e535624
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
Add initial content handler for PDF format
diff --git a/Makefile b/Makefile
index 3e63fb2..2cad7d4 100644
--- a/Makefile
+++ b/Makefile
@@ -513,7 +513,6 @@ include Makefile.defaults
# libraries enabled by feature switch without pkgconfig file
$(eval $(call feature_switch,JPEG,JPEG (libjpeg),-DWITH_JPEG,-ljpeg,-UWITH_JPEG,))
-$(eval $(call feature_switch,HARU_PDF,PDF export (haru),-DWITH_PDF_EXPORT,-lhpdf -lpng,-UWITH_PDF_EXPORT,))
$(eval $(call feature_switch,LIBICONV_PLUG,glibc internal iconv,-DLIBICONV_PLUG,,-ULIBICONV_PLUG,-liconv))
$(eval $(call feature_switch,DUKTAPE,Javascript (Duktape),,,,,))
@@ -538,6 +537,7 @@ NETSURF_FEATURE_OPENSSL_CFLAGS := -DWITH_OPENSSL
NETSURF_FEATURE_ROSPRITE_CFLAGS := -DWITH_NSSPRITE
NETSURF_FEATURE_NSPSL_CFLAGS := -DWITH_NSPSL
NETSURF_FEATURE_NSLOG_CFLAGS := -DWITH_NSLOG
+NETSURF_FEATURE_NSPDF_CFLAGS := -DWITH_NSPDF
# libcurl and openssl ordering matters as if libcurl requires ssl it
# needs to come first in link order to ensure its symbols can be
@@ -559,6 +559,7 @@ $(eval $(call pkg_config_find_and_add_enabled,NSSVG,libsvgtiny,SVG))
$(eval $(call pkg_config_find_and_add_enabled,ROSPRITE,librosprite,Sprite))
$(eval $(call pkg_config_find_and_add_enabled,NSPSL,libnspsl,PSL))
$(eval $(call pkg_config_find_and_add_enabled,NSLOG,libnslog,LOG))
+$(eval $(call pkg_config_find_and_add_enabled,NSPDF,libnspdf,PDF))
# List of directories in which headers are searched for
INCLUDE_DIRS :=. include $(OBJROOT)
diff --git a/Makefile.defaults b/Makefile.defaults
index 5109010..85fb9b8 100644
--- a/Makefile.defaults
+++ b/Makefile.defaults
@@ -63,11 +63,9 @@ NETSURF_USE_VIDEO := NO
# Valid options: YES, NO
NETSURF_USE_DUKTAPE := YES
-# 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 the use of netsurf integrated pdf viewing
+# Valid options: YES, NO, AUTO
+NETSURF_USE_NSPDF := AUTO
# Enable the use of the Public suffix library to detect supercookies
# Valid options: YES, NO, AUTO (highly recommended)
diff --git a/content/content_protected.h b/content/content_protected.h
index 21b73a6..941b5a7 100644
--- a/content/content_protected.h
+++ b/content/content_protected.h
@@ -17,8 +17,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Content handling (interface).
+/**
+ * \file
+ * Content handling interface.
*
* The content functions manipulate struct contents, which correspond to URLs.
*/
@@ -36,17 +37,34 @@ struct content_redraw_data;
struct http_parameter;
struct content_handler {
+ /**
+ * content handler finalisation
+ */
void (*fini)(void);
+ /**
+ * create a content
+ */
nserror (*create)(const struct content_handler *handler,
lwc_string *imime_type,
const struct http_parameter *params,
struct llcache_handle *llcache,
- const char *fallback_charset, bool quirks,
+ const char *fallback_charset,
+ bool quirks,
struct content **c);
+ /**
+ * ongoing fetch has received data
+ */
bool (*process_data)(struct content *c,
- const char *data, unsigned int size);
+ const char *data,
+ unsigned int size);
+
+ /**
+ * fetcher has completed retrieving all the data
+ *
+ * \param c The completed content.
+ */
bool (*data_complete)(struct content *c);
void (*reformat)(struct content *c, int width, int height);
void (*destroy)(struct content *c);
@@ -82,10 +100,14 @@ struct content_handler {
void (*add_user)(struct content *c);
void (*remove_user)(struct content *c);
- /** handler dependant content sensitive internal data interface. */
+ /**
+ * 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. */
+ /**
+ * There must be one content per user for this type.
+ */
bool no_share;
};
diff --git a/content/handlers/Makefile b/content/handlers/Makefile
index ea9d0c8..b88f3ca 100644
--- a/content/handlers/Makefile
+++ b/content/handlers/Makefile
@@ -23,5 +23,10 @@ include content/handlers/text/Makefile
S_CONTENT += $(addprefix handlers/text/,$(S_TEXT))
+# PDF content handler source
+include content/handlers/pdf/Makefile
+
+S_CONTENT += $(addprefix handlers/pdf/,$(S_PDF))
+
# extend the include search path
INCLUDE_DIRS += content/handlers
diff --git a/content/handlers/image/jpeg.c b/content/handlers/image/jpeg.c
index 123a0bf..6eec61c 100644
--- a/content/handlers/image/jpeg.c
+++ b/content/handlers/image/jpeg.c
@@ -17,8 +17,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Content for image/jpeg (implementation).
+/**
+ * \file
+ * implementation of content handling for JPEG images.
*
* This implementation uses the IJG JPEG library.
*/
diff --git a/content/handlers/pdf/Makefile b/content/handlers/pdf/Makefile
new file mode 100644
index 0000000..32d6e27
--- /dev/null
+++ b/content/handlers/pdf/Makefile
@@ -0,0 +1,11 @@
+#
+# NetSurf pdf source file inclusion
+#
+# Included by content handlers Makefile
+#
+
+ifeq ($(NETSURF_USE_NSPDF),YES)
+S_PDF := pdf.c
+else
+S_PDF :=
+endif
diff --git a/content/handlers/pdf/pdf.c b/content/handlers/pdf/pdf.c
new file mode 100644
index 0000000..23457a2
--- /dev/null
+++ b/content/handlers/pdf/pdf.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2004 James Bursa <bursa(a)users.sourceforge.net>
+ * Copyright 2004 John M Bell <jmb202(a)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
+ * implementation of content handling for PDF.
+ *
+ * This implementation uses the netsurf pdf library.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "utils/utils.h"
+#include "content/llcache.h"
+#include "content/content_protected.h"
+
+#include "pdf.h"
+
+/**
+ * Content create entry point.
+ */
+static nserror
+pdf_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)
+{
+ 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;
+}
+
+/* exported interface documented in image_cache.h */
+static void pdf_destroy(struct content *content)
+{
+}
+
+static bool pdf_convert(struct content *c)
+{
+ content_set_ready(c);
+ content_set_done(c);
+ return true;
+}
+
+/* exported interface documented in image_cache.h */
+static bool
+pdf_redraw(struct content *c,
+ struct content_redraw_data *data,
+ const struct rect *clip,
+ const struct redraw_context *ctx)
+{
+ return true;
+}
+
+/**
+ * Clone content.
+ */
+static nserror pdf_clone(const struct content *old, struct content **newc)
+{
+ return NSERROR_NOMEM;
+}
+
+static content_type pdf_content_type(void)
+{
+ return CONTENT_PDF;
+}
+
+
+static const content_handler nspdf_content_handler = {
+ .create = pdf_create,
+ .data_complete = pdf_convert,
+ .destroy = pdf_destroy,
+ .redraw = pdf_redraw,
+ .clone = pdf_clone,
+ .type = pdf_content_type,
+ .no_share = false,
+};
+
+static const char *nspdf_types[] = {
+ "application/pdf",
+ "application/x-pdf",
+ "application/acrobat",
+ "applications/vnd.pdf",
+ "text/pdf",
+ "text/x-pdf"
+};
+
+CONTENT_FACTORY_REGISTER_TYPES(nspdf, nspdf_types, nspdf_content_handler);
diff --git a/content/handlers/pdf/pdf.h b/content/handlers/pdf/pdf.h
new file mode 100644
index 0000000..2171b80
--- /dev/null
+++ b/content/handlers/pdf/pdf.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018 Vincent Sanders <vince(a)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 for PDF content handler.
+ */
+
+#ifndef NETSURF_PDF_PDF_H_
+#define NETSURF_PDF_PDF_H_
+
+nserror nspdf_init(void);
+
+#endif
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index 8785a98..770fcbd 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -44,6 +44,7 @@
#include "javascript/js.h"
#include "html/html.h"
#include "text/textplain.h"
+#include "pdf/pdf.h"
#include "netsurf/browser_window.h"
#include "desktop/system_colour.h"
@@ -411,6 +412,12 @@ nserror netsurf_init(const char *store_path)
if (ret != NSERROR_OK)
return ret;
+#ifdef WITH_NSPDF
+ ret = nspdf_init();
+ if (ret != NSERROR_OK)
+ return ret;
+#endif
+
setlocale(LC_ALL, "");
/* initialise the fetchers */
diff --git a/include/netsurf/content_type.h b/include/netsurf/content_type.h
index ef654cd..155db1f 100644
--- a/include/netsurf/content_type.h
+++ b/include/netsurf/content_type.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2003 James Bursa <bursa(a)users.sourceforge.net>
+ * Copyright 2012 Vincent Sanders <vince(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -68,8 +68,11 @@ typedef enum {
/** All script types. */
CONTENT_SCRIPT = 0x40,
+ /** Portable Document Format. */
+ CONTENT_PDF = 0x80,
+
/** Any content matches */
- CONTENT_ANY = 0x7f
+ CONTENT_ANY = 0xff
} content_type;
-----------------------------------------------------------------------
Summary of changes:
!NetSurf/ChkSprites,ffb | Bin 1531 -> 0 bytes
.gitignore | 28 +-
Makefile | 45 +-
Makefile.config.example | 6 +
Makefile.defaults | 5 +
content/content.c | 18 +-
content/fetchers/curl.c | 32 +-
content/fs_backing_store.c | 9 +-
content/handlers/Makefile | 13 +-
content/handlers/css/dump.c | 39 +
content/handlers/css/select.c | 52 +-
content/handlers/css/select.h | 1 +
content/handlers/css/utils.c | 144 +-
content/handlers/css/utils.h | 46 +-
content/handlers/html/Makefile | 7 +
{render => content/handlers/html}/box.c | 64 +-
{render => content/handlers/html}/box.h | 31 +-
{render => content/handlers/html}/box_construct.c | 51 +-
{render => content/handlers/html}/box_normalise.c | 142 +-
{render => content/handlers/html}/box_textarea.c | 23 +-
{render => content/handlers/html}/box_textarea.h | 19 +-
{render => content/handlers/html}/font.c | 25 +-
{render => content/handlers/html}/font.h | 16 +-
{render => content/handlers/html}/form.c | 191 +-
{render => content/handlers/html}/form_internal.h | 8 +-
{render => content/handlers/html}/html.c | 124 +-
{render => content/handlers/html}/html.h | 96 +-
{render => content/handlers/html}/html_css.c | 14 +-
.../handlers/html}/html_css_fetcher.c | 42 +-
{render => content/handlers/html}/html_forms.c | 12 +-
.../handlers/html}/html_interaction.c | 140 +-
{render => content/handlers/html}/html_internal.h | 67 +-
{render => content/handlers/html}/html_object.c | 86 +-
{render => content/handlers/html}/html_redraw.c | 91 +-
.../handlers/html}/html_redraw_border.c | 6 +-
content/handlers/{pdf/pdf.h => html/html_save.h} | 25 +-
{render => content/handlers/html}/html_script.c | 14 +-
{render => content/handlers/html}/imagemap.c | 29 +-
{render => content/handlers/html}/imagemap.h | 9 +-
{render => content/handlers/html}/layout.c | 5227 +++++++++--------
{render => content/handlers/html}/layout.h | 37 +-
{render => content/handlers/html}/search.c | 27 +-
{render => content/handlers/html}/search.h | 9 +-
{render => content/handlers/html}/table.c | 391 +-
{render => content/handlers/html}/table.h | 17 +-
content/handlers/image/jpeg.c | 55 +-
content/handlers/image/rsvg.c | 14 +-
content/handlers/image/svg.c | 13 +-
content/handlers/javascript/duktape/Document.bnd | 2 +-
content/handlers/javascript/duktape/Makefile | 2 +-
content/handlers/javascript/duktape/Window.bnd | 6 +-
content/handlers/javascript/duktape/duk_config.h | 75 +-
content/handlers/javascript/duktape/duktape.c | 6053 +++++++++++++-------
content/handlers/javascript/duktape/duktape.h | 108 +-
content/handlers/pdf/pdf.c | 21 +-
content/handlers/text/Makefile | 3 +
{render => content/handlers/text}/textplain.c | 283 +-
{render => content/handlers/text}/textplain.h | 6 +-
content/llcache.c | 511 +-
content/urldb.c | 188 +-
content/urldb.h | 39 +
desktop/browser.c | 54 +-
desktop/browser_history.c | 4 +-
desktop/font_haru.c | 2 +-
desktop/frames.c | 4 +-
desktop/gui_factory.c | 10 +-
desktop/knockout.c | 4 +-
desktop/local_history.c | 10 +-
desktop/netsurf.c | 203 +-
desktop/plot_style.c | 14 +-
desktop/print.c | 39 +-
desktop/save_complete.c | 5 +-
desktop/save_pdf.c | 16 +-
desktop/save_text.c | 4 +-
desktop/scrollbar.c | 6 +-
desktop/selection.c | 75 +-
desktop/selection.h | 7 +-
desktop/textarea.c | 54 +-
desktop/textarea.h | 8 +-
desktop/textinput.c | 6 +-
desktop/treeview.c | 119 +-
desktop/version.c | 6 +-
docs/Doxyfile | 3 +-
docs/PACKAGING-GTK | 3 +-
docs/env.sh | 9 +-
docs/logging.md | 10 +-
docs/quick-start.md | 47 +-
frontends/amiga/Makefile | 15 +-
frontends/amiga/arexx.c | 4 +-
frontends/amiga/ctxmenu.c | 10 +-
frontends/amiga/dt_sound.c | 4 +-
frontends/amiga/font_bullet.c | 4 +-
frontends/amiga/font_diskfont.c | 2 +-
frontends/amiga/gui.c | 6 +-
frontends/amiga/gui_menu.c | 4 +-
frontends/amiga/gui_options.c | 2 +-
frontends/amiga/login.c | 123 +-
frontends/amiga/login.h | 8 +-
frontends/amiga/pkg/makereslinks | 24 +-
frontends/amiga/pkg/netsurf.readme | 4 +-
frontends/amiga/pkg/netsurf_os3.readme | 4 +-
frontends/amiga/plotters.c | 10 +-
frontends/amiga/plugin_hack.c | 2 +-
frontends/amiga/resources/AdBlock.css | 2 +-
frontends/amiga/resources/ca-bundle | 2 +-
frontends/amiga/resources/de | 1 -
frontends/amiga/resources/en | 1 -
frontends/amiga/resources/fr | 1 -
frontends/amiga/resources/it | 1 -
frontends/amiga/resources/nl | 1 -
frontends/amiga/resources/nsdefault.css | 2 +-
frontends/amiga/resources/quirks.css | 2 +-
frontends/amiga/theme.c | 4 +-
frontends/atari/Makefile | 33 +-
frontends/atari/ctxmenu.c | 6 +-
frontends/atari/deskmenu.c | 2 +-
frontends/atari/gui.c | 41 +-
frontends/atari/login.c | 19 +-
frontends/atari/login.h | 2 +-
frontends/atari/plot/font_freetype.c | 2 +-
frontends/atari/plot/font_vdi.c | 14 +-
frontends/atari/plot/plot.c | 8 +-
frontends/atari/toolbar.c | 4 +-
frontends/beos/Makefile | 64 +-
frontends/beos/filetype.cpp | 1 +
frontends/beos/font.cpp | 2 +-
frontends/beos/gui.cpp | 32 +-
frontends/beos/gui.h | 7 +-
frontends/beos/login.cpp | 31 +-
frontends/beos/plotters.cpp | 8 +-
frontends/beos/res/adblock.css | 2 +-
frontends/beos/res/ca-bundle.txt | 2 +-
frontends/beos/res/de/welcome.html | 2 +-
frontends/beos/res/default.css | 2 +-
frontends/beos/res/en/credits.html | 2 +-
frontends/beos/res/en/licence.html | 2 +-
frontends/beos/res/en/maps.html | 2 +-
frontends/beos/res/en/welcome.html | 2 +-
frontends/beos/res/icons | 2 +-
frontends/beos/res/internal.css | 2 +-
frontends/beos/res/it/credits.html | 2 +-
frontends/beos/res/it/licence.html | 2 +-
frontends/beos/res/it/welcome.html | 2 +-
frontends/beos/res/ja/welcome.html | 2 +-
frontends/beos/res/netsurf.png | 2 +-
frontends/beos/res/quirks.css | 2 +-
frontends/beos/window.cpp | 15 +-
frontends/framebuffer/Makefile | 9 +-
frontends/framebuffer/fbtk/text.c | 2 +-
frontends/framebuffer/font_freetype.c | 2 +-
frontends/framebuffer/font_internal.c | 6 +-
frontends/framebuffer/framebuffer.c | 8 +-
frontends/framebuffer/gui.c | 4 +-
frontends/framebuffer/res/Messages | 1 -
frontends/framebuffer/res/adblock.css | 2 +-
frontends/framebuffer/res/credits.html | 2 +-
frontends/framebuffer/res/default.css | 2 +-
frontends/framebuffer/res/internal.css | 2 +-
frontends/framebuffer/res/licence.html | 2 +-
frontends/framebuffer/res/maps.html | 2 +-
frontends/framebuffer/res/netsurf.png | 2 +-
frontends/framebuffer/res/quirks.css | 2 +-
frontends/framebuffer/res/welcome.html | 2 +-
frontends/gtk/Makefile | 2 +-
frontends/gtk/accelerator.c | 79 +
frontends/gtk/accelerator.h | 2 +
frontends/gtk/compat.c | 39 +-
frontends/gtk/compat.h | 25 +
frontends/gtk/completion.c | 5 +-
frontends/gtk/corewindow.c | 2 +-
frontends/gtk/fetch.c | 3 +-
frontends/gtk/gui.c | 74 +-
frontends/gtk/layout_pango.c | 2 +-
frontends/gtk/login.c | 141 +-
frontends/gtk/login.h | 7 +-
frontends/gtk/menu.c | 44 +-
frontends/gtk/plotters.c | 33 +-
frontends/gtk/preferences.c | 2 +-
frontends/gtk/print.c | 32 +-
frontends/gtk/res/accelerators | 40 +
frontends/gtk/res/adblock.css | 2 +-
frontends/gtk/res/ca-bundle.txt | 2 +-
frontends/gtk/res/de/welcome.html | 2 +-
frontends/gtk/res/default.css | 2 +-
frontends/gtk/res/en/credits.html | 2 +-
frontends/gtk/res/en/licence.html | 2 +-
frontends/gtk/res/en/maps.html | 2 +-
frontends/gtk/res/en/welcome.html | 2 +-
frontends/gtk/res/icons | 2 +-
frontends/gtk/res/internal.css | 2 +-
frontends/gtk/res/it/credits.html | 2 +-
frontends/gtk/res/it/licence.html | 2 +-
frontends/gtk/res/it/welcome.html | 2 +-
frontends/gtk/res/ja/welcome.html | 2 +-
frontends/gtk/res/login.gtk2.ui | 291 +-
frontends/gtk/res/login.gtk3.ui | 300 +-
frontends/gtk/res/netsurf.gresource.xml | 1 +
frontends/gtk/res/netsurf.png | 2 +-
frontends/gtk/res/nl/credits.html | 2 +-
frontends/gtk/res/nl/licence.html | 2 +-
frontends/gtk/res/nl/welcome.html | 2 +-
frontends/gtk/res/quirks.css | 2 +-
frontends/gtk/resources.c | 30 +-
frontends/gtk/scaffolding.c | 14 +-
frontends/gtk/tabs.c | 2 +-
frontends/gtk/viewsource.c | 6 +-
frontends/gtk/window.c | 5 +-
frontends/monkey/401login.c | 15 +-
frontends/monkey/401login.h | 8 +-
frontends/monkey/filetype.c | 1 +
frontends/monkey/layout.c | 10 +-
frontends/monkey/plot.c | 6 +-
frontends/riscos/401login.c | 94 +-
frontends/riscos/Makefile | 26 +-
{!NetSurf => frontends/riscos/appdir}/!Boot,feb | 0
{!NetSurf => frontends/riscos/appdir}/!Sprites,ff9 | Bin 1580 -> 1580 bytes
.../riscos/appdir}/!Sprites22,ff9 | Bin 11528 -> 11528 bytes
{!NetSurf => frontends/riscos/appdir}/5Sprites,ff9 | Bin 30964 -> 30964 bytes
.../riscos/appdir}/5Sprites11,ff9 | Bin 64228 -> 64228 bytes
.../riscos/appdir}/5Sprites22,ff9 | Bin 40800 -> 40800 bytes
{!NetSurf => frontends/riscos/appdir}/ASprites,ff9 | Bin 3664 -> 3664 bytes
.../riscos/appdir}/ASprites11,ff9 | Bin 15892 -> 15892 bytes
.../riscos/appdir}/ASprites22,ff9 | Bin 12668 -> 12668 bytes
frontends/riscos/appdir/ChkSprites,ffb | Bin 0 -> 2029 bytes
.../riscos/appdir}/Docs/online,b60 | Bin 165 -> 165 bytes
{!NetSurf => frontends/riscos/appdir}/FixFonts,ffb | 0
{!NetSurf => frontends/riscos/appdir}/KickNS,ffb | Bin 1511 -> 1511 bytes
.../riscos/appdir}/OpenChoices,feb | 0
{!NetSurf => frontends/riscos/appdir}/OpenHelp,ffb | Bin 925 -> 925 bytes
.../riscos/appdir}/OpenScrap,feb | 0
frontends/riscos/appdir/Resources/AdBlock,f79 | 1 +
.../riscos/appdir}/Resources/Aletheia,ffd | Bin 15237 -> 15237 bytes
frontends/riscos/appdir/Resources/CSS,f79 | 1 +
.../appdir}/Resources/Fonts/NSSymbol/Encoding | 0
.../Resources/Fonts/NSSymbol/IntMetrics,ff6 | Bin 344 -> 344 bytes
.../appdir}/Resources/Fonts/NSSymbol/Outlines,ff6 | Bin 904 -> 904 bytes
frontends/riscos/appdir/Resources/Icons | 1 +
.../riscos/appdir}/Resources/Image,ff9 | Bin 111972 -> 111972 bytes
.../riscos/appdir}/Resources/LangNames | 0
frontends/riscos/appdir/Resources/Quirks,f79 | 1 +
.../riscos/appdir}/Resources/SearchEngines | 0
.../riscos/appdir}/Resources/Sprites,ff9 | Bin 77336 -> 77336 bytes
frontends/riscos/appdir/Resources/ca-bundle | 1 +
frontends/riscos/appdir/Resources/de/Messages | 1 +
.../riscos/appdir/Resources/de/welcome.html,faf | 1 +
.../riscos/appdir}/Resources/en/!Help | 0
frontends/riscos/appdir/Resources/en/Messages | 1 +
.../riscos/appdir/Resources/en/credits.html,faf | 1 +
.../riscos/appdir/Resources/en/licence.html,faf | 1 +
frontends/riscos/appdir/Resources/en/maps.html,faf | 1 +
.../riscos/appdir/Resources/en/welcome.html,faf | 1 +
frontends/riscos/appdir/Resources/fr/Messages | 1 +
frontends/riscos/appdir/Resources/internal.css,f79 | 1 +
frontends/riscos/appdir/Resources/it/Messages | 1 +
.../riscos/appdir/Resources/it/credits.html,faf | 1 +
.../riscos/appdir/Resources/it/licence.html,faf | 1 +
.../riscos/appdir/Resources/it/welcome.html,faf | 1 +
.../riscos/appdir/Resources/ja/welcome.html,faf | 1 +
frontends/riscos/appdir/Resources/netsurf.png,b60 | 1 +
.../riscos/appdir}/Resources/nl/!Help | 0
frontends/riscos/appdir/Resources/nl/Messages | 1 +
.../riscos/appdir/Resources/nl/credits.html,faf | 1 +
.../riscos/appdir/Resources/nl/licence.html,faf | 1 +
.../riscos/appdir/Resources/nl/welcome.html,faf | 1 +
frontends/riscos/font.c | 2 +-
frontends/riscos/gui.c | 13 +-
frontends/riscos/gui.h | 8 +-
frontends/riscos/plotters.c | 20 +-
frontends/riscos/print.c | 1 -
frontends/riscos/save_draw.c | 9 +-
frontends/riscos/window.c | 26 +-
frontends/windows/Makefile | 11 +-
frontends/windows/about.c | 4 +-
frontends/windows/about.h | 6 +-
frontends/windows/download.c | 2 +-
frontends/windows/{filetype.c => fetch.c} | 69 +-
frontends/windows/{filetype.h => fetch.h} | 16 +
frontends/windows/font.c | 2 +-
frontends/windows/gui.c | 72 +-
frontends/windows/gui.h | 14 +
frontends/windows/login.c | 297 +
.../pdf/pdf.h => frontends/windows/login.h | 18 +-
frontends/windows/main.c | 62 +-
frontends/windows/plot.c | 10 +-
frontends/windows/pointers.c | 1 -
frontends/windows/prefs.c | 6 +-
frontends/windows/res/adblock.css | 2 +-
frontends/windows/res/ca-bundle.crt | 2 +-
frontends/windows/res/credits.html | 2 +-
frontends/windows/res/default.css | 2 +-
frontends/windows/res/icons/arrow-l.png | 1 +
frontends/windows/res/icons/content.png | 1 +
frontends/windows/res/icons/directory.png | 1 +
frontends/windows/res/icons/directory2.png | 1 +
frontends/windows/res/icons/hotlist-add.png | 1 +
frontends/windows/res/icons/hotlist-rmv.png | 1 +
frontends/windows/res/icons/search.png | 1 +
frontends/windows/res/installer.nsi | 2 +-
frontends/windows/res/internal.css | 2 +-
frontends/windows/res/licence.html | 2 +-
frontends/windows/res/netsurf.png | 2 +-
frontends/windows/res/quirks.css | 2 +-
frontends/windows/res/resource.rc | 561 +-
frontends/windows/res/welcome.html | 2 +-
frontends/windows/resourceid.h | 33 +-
frontends/windows/window.c | 8 +-
include/netsurf/browser_window.h | 17 +-
include/netsurf/misc.h | 33 +-
include/netsurf/plot_style.h | 37 +-
include/netsurf/plotters.h | 72 +-
include/netsurf/url_db.h | 21 -
render/Makefile | 10 -
resources/FatMessages | 179 +-
.../Resources/AdBlock,f79 => resources/adblock.css | 0
{!NetSurf/Resources => resources}/ca-bundle | 1831 ++----
.../welcome.html,faf => resources/de/welcome.html | 10 +-
.../Resources/CSS,f79 => resources/default.css | 0
.../credits.html,faf => resources/en/credits.html | 16 +-
.../licence.html,faf => resources/en/licence.html | 10 +-
.../en/maps.html,faf => resources/en/maps.html | 0
.../welcome.html,faf => resources/en/welcome.html | 10 +-
.../Icons => resources/icons}/arrow-l.png | Bin 284 -> 284 bytes
.../Icons => resources/icons}/content.png | Bin 598 -> 598 bytes
.../Icons => resources/icons}/directory.png | Bin 259 -> 259 bytes
.../Icons => resources/icons}/directory2.png | Bin 336 -> 336 bytes
.../Icons => resources/icons}/hotlist-add.png | Bin 356 -> 356 bytes
.../Icons => resources/icons}/hotlist-rmv.png | Bin 610 -> 610 bytes
.../Resources/Icons => resources/icons}/search.png | Bin 536 -> 536 bytes
.../internal.css,f79 => resources/internal.css | 0
.../credits.html,faf => resources/it/credits.html | 2 +-
.../licence.html,faf => resources/it/licence.html | 6 +-
.../welcome.html,faf => resources/it/welcome.html | 10 +-
.../welcome.html,faf => resources/ja/welcome.html | 10 +-
.../netsurf.png,b60 => resources/netsurf.png | Bin 16486 -> 16486 bytes
.../credits.html,faf => resources/nl/credits.html | 2 +-
.../licence.html,faf => resources/nl/licence.html | 12 +-
.../welcome.html,faf => resources/nl/welcome.html | 10 +-
.../Resources/Quirks,f79 => resources/quirks.css | 0
test/Makefile | 7 +-
test/data/urldb-out | 8 +-
test/hashtable.c | 2 +
utils/corestringlist.h | 3 +
utils/filename.c | 21 +-
utils/filepath.c | 8 +-
utils/filepath.h | 14 +-
utils/hashtable.c | 227 +-
utils/hashtable.h | 53 +-
utils/http.h | 1 +
utils/http/Makefile | 5 +-
utils/http/challenge.c | 2 +-
utils/http/content-disposition.c | 2 +-
utils/http/content-type.c | 2 +-
utils/http/generics.h | 2 +
utils/http/strict-transport-security.c | 341 ++
utils/http/strict-transport-security.h | 64 +
utils/idna.c | 1 +
utils/jenkins-build.sh | 19 +-
utils/merge-messages.lua | 83 -
utils/messages.c | 166 +-
utils/nsurl.h | 37 +
utils/nsurl/nsurl.c | 104 +-
utils/nsurl/parse.c | 64 +-
utils/nsurl/private.h | 47 +-
utils/split-messages.pl | 17 +-
364 files changed, 13457 insertions(+), 9037 deletions(-)
delete mode 100644 !NetSurf/ChkSprites,ffb
create mode 100644 content/handlers/html/Makefile
rename {render => content/handlers/html}/box.c (95%)
rename {render => content/handlers/html}/box.h (95%)
rename {render => content/handlers/html}/box_construct.c (98%)
rename {render => content/handlers/html}/box_normalise.c (89%)
rename {render => content/handlers/html}/box_textarea.c (96%)
rename {render => content/handlers/html}/box_textarea.h (81%)
rename {render => content/handlers/html}/font.c (84%)
rename {render => content/handlers/html}/font.h (77%)
rename {render => content/handlers/html}/form.c (97%)
rename {render => content/handlers/html}/form_internal.h (98%)
rename {render => content/handlers/html}/html.c (95%)
rename {render => content/handlers/html}/html.h (81%)
rename {render => content/handlers/html}/html_css.c (98%)
rename {render => content/handlers/html}/html_css_fetcher.c (93%)
rename {render => content/handlers/html}/html_forms.c (99%)
rename {render => content/handlers/html}/html_interaction.c (97%)
rename {render => content/handlers/html}/html_internal.h (92%)
rename {render => content/handlers/html}/html_object.c (90%)
rename {render => content/handlers/html}/html_redraw.c (96%)
rename {render => content/handlers/html}/html_redraw_border.c (99%)
copy content/handlers/{pdf/pdf.h => html/html_save.h} (55%)
rename {render => content/handlers/html}/html_script.c (97%)
rename {render => content/handlers/html}/imagemap.c (97%)
rename {render => content/handlers/html}/imagemap.h (90%)
rename {render => content/handlers/html}/layout.c (88%)
rename {render => content/handlers/html}/layout.h (52%)
rename {render => content/handlers/html}/search.c (97%)
rename {render => content/handlers/html}/search.h (95%)
rename {render => content/handlers/html}/table.c (71%)
rename {render => content/handlers/html}/table.h (73%)
create mode 100644 content/handlers/text/Makefile
rename {render => content/handlers/text}/textplain.c (82%)
rename {render => content/handlers/text}/textplain.h (98%)
delete mode 120000 frontends/amiga/resources/de
delete mode 120000 frontends/amiga/resources/en
delete mode 120000 frontends/amiga/resources/fr
delete mode 120000 frontends/amiga/resources/it
delete mode 120000 frontends/amiga/resources/nl
delete mode 120000 frontends/framebuffer/res/Messages
create mode 100644 frontends/gtk/accelerator.c
create mode 100644 frontends/gtk/accelerator.h
create mode 100644 frontends/gtk/res/accelerators
rename {!NetSurf => frontends/riscos/appdir}/!Boot,feb (100%)
rename {!NetSurf => frontends/riscos/appdir}/!Sprites,ff9 (100%)
rename {!NetSurf => frontends/riscos/appdir}/!Sprites22,ff9 (100%)
rename {!NetSurf => frontends/riscos/appdir}/5Sprites,ff9 (100%)
rename {!NetSurf => frontends/riscos/appdir}/5Sprites11,ff9 (100%)
rename {!NetSurf => frontends/riscos/appdir}/5Sprites22,ff9 (100%)
rename {!NetSurf => frontends/riscos/appdir}/ASprites,ff9 (100%)
rename {!NetSurf => frontends/riscos/appdir}/ASprites11,ff9 (100%)
rename {!NetSurf => frontends/riscos/appdir}/ASprites22,ff9 (100%)
create mode 100644 frontends/riscos/appdir/ChkSprites,ffb
rename {!NetSurf => frontends/riscos/appdir}/Docs/online,b60 (100%)
rename {!NetSurf => frontends/riscos/appdir}/FixFonts,ffb (100%)
rename {!NetSurf => frontends/riscos/appdir}/KickNS,ffb (100%)
rename {!NetSurf => frontends/riscos/appdir}/OpenChoices,feb (100%)
rename {!NetSurf => frontends/riscos/appdir}/OpenHelp,ffb (100%)
rename {!NetSurf => frontends/riscos/appdir}/OpenScrap,feb (100%)
create mode 120000 frontends/riscos/appdir/Resources/AdBlock,f79
rename {!NetSurf => frontends/riscos/appdir}/Resources/Aletheia,ffd (100%)
create mode 120000 frontends/riscos/appdir/Resources/CSS,f79
rename {!NetSurf => frontends/riscos/appdir}/Resources/Fonts/NSSymbol/Encoding (100%)
rename {!NetSurf => frontends/riscos/appdir}/Resources/Fonts/NSSymbol/IntMetrics,ff6 (100%)
rename {!NetSurf => frontends/riscos/appdir}/Resources/Fonts/NSSymbol/Outlines,ff6 (100%)
create mode 120000 frontends/riscos/appdir/Resources/Icons
rename {!NetSurf => frontends/riscos/appdir}/Resources/Image,ff9 (100%)
rename {!NetSurf => frontends/riscos/appdir}/Resources/LangNames (100%)
create mode 120000 frontends/riscos/appdir/Resources/Quirks,f79
rename {!NetSurf => frontends/riscos/appdir}/Resources/SearchEngines (100%)
rename {!NetSurf => frontends/riscos/appdir}/Resources/Sprites,ff9 (100%)
create mode 120000 frontends/riscos/appdir/Resources/ca-bundle
create mode 120000 frontends/riscos/appdir/Resources/de/Messages
create mode 120000 frontends/riscos/appdir/Resources/de/welcome.html,faf
rename {!NetSurf => frontends/riscos/appdir}/Resources/en/!Help (100%)
create mode 120000 frontends/riscos/appdir/Resources/en/Messages
create mode 120000 frontends/riscos/appdir/Resources/en/credits.html,faf
create mode 120000 frontends/riscos/appdir/Resources/en/licence.html,faf
create mode 120000 frontends/riscos/appdir/Resources/en/maps.html,faf
create mode 120000 frontends/riscos/appdir/Resources/en/welcome.html,faf
create mode 120000 frontends/riscos/appdir/Resources/fr/Messages
create mode 120000 frontends/riscos/appdir/Resources/internal.css,f79
create mode 120000 frontends/riscos/appdir/Resources/it/Messages
create mode 120000 frontends/riscos/appdir/Resources/it/credits.html,faf
create mode 120000 frontends/riscos/appdir/Resources/it/licence.html,faf
create mode 120000 frontends/riscos/appdir/Resources/it/welcome.html,faf
create mode 120000 frontends/riscos/appdir/Resources/ja/welcome.html,faf
create mode 120000 frontends/riscos/appdir/Resources/netsurf.png,b60
rename {!NetSurf => frontends/riscos/appdir}/Resources/nl/!Help (100%)
create mode 120000 frontends/riscos/appdir/Resources/nl/Messages
create mode 120000 frontends/riscos/appdir/Resources/nl/credits.html,faf
create mode 120000 frontends/riscos/appdir/Resources/nl/licence.html,faf
create mode 120000 frontends/riscos/appdir/Resources/nl/welcome.html,faf
rename frontends/windows/{filetype.c => fetch.c} (55%)
rename frontends/windows/{filetype.h => fetch.h} (63%)
create mode 100644 frontends/windows/login.c
copy content/handlers/pdf/pdf.h => frontends/windows/login.h (66%)
create mode 120000 frontends/windows/res/icons/arrow-l.png
create mode 120000 frontends/windows/res/icons/content.png
create mode 120000 frontends/windows/res/icons/directory.png
create mode 120000 frontends/windows/res/icons/directory2.png
create mode 120000 frontends/windows/res/icons/hotlist-add.png
create mode 120000 frontends/windows/res/icons/hotlist-rmv.png
create mode 120000 frontends/windows/res/icons/search.png
delete mode 100644 render/Makefile
rename !NetSurf/Resources/AdBlock,f79 => resources/adblock.css (100%)
rename {!NetSurf/Resources => resources}/ca-bundle (69%)
rename !NetSurf/Resources/de/welcome.html,faf => resources/de/welcome.html (87%)
rename !NetSurf/Resources/CSS,f79 => resources/default.css (100%)
rename !NetSurf/Resources/en/credits.html,faf => resources/en/credits.html (97%)
rename !NetSurf/Resources/en/licence.html,faf => resources/en/licence.html (99%)
rename !NetSurf/Resources/en/maps.html,faf => resources/en/maps.html (100%)
rename !NetSurf/Resources/en/welcome.html,faf => resources/en/welcome.html (86%)
rename {!NetSurf/Resources/Icons => resources/icons}/arrow-l.png (100%)
rename {!NetSurf/Resources/Icons => resources/icons}/content.png (100%)
rename {!NetSurf/Resources/Icons => resources/icons}/directory.png (100%)
rename {!NetSurf/Resources/Icons => resources/icons}/directory2.png (100%)
rename {!NetSurf/Resources/Icons => resources/icons}/hotlist-add.png (100%)
rename {!NetSurf/Resources/Icons => resources/icons}/hotlist-rmv.png (100%)
rename {!NetSurf/Resources/Icons => resources/icons}/search.png (100%)
rename !NetSurf/Resources/internal.css,f79 => resources/internal.css (100%)
rename !NetSurf/Resources/it/credits.html,faf => resources/it/credits.html (97%)
rename !NetSurf/Resources/it/licence.html,faf => resources/it/licence.html (99%)
rename !NetSurf/Resources/it/welcome.html,faf => resources/it/welcome.html (87%)
rename !NetSurf/Resources/ja/welcome.html,faf => resources/ja/welcome.html (86%)
rename !NetSurf/Resources/netsurf.png,b60 => resources/netsurf.png (100%)
rename !NetSurf/Resources/nl/credits.html,faf => resources/nl/credits.html (92%)
rename !NetSurf/Resources/nl/licence.html,faf => resources/nl/licence.html (99%)
rename !NetSurf/Resources/nl/welcome.html,faf => resources/nl/welcome.html (85%)
rename !NetSurf/Resources/Quirks,f79 => resources/quirks.css (100%)
create mode 100644 utils/http/strict-transport-security.c
create mode 100644 utils/http/strict-transport-security.h
delete mode 100755 utils/merge-messages.lua
diff --git a/!NetSurf/ChkSprites,ffb b/!NetSurf/ChkSprites,ffb
deleted file mode 100644
index 4e7d325..0000000
Binary files a/!NetSurf/ChkSprites,ffb and /dev/null differ
diff --git a/.gitignore b/.gitignore
index 35de191..fa42a20 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,23 +1,17 @@
*~
-\!NetSurf/!Run,feb
-\!NetSurf/!RunImage,ff8
-\!NetSurf/!Help,feb
-\!NetSurf/Resources/en/Templates,fec
-\!NetSurf/Resources/en/Messages
-\!NetSurf/Resources/fr/Templates,fec
-\!NetSurf/Resources/fr/Messages
-\!NetSurf/Resources/de/Templates,fec
-\!NetSurf/Resources/de/Messages
-\!NetSurf/Resources/nl/Templates,fec
-\!NetSurf/Resources/nl/Messages
-\!NetSurf/Resources/it/Messages
-frontends/gtk/res/en/Messages
-frontends/gtk/res/fr/Messages
-frontends/gtk/res/de/Messages
-frontends/gtk/res/nl/Messages
-frontends/gtk/res/it/Messages
+frontends/riscos/appdir/!Run,feb
+frontends/riscos/appdir/!RunImage,ff8
+frontends/riscos/appdir/!Help,feb
+frontends/riscos/appdir/Resources/en/Templates,fec
+frontends/riscos/appdir/Resources/fr/Templates,fec
+frontends/riscos/appdir/Resources/de/Templates,fec
+frontends/riscos/appdir/Resources/nl/Templates,fec
+resources/*/Messages
+frontends/gtk/res/*/Messages
+frontends/windows/res/*/Messages
codedocs
nsgtk
+nsgtk3
nsfb
nsmonkey
nsdebug
diff --git a/Makefile b/Makefile
index 011fc1f..2cad7d4 100644
--- a/Makefile
+++ b/Makefile
@@ -130,7 +130,7 @@ MESSAGES_FILTER=any
# The languages in the fat messages to convert
MESSAGES_LANGUAGES=de en fr it nl
# The target directory for the split messages
-MESSAGES_TARGET=!NetSurf/Resources
+MESSAGES_TARGET=resources
# Defaults for tools
PERL=perl
@@ -576,6 +576,25 @@ CXXFLAGS += -DNETSURF_HOMEPAGE=\"$(NETSURF_HOMEPAGE)\"
CFLAGS += -DNETSURF_LOG_LEVEL=$(NETSURF_LOG_LEVEL)
CXXFLAGS += -DNETSURF_LOG_LEVEL=$(NETSURF_LOG_LEVEL)
+# If we're building the sanitize goal, override things
+ifneq ($(filter-out sanitize,$(MAKECMDGOALS)),$(MAKECMDGOALS))
+override NETSURF_USE_SANITIZER := YES
+override NETSURF_RECOVER_SANITIZERS := NO
+endif
+
+# If we're going to use the sanitizer set it up
+ifeq ($(NETSURF_USE_SANITIZER),YES)
+SAN_FLAGS := -fsanitize=address -fsanitize=undefined
+ifeq ($(NETSURF_RECOVER_SANITIZERS),NO)
+SAN_FLAGS += -fno-sanitize-recover
+endif
+else
+SAN_FLAGS :=
+endif
+CFLAGS += $(SAN_FLAGS)
+CXXFLAGS += $(SAN_FLAGS)
+LDFLAGS += $(SAN_FLAGS)
+
# and the logging filter
CFLAGS += -DNETSURF_BUILTIN_LOG_FILTER=\"$(NETSURF_BUILTIN_LOG_FILTER)\"
CXXFLAGS += -DNETSURF_BUILTIN_LOG_FILTER=\"$(NETSURF_BUILTIN_LOG_FILTER)\"
@@ -618,9 +637,6 @@ include frontends/Makefile
# Content sources
include content/Makefile
-# render sources
-include render/Makefile
-
# utility sources
include utils/Makefile
@@ -637,7 +653,6 @@ include desktop/Makefile
S_COMMON := \
$(S_CONTENT) \
$(S_FETCHERS) \
- $(S_RENDER) \
$(S_UTILS) \
$(S_HTTP) \
$(S_NSURL) \
@@ -652,16 +667,12 @@ S_COMMON := \
# Message splitting rule generation macro
# 1 = Language
define split_messages
-.INTERMEDIATE:$$(MESSAGES_TARGET)/$(1)/Messages.tmp
-$$(MESSAGES_TARGET)/$(1)/Messages.tmp: resources/FatMessages
+$$(MESSAGES_TARGET)/$(1)/Messages: resources/FatMessages
$$(VQ)echo "MSGSPLIT: Language: $(1) Filter: $$(MESSAGES_FILTER)"
$$(Q)$$(MKDIR) -p $$(MESSAGES_TARGET)/$(1)
- $$(Q)$$(SPLIT_MESSAGES) -l $(1) -p $$(MESSAGES_FILTER) -f messages -o $$@ $$<
-
-$$(MESSAGES_TARGET)/$(1)/Messages: $$(MESSAGES_TARGET)/$(1)/Messages.tmp
- $$(VQ)echo "COMPRESS: $$@"
- $$(Q)gzip -9n < $$< > $$@
+ $$(Q)$$(RM) $$@
+ $$(Q)$$(SPLIT_MESSAGES) -l $(1) -p $$(MESSAGES_FILTER) -f messages -o $$@ -z $$<
CLEAN_MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
@@ -753,7 +764,6 @@ DEPFILES :=
# 3 = obj filename, no prefix
define dependency_generate_c
DEPFILES += $(2)
-$$(DEPROOT)/$(2): $$(DEPROOT)/created $(1) Makefile.config
endef
@@ -762,7 +772,6 @@ endef
# 3 = obj filename, no prefix
define dependency_generate_s
DEPFILES += $(2)
-$$(DEPROOT)/$(2): $$(DEPROOT)/created $(1)
endef
@@ -772,7 +781,7 @@ endef
ifeq ($(CC_MAJOR),2)
# simpler deps tracking for gcc2...
define compile_target_c
-$$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
$$(VQ)echo " DEP: $(1)"
$$(Q)$$(RM) $$(DEPROOT)/$(3)
$$(Q)$$(CC) $$(IFLAGS) $$(CFLAGS) -MM \
@@ -785,7 +794,7 @@ $$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
endef
else
define compile_target_c
-$$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
$$(VQ)echo " COMPILE: $(1)"
$$(Q)$$(RM) $$(DEPROOT)/$(3)
$$(Q)$$(RM) $$(OBJROOT)/$(2)
@@ -797,7 +806,7 @@ endef
endif
define compile_target_cpp
-$$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
$$(VQ)echo " DEP: $(1)"
$$(Q)$$(RM) $$(DEPROOT)/$(3)
$$(Q)$$(CC) $$(IFLAGS) $$(CXXFLAGS) $$(COMMON_WARNFLAGS) $$(CXXWARNFLAGS) -MM \
@@ -813,7 +822,7 @@ endef
# 2 = obj filename, no prefix
# 3 = dep filename, no prefix
define compile_target_s
-$$(DEPROOT)/$(3) $$(OBJROOT)/$(2): $$(OBJROOT)/created
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
$$(VQ)echo "ASSEMBLE: $(1)"
$$(Q)$$(RM) $$(DEPROOT)/$(3)
$$(Q)$$(RM) $$(OBJROOT)/$(2)
diff --git a/Makefile.config.example b/Makefile.config.example
index aeddc10..7fa7f41 100644
--- a/Makefile.config.example
+++ b/Makefile.config.example
@@ -33,3 +33,9 @@
### To change flags to javascript binding generator
# GBFLAGS:=-g
+
+### To enable ASAN and UBSAN support in builds regardless of target
+# override NETSURF_USE_SANITIZER := YES
+
+### If you're using the sanitizers and you want it to stop on failure...
+# override NETSURF_RECOVER_SANITIZERS := NO
diff --git a/Makefile.defaults b/Makefile.defaults
index 6bb82cb..85fb9b8 100644
--- a/Makefile.defaults
+++ b/Makefile.defaults
@@ -107,6 +107,11 @@ NETSURF_USE_LIBICONV_PLUG := YES
# Valid options: YES, NO
NETSURF_FS_BACKING_STORE := NO
+# Enable the ASAN and UBSAN flags regardless of targets
+NETSURF_USE_SANITIZERS := NO
+# But recover after sanitizer failure
+NETSURF_RECOVER_SANITIZERS := YES
+
# Initial CFLAGS. Optimisation level etc. tend to be target specific.
CFLAGS :=
diff --git a/content/content.c b/content/content.c
index d359268..3cf38b7 100644
--- a/content/content.c
+++ b/content/content.c
@@ -74,7 +74,7 @@ nserror content__init(struct content *c, const content_handler *handler,
nserror error;
NSLOG(netsurf, INFO, "url "URL_FMT_SPC" -> %p",
- nsurl_access(llcache_handle_get_url(llcache)), c);
+ nsurl_access_log(llcache_handle_get_url(llcache)), c);
user_sentinel = calloc(1, sizeof(struct content_user));
if (user_sentinel == NULL) {
@@ -274,7 +274,7 @@ void content_convert(struct content *c)
return;
NSLOG(netsurf, INFO, "content "URL_FMT_SPC" (%p)",
- nsurl_access(llcache_handle_get_url(c->llcache)), c);
+ nsurl_access_log(llcache_handle_get_url(c->llcache)), c);
if (c->handler->data_complete != NULL) {
c->locked = true;
@@ -379,7 +379,7 @@ void content_destroy(struct content *c)
assert(c);
NSLOG(netsurf, INFO, "content %p %s", c,
- nsurl_access(llcache_handle_get_url(c->llcache)));
+ nsurl_access_log(llcache_handle_get_url(c->llcache)));
assert(c->locked == false);
if (c->handler->destroy != NULL)
@@ -658,8 +658,8 @@ bool content_add_user(
struct content_user *user;
NSLOG(netsurf, INFO, "content "URL_FMT_SPC" (%p), user %p %p",
- nsurl_access(llcache_handle_get_url(c->llcache)), c, callback,
- pw);
+ nsurl_access_log(llcache_handle_get_url(c->llcache)),
+ c, callback, pw);
user = malloc(sizeof(struct content_user));
if (!user)
return false;
@@ -693,8 +693,8 @@ void content_remove_user(
{
struct content_user *user, *next;
NSLOG(netsurf, INFO, "content "URL_FMT_SPC" (%p), user %p %p",
- nsurl_access(llcache_handle_get_url(c->llcache)), c, callback,
- pw);
+ nsurl_access_log(llcache_handle_get_url(c->llcache)),
+ c, callback, pw);
/* user_list starts with a sentinel */
for (user = c->user_list; user->next != 0 &&
@@ -816,7 +816,7 @@ void content_open(hlcache_handle *h, struct browser_window *bw,
struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
NSLOG(netsurf, INFO, "content %p %s", c,
- nsurl_access(llcache_handle_get_url(c->llcache)));
+ nsurl_access_log(llcache_handle_get_url(c->llcache)));
if (c->handler->open != NULL)
c->handler->open(c, bw, page, params);
}
@@ -833,7 +833,7 @@ void content_close(hlcache_handle *h)
struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
NSLOG(netsurf, INFO, "content %p %s", c,
- nsurl_access(llcache_handle_get_url(c->llcache)));
+ nsurl_access_log(llcache_handle_get_url(c->llcache)));
if (c->handler->close != NULL)
c->handler->close(c);
}
diff --git a/content/fetchers/curl.c b/content/fetchers/curl.c
index a6146ed..7ce7c5b 100644
--- a/content/fetchers/curl.c
+++ b/content/fetchers/curl.c
@@ -67,6 +67,21 @@
/** maximum number of X509 certificates in chain for TLS connection */
#define MAX_CERTS 10
+/* the ciphersuites we are willing to use */
+#define CIPHER_LIST \
+ /* disable everything */ \
+ "-ALL:" \
+ /* enable TLSv1.2 PFS suites */ \
+ "EECDH+AES+TLSv1.2:EDH+AES+TLSv1.2:" \
+ /* enable PFS AES GCM suites */ \
+ "EECDH+AESGCM:EDH+AESGCM:" \
+ /* Enable PFS AES CBC suites */ \
+ "EECDH+AES:EDH+AES:" \
+ /* Enable non-PFS fallback suite */ \
+ "AES128-SHA:" \
+ /* Remove any PFS suites using weak DSA key exchange */ \
+ "-DSS"
+
/** SSL certificate info */
struct cert_info {
X509 *cert; /**< Pointer to certificate */
@@ -555,10 +570,16 @@ fetch_curl_sslctxfun(CURL *curl_handle, void *_sslctx, void *parm)
/* Ensure server rejects the connection if downgraded too far */
SSL_CTX_set_mode(sslctx, SSL_MODE_SEND_FALLBACK_SCSV);
#endif
+ /* Disable TLS1.2 ciphersuites */
+ SSL_CTX_set_cipher_list(sslctx, CIPHER_LIST ":-TLSv1.2");
}
SSL_CTX_set_options(sslctx, options);
+#ifdef SSL_OP_NO_TICKET
+ SSL_CTX_clear_options(sslctx, SSL_OP_NO_TICKET);
+#endif
+
return CURLE_OK;
}
@@ -646,8 +667,8 @@ static CURLcode fetch_curl_set_options(struct curl_fetch_info *f)
SETOPT(CURLOPT_PROXY, NULL);
}
- /* Disable SSL session ID caching, as some servers can't cope. */
- SETOPT(CURLOPT_SSL_SESSIONID_CACHE, 0);
+ /* Force-enable SSL session ID caching, as some distros are odd. */
+ SETOPT(CURLOPT_SSL_SESSIONID_CACHE, 1);
if (urldb_get_cert_permissions(f->url)) {
/* Disable certificate verification */
@@ -1158,7 +1179,7 @@ static void fetch_curl_poll(lwc_string *scheme_ignored)
&exc_fd_set, &max_fd);
assert(codem == CURLM_OK);
- NSLOG(netsurf, INFO,
+ NSLOG(netsurf, DEEPDEBUG,
"Curl file descriptor states (maxfd=%i):", max_fd);
for (i = 0; i <= max_fd; i++) {
bool read = false;
@@ -1175,7 +1196,7 @@ static void fetch_curl_poll(lwc_string *scheme_ignored)
error = true;
}
if (read || write || error) {
- NSLOG(netsurf, INFO, " fd %i: %s %s %s", i,
+ NSLOG(netsurf, DEEPDEBUG, " fd %i: %s %s %s", i,
read ? "read" : " ",
write ? "write" : " ",
error ? "error" : " ");
@@ -1187,7 +1208,7 @@ static void fetch_curl_poll(lwc_string *scheme_ignored)
do {
codem = curl_multi_perform(fetch_curl_multi, &running);
if (codem != CURLM_OK && codem != CURLM_CALL_MULTI_PERFORM) {
- NSLOG(netsurf, INFO, "curl_multi_perform: %i %s",
+ NSLOG(netsurf, WARNING, "curl_multi_perform: %i %s",
codem, curl_multi_strerror(codem));
guit->misc->warning("MiscError", curl_multi_strerror(codem));
return;
@@ -1508,6 +1529,7 @@ nserror fetch_curl_register(void)
SETOPT(CURLOPT_LOW_SPEED_TIME, 180L);
SETOPT(CURLOPT_NOSIGNAL, 1L);
SETOPT(CURLOPT_CONNECTTIMEOUT, nsoption_uint(curl_fetch_timeout));
+ SETOPT(CURLOPT_SSL_CIPHER_LIST, CIPHER_LIST);
if (nsoption_charp(ca_bundle) &&
strcmp(nsoption_charp(ca_bundle), "")) {
diff --git a/content/fs_backing_store.c b/content/fs_backing_store.c
index 1b59ea1..19eb1ca 100644
--- a/content/fs_backing_store.c
+++ b/content/fs_backing_store.c
@@ -1141,7 +1141,7 @@ build_entrymap(struct store_state *state)
{
unsigned int eloop;
- NSLOG(netsurf, INFO, "Allocating %ld bytes for max of %d buckets",
+ NSLOG(netsurf, INFO, "Allocating %"PRIsizet" bytes for max of %d buckets",
(1 << state->ident_bits) * sizeof(entry_index_t),
1 << state->ident_bits);
@@ -1220,7 +1220,7 @@ read_entries(struct store_state *state)
entries_size = (1 << state->entry_bits) * sizeof(struct store_entry);
NSLOG(netsurf, INFO,
- "Allocating %"PRIsizet" bytes for max of %d entries of %ld length elements %ld length",
+ "Allocating %"PRIsizet" bytes for max of %d entries of %"PRIsizet" length elements %"PRIsizet" length",
entries_size,
1 << state->entry_bits,
sizeof(struct store_entry),
@@ -1565,6 +1565,7 @@ initialise(const struct llcache_store_parameters *parameters)
ret = build_entrymap(newstate);
if (ret != NSERROR_OK) {
/* that obviously went well */
+ free(newstate->entries);
free(newstate->path);
free(newstate);
return ret;
@@ -1573,6 +1574,8 @@ initialise(const struct llcache_store_parameters *parameters)
ret = read_blocks(newstate);
if (ret != NSERROR_OK) {
/* oh dear */
+ free(newstate->addrmap);
+ free(newstate->entries);
free(newstate->path);
free(newstate);
return ret;
@@ -1640,6 +1643,8 @@ finalise(void)
0);
}
+ free(storestate->addrmap);
+ free(storestate->entries);
free(storestate->path);
free(storestate);
storestate = NULL;
diff --git a/content/handlers/Makefile b/content/handlers/Makefile
index 416969f..b88f3ca 100644
--- a/content/handlers/Makefile
+++ b/content/handlers/Makefile
@@ -13,9 +13,20 @@ include content/handlers/javascript/Makefile
S_CONTENT += $(addprefix handlers/javascript/,$(S_JAVASCRIPT))
-# PDF source
+# HTML content handler sources
+include content/handlers/html/Makefile
+
+S_CONTENT += $(addprefix handlers/html/,$(S_HTML))
+
+# Text content handler sources
+include content/handlers/text/Makefile
+
+S_CONTENT += $(addprefix handlers/text/,$(S_TEXT))
+
+# PDF content handler source
include content/handlers/pdf/Makefile
S_CONTENT += $(addprefix handlers/pdf/,$(S_PDF))
+# extend the include search path
INCLUDE_DIRS += content/handlers
diff --git a/content/handlers/css/dump.c b/content/handlers/css/dump.c
index 529bd4a..b12e1d9 100644
--- a/content/handlers/css/dump.c
+++ b/content/handlers/css/dump.c
@@ -113,6 +113,45 @@ static void dump_css_unit(FILE *stream, css_fixed val, css_unit unit)
case CSS_UNIT_KHZ:
fprintf(stream, "kHz");
break;
+ case CSS_UNIT_CAP:
+ fprintf(stream, "cap");
+ break;
+ case CSS_UNIT_CH:
+ fprintf(stream, "ch");
+ break;
+ case CSS_UNIT_IC:
+ fprintf(stream, "ic");
+ break;
+ case CSS_UNIT_REM:
+ fprintf(stream, "rem");
+ break;
+ case CSS_UNIT_LH:
+ fprintf(stream, "lh");
+ break;
+ case CSS_UNIT_RLH:
+ fprintf(stream, "rlh");
+ break;
+ case CSS_UNIT_VH:
+ fprintf(stream, "vh");
+ break;
+ case CSS_UNIT_VW:
+ fprintf(stream, "vw");
+ break;
+ case CSS_UNIT_VI:
+ fprintf(stream, "vi");
+ break;
+ case CSS_UNIT_VB:
+ fprintf(stream, "vb");
+ break;
+ case CSS_UNIT_VMIN:
+ fprintf(stream, "vmin");
+ break;
+ case CSS_UNIT_VMAX:
+ fprintf(stream, "vmax");
+ break;
+ case CSS_UNIT_Q:
+ fprintf(stream, "q");
+ break;
}
}
diff --git a/content/handlers/css/select.c b/content/handlers/css/select.c
index 328d6a7..ee79eb3 100644
--- a/content/handlers/css/select.c
+++ b/content/handlers/css/select.c
@@ -278,7 +278,7 @@ css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n,
* element's style */
error = css_computed_style_compose(ctx->parent_style,
styles->styles[CSS_PSEUDO_ELEMENT_NONE],
- nscss_compute_font_size, NULL,
+ nscss_compute_font_size, ctx,
&composed);
if (error != CSS_OK) {
css_select_results_destroy(styles);
@@ -310,7 +310,7 @@ css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n,
error = css_computed_style_compose(
styles->styles[CSS_PSEUDO_ELEMENT_NONE],
styles->styles[pseudo_element],
- nscss_compute_font_size, NULL,
+ nscss_compute_font_size, ctx,
&composed);
if (error != CSS_OK) {
/* TODO: perhaps this shouldn't be quite so
@@ -349,7 +349,7 @@ css_computed_style *nscss_get_blank_style(nscss_select_ctx *ctx,
/* TODO: Do we really need to compose? Initial style shouldn't
* have any inherited properties. */
error = css_computed_style_compose(parent, partial,
- nscss_compute_font_size, NULL, &composed);
+ nscss_compute_font_size, ctx, &composed);
css_computed_style_destroy(partial);
if (error != CSS_OK) {
css_computed_style_destroy(composed);
@@ -422,14 +422,37 @@ css_error nscss_compute_font_size(void *pw, const css_hint *parent,
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.unit == CSS_UNIT_EX ||
+ size->data.length.unit == CSS_UNIT_CAP ||
+ size->data.length.unit == CSS_UNIT_CH ||
+ size->data.length.unit == CSS_UNIT_IC) {
size->data.length.value =
FMUL(size->data.length.value, parent_size.value);
- if (size->data.length.unit == CSS_UNIT_EX) {
+ switch (size->data.length.unit) {
+ case CSS_UNIT_EX:
/* 1ex = 0.6em in NetSurf */
size->data.length.value = FMUL(size->data.length.value,
FLTTOFIX(0.6));
+ break;
+ case CSS_UNIT_CAP:
+ /* Height of captals. 1cap = 0.9em in NetSurf. */
+ size->data.length.value = FMUL(size->data.length.value,
+ FLTTOFIX(0.9));
+ break;
+ case CSS_UNIT_CH:
+ /* Width of '0'. 1ch = 0.4em in NetSurf. */
+ size->data.length.value = FMUL(size->data.length.value,
+ FLTTOFIX(0.4));
+ break;
+ case CSS_UNIT_IC:
+ /* Width of U+6C43. 1ic = 1.1em in NetSurf. */
+ size->data.length.value = FMUL(size->data.length.value,
+ FLTTOFIX(1.1));
+ break;
+ default:
+ /* No scaling required for EM. */
+ break;
}
size->data.length.unit = parent_size.unit;
@@ -437,6 +460,25 @@ css_error nscss_compute_font_size(void *pw, const css_hint *parent,
size->data.length.value = FDIV(FMUL(size->data.length.value,
parent_size.value), INTTOFIX(100));
size->data.length.unit = parent_size.unit;
+ } else if (size->data.length.unit == CSS_UNIT_REM) {
+ nscss_select_ctx *ctx = pw;
+ if (parent == NULL) {
+ size->data.length.value = parent_size.value;
+ size->data.length.unit = parent_size.unit;
+ } else {
+ css_computed_font_size(ctx->root_style,
+ &parent_size.value,
+ &size->data.length.unit);
+ size->data.length.value = FMUL(
+ size->data.length.value,
+ parent_size.value);
+ }
+ } else if (size->data.length.unit == CSS_UNIT_RLH) {
+ /** TODO: Convert root element line-height to absolute value. */
+ size->data.length.value = FMUL(size->data.length.value, FDIV(
+ INTTOFIX(nsoption_int(font_size)),
+ INTTOFIX(10)));
+ size->data.length.unit = CSS_UNIT_PT;
}
size->status = CSS_FONT_SIZE_DIMENSION;
diff --git a/content/handlers/css/select.h b/content/handlers/css/select.h
index abfb858..9fa6d3a 100644
--- a/content/handlers/css/select.h
+++ b/content/handlers/css/select.h
@@ -37,6 +37,7 @@ typedef struct nscss_select_ctx
bool quirks;
struct nsurl *base_url;
lwc_string *universal;
+ const css_computed_style *root_style;
const css_computed_style *parent_style;
} nscss_select_ctx;
diff --git a/content/handlers/css/utils.c b/content/handlers/css/utils.c
index 5c7cbd9..8fe157b 100644
--- a/content/handlers/css/utils.c
+++ b/content/handlers/css/utils.c
@@ -27,11 +27,75 @@
/** Screen DPI in fixed point units: defaults to 90, which RISC OS uses */
css_fixed nscss_screen_dpi = F_90;
+
+/**
+ * Map viewport-relative length units to either vh or vw.
+ *
+ * Non-viewport-relative units are unchanged.
+ *
+ * \param[in] ctx Length conversion context.
+ * \param[in] unit Unit to map.
+ * \return the mapped unit.
+ */
+static inline css_unit css_utils__fudge_viewport_units(
+ const nscss_len_ctx *ctx,
+ css_unit unit)
+{
+ switch (unit) {
+ case CSS_UNIT_VI:
+ assert(ctx->root_style != NULL);
+ if (css_computed_writing_mode(ctx->root_style) ==
+ CSS_WRITING_MODE_HORIZONTAL_TB) {
+ unit = CSS_UNIT_VW;
+ } else {
+ unit = CSS_UNIT_VH;
+ }
+ break;
+ case CSS_UNIT_VB:
+ assert(ctx->root_style != NULL);
+ if (css_computed_writing_mode(ctx->root_style) ==
+ CSS_WRITING_MODE_HORIZONTAL_TB) {
+ unit = CSS_UNIT_VH;
+ } else {
+ unit = CSS_UNIT_VW;
+ }
+ break;
+ case CSS_UNIT_VMIN:
+ if (ctx->vh < ctx->vw) {
+ unit = CSS_UNIT_VH;
+ } else {
+ unit = CSS_UNIT_VW;
+ }
+ break;
+ case CSS_UNIT_VMAX:
+ if (ctx->vh > ctx->vw) {
+ unit = CSS_UNIT_VH;
+ } else {
+ unit = CSS_UNIT_VW;
+ }
+ break;
+ default: break;
+ }
+
+ return unit;
+}
+
/* exported interface documented in content/handlers/css/utils.h */
-css_fixed nscss_len2pt(css_fixed length, css_unit unit)
+css_fixed nscss_len2pt(
+ const nscss_len_ctx *ctx,
+ css_fixed length,
+ css_unit unit)
{
/* Length must not be relative */
- assert(unit != CSS_UNIT_EM && unit != CSS_UNIT_EX);
+ assert(unit != CSS_UNIT_EM &&
+ unit != CSS_UNIT_EX &&
+ unit != CSS_UNIT_CAP &&
+ unit != CSS_UNIT_CH &&
+ unit != CSS_UNIT_IC &&
+ unit != CSS_UNIT_REM &&
+ unit != CSS_UNIT_RLH);
+
+ unit = css_utils__fudge_viewport_units(ctx, unit);
switch (unit) {
/* We assume the screen and any other output has the same dpi */
@@ -45,36 +109,50 @@ css_fixed nscss_len2pt(css_fixed length, css_unit unit)
/* 1in = 25.4mm => 1mm = (72/25.4)pt */
case CSS_UNIT_MM: return FMUL(length,
FDIV(F_72, FLTTOFIX(25.4)));
+ /* 1in = 101.6q => 1mm = (72/101.6)pt */
+ case CSS_UNIT_Q: return FMUL(length,
+ FDIV(F_72, FLTTOFIX(101.6)));
case CSS_UNIT_PT: return length;
/* 1pc = 12pt */
case CSS_UNIT_PC: return FMUL(length, INTTOFIX(12));
+ case CSS_UNIT_VH: return FDIV(FMUL(FDIV((length * ctx->vh), F_100),
+ F_72), nscss_screen_dpi);
+ case CSS_UNIT_VW: return FDIV(FMUL(FDIV((length * ctx->vw), F_100),
+ F_72), nscss_screen_dpi);
default: break;
}
return 0;
}
-
/* exported interface documented in content/handlers/css/utils.h */
-css_fixed nscss_len2px(css_fixed length, css_unit unit,
+css_fixed nscss_len2px(
+ const nscss_len_ctx *ctx,
+ 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));
+ unit = css_utils__fudge_viewport_units(ctx, unit);
switch (unit) {
case CSS_UNIT_EM:
case CSS_UNIT_EX:
+ case CSS_UNIT_CAP:
+ case CSS_UNIT_CH:
+ case CSS_UNIT_IC:
{
css_fixed font_size = 0;
css_unit font_unit = CSS_UNIT_PT;
+ assert(style != NULL);
+
css_computed_font_size(style, &font_size, &font_unit);
/* Convert to points */
- font_size = nscss_len2pt(font_size, font_unit);
+ font_size = nscss_len2pt(ctx, font_size, font_unit);
/* Clamp to configured minimum */
if (font_size < FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)) {
@@ -85,9 +163,22 @@ css_fixed nscss_len2px(css_fixed length, css_unit unit,
* 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)
+ /* Scale non-em units to em. We have fixed ratios. */
+ switch (unit) {
+ case CSS_UNIT_EX:
px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.6));
+ break;
+ case CSS_UNIT_CAP:
+ px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.9));
+ break;
+ case CSS_UNIT_CH:
+ px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.4));
+ break;
+ case CSS_UNIT_IC:
+ px_per_unit = FMUL(px_per_unit, FLTTOFIX(1.1));
+ break;
+ default: break;
+ }
}
break;
case CSS_UNIT_PX:
@@ -105,6 +196,10 @@ css_fixed nscss_len2px(css_fixed length, css_unit unit,
case CSS_UNIT_MM:
px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(25.4));
break;
+ /* 1in = 101.6q => 1q = (DPI/101.6)px */
+ case CSS_UNIT_Q:
+ px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(101.6));
+ break;
/* 1in = 72pt => 1pt = (DPI/72)px */
case CSS_UNIT_PT:
px_per_unit = FDIV(nscss_screen_dpi, F_72);
@@ -113,6 +208,39 @@ css_fixed nscss_len2px(css_fixed length, css_unit unit,
case CSS_UNIT_PC:
px_per_unit = FDIV(nscss_screen_dpi, INTTOFIX(6));
break;
+ case CSS_UNIT_REM:
+ {
+ css_fixed font_size = 0;
+ css_unit font_unit = CSS_UNIT_PT;
+
+ assert(ctx->root_style != NULL);
+
+ css_computed_font_size(ctx->root_style,
+ &font_size, &font_unit);
+
+ /* Convert to points */
+ font_size = nscss_len2pt(ctx, 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);
+ break;
+ }
+ /* 1rlh = <user_font_size>pt => 1rlh = (DPI/user_font_size)px */
+ case CSS_UNIT_RLH:
+ px_per_unit = FDIV(nscss_screen_dpi, FDIV(
+ INTTOFIX(nsoption_int(font_size)),
+ INTTOFIX(10)));
+ break;
+ case CSS_UNIT_VH:
+ return TRUNCATEFIX((FDIV((length * ctx->vh), F_100) + F_0_5));
+ case CSS_UNIT_VW:
+ return TRUNCATEFIX((FDIV((length * ctx->vw), F_100) + F_0_5));
default:
px_per_unit = 0;
break;
diff --git a/content/handlers/css/utils.h b/content/handlers/css/utils.h
index 21cb497..c8f4c82 100644
--- a/content/handlers/css/utils.h
+++ b/content/handlers/css/utils.h
@@ -27,24 +27,54 @@
extern css_fixed nscss_screen_dpi;
/**
+ * Length conversion context data.
+ */
+typedef struct nscss_len_ctx {
+ /**
+ * Viewport width in px.
+ * Only used if unit is vh, vw, vi, vb, vmin, or vmax.
+ */
+ int vw;
+ /**
+ * Viewport height in px.
+ * Only used if unit is vh, vw, vi, vb, vmin, or vmax.
+ */
+ int vh;
+ /**
+ * Computed style for the document root element.
+ * May be NULL if unit is not rem, or rlh.
+ */
+ const css_computed_style *root_style;
+} nscss_len_ctx;
+
+/**
* Convert an absolute CSS length to points.
*
- * \param[in] length Absolute CSS length.
- * \param[in] unit Unit of the length.
+ * \param[in] ctx Length conversion context.
+ * \param[in] length Absolute CSS length.
+ * \param[in] unit Unit of the length.
* \return length in points
*/
-css_fixed nscss_len2pt(css_fixed length, css_unit unit);
+css_fixed nscss_len2pt(
+ const nscss_len_ctx *ctx,
+ css_fixed length,
+ css_unit unit);
/**
* 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
+ * \param[in] ctx Length conversion context.
+ * \param[in] length Length to convert.
+ * \param[in] unit Corresponding unit.
+ * \param[in] style Computed style applying to length.
+ * May be NULL if unit is not em, ex, cap, ch, or ic.
* \return length in pixels
*/
-css_fixed nscss_len2px(css_fixed length, css_unit unit, const css_computed_style *style);
+css_fixed nscss_len2px(
+ const nscss_len_ctx *ctx,
+ css_fixed length,
+ css_unit unit,
+ const css_computed_style *style);
/**
diff --git a/content/handlers/html/Makefile b/content/handlers/html/Makefile
new file mode 100644
index 0000000..afefba2
--- /dev/null
+++ b/content/handlers/html/Makefile
@@ -0,0 +1,7 @@
+# HTML content handler sources
+
+S_HTML := box.c box_construct.c box_normalise.c box_textarea.c \
+ font.c form.c imagemap.c layout.c search.c table.c \
+ html.c html_css.c html_css_fetcher.c html_script.c \
+ html_interaction.c html_redraw.c html_redraw_border.c \
+ html_forms.c html_object.c
diff --git a/render/box.c b/content/handlers/html/box.c
similarity index 95%
rename from render/box.c
rename to content/handlers/html/box.c
index 8b9c89e..52cf124 100644
--- a/render/box.c
+++ b/content/handlers/html/box.c
@@ -41,9 +41,9 @@
#include "desktop/scrollbar.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
+#include "html/box.h"
+#include "html/form_internal.h"
+#include "html/html_internal.h"
#define box_is_float(box) (box->type == BOX_FLOAT_LEFT || \
box->type == BOX_FLOAT_RIGHT)
@@ -62,7 +62,7 @@ static int box_talloc_destructor(struct box *b)
css_computed_style_destroy(b->style);
b->style = NULL;
}
-
+
if (b->styles != NULL) {
css_select_results_destroy(b->styles);
b->styles = NULL;
@@ -112,7 +112,7 @@ static int box_talloc_destructor(struct box *b)
*/
struct box * box_create(css_select_results *styles, css_computed_style *style,
- bool style_owned, nsurl *href, const char *target,
+ bool style_owned, nsurl *href, const char *target,
const char *title, lwc_string *id, void *context)
{
unsigned int i;
@@ -342,20 +342,27 @@ void box_bounds(struct box *box, struct rect *r)
/**
* Determine if a point lies within a box.
*
- * \param box box to consider
- * \param x coordinate relative to box
- * \param y coordinate relative to box
- * \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.
+ * \param[in] len_ctx CSS length conversion context to use.
+ * \param[in] box Box to consider
+ * \param[in] x Coordinate relative to box
+ * \param[in] y Coordinate relative to box
+ * \param[out] physically If function returning true, physically is set true
+ * iff 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 returns 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().
*/
-static bool box_contains_point(struct box *box, int x, int y, bool *physically)
+static bool box_contains_point(
+ const nscss_len_ctx *len_ctx,
+ const struct box *box,
+ int x,
+ int y,
+ bool *physically)
{
css_computed_clip_rect css_rect;
@@ -382,25 +389,25 @@ static bool box_contains_point(struct box *box, int x, int y, bool *physically)
/* Adjust rect to css clip region */
if (css_rect.left_auto == false) {
- r.x0 += FIXTOINT(nscss_len2px(
+ r.x0 += FIXTOINT(nscss_len2px(len_ctx,
css_rect.left, css_rect.lunit,
box->style));
}
if (css_rect.top_auto == false) {
- r.y0 += FIXTOINT(nscss_len2px(
+ r.y0 += FIXTOINT(nscss_len2px(len_ctx,
css_rect.top, css_rect.tunit,
box->style));
}
if (css_rect.right_auto == false) {
r.x1 = box->border[LEFT].width +
- FIXTOINT(nscss_len2px(
+ FIXTOINT(nscss_len2px(len_ctx,
css_rect.right,
css_rect.runit,
box->style));
}
if (css_rect.bottom_auto == false) {
r.y1 = box->border[TOP].width +
- FIXTOINT(nscss_len2px(
+ FIXTOINT(nscss_len2px(len_ctx,
css_rect.bottom,
css_rect.bunit,
box->style));
@@ -441,7 +448,7 @@ static bool box_contains_point(struct box *box, int x, int y, bool *physically)
*physically = true;
return true;
}
- if ((box->style && css_computed_overflow_x(box->style) ==
+ if ((box->style && css_computed_overflow_x(box->style) ==
CSS_OVERFLOW_VISIBLE) || !box->style) {
if (box->descendant_x0 <= x &&
x < box->descendant_x1) {
@@ -449,7 +456,7 @@ static bool box_contains_point(struct box *box, int x, int y, bool *physically)
return true;
}
}
- if ((box->style && css_computed_overflow_y(box->style) ==
+ if ((box->style && css_computed_overflow_y(box->style) ==
CSS_OVERFLOW_VISIBLE) || !box->style) {
if (box->descendant_y0 <= y &&
y < box->descendant_y1) {
@@ -659,6 +666,7 @@ skip_children:
/**
* Find the boxes at a point.
*
+ * \param len_ctx CSS length conversion context for document.
* \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
@@ -674,13 +682,14 @@ skip_children:
* 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))) {
+ * while ((box = box_at_point(len_ctx, box, x, y, &box_x, &box_y))) {
* // process box
* }
* \endcode
*/
-struct box *box_at_point(struct box *box, const int x, const int y,
+struct box *box_at_point(const nscss_len_ctx *len_ctx,
+ struct box *box, const int x, const int y,
int *box_x, int *box_y)
{
bool skip_children;
@@ -690,7 +699,7 @@ struct box *box_at_point(struct box *box, const int x, const int y,
skip_children = false;
while ((box = box_next_xy(box, box_x, box_y, skip_children))) {
- if (box_contains_point(box, x - *box_x, y - *box_y,
+ if (box_contains_point(len_ctx, box, x - *box_x, y - *box_y,
&physically)) {
*box_x -= scrollbar_get_offset(box->scroll_x);
*box_y -= scrollbar_get_offset(box->scroll_y);
@@ -972,7 +981,7 @@ struct box *box_find_by_id(struct box *box, lwc_string *id)
bool box_visible(struct box *box)
{
/* visibility: hidden */
- if (box->style && css_computed_visibility(box->style) ==
+ if (box->style && css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)
return false;
@@ -1031,7 +1040,7 @@ void box_dump(FILE *stream, struct box *box, unsigned int depth, bool style)
if (box->space)
fprintf(stream, "space ");
if (box->object) {
- fprintf(stream, "(object '%s') ",
+ fprintf(stream, "(object '%s') ",
nsurl_access(hlcache_handle_get_url(box->object)));
}
if (box->iframe) {
@@ -1197,10 +1206,10 @@ bool box_handle_scrollbars(struct content *c, struct box *box,
visible_width, full_width);
}
}
-
+
if (right && bottom)
scrollbar_make_pair(box->scroll_x, box->scroll_y);
-
+
return true;
}
@@ -1230,4 +1239,3 @@ 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;
}
-
diff --git a/render/box.h b/content/handlers/html/box.h
similarity index 95%
rename from render/box.h
rename to content/handlers/html/box.h
index 2800d40..0952b84 100644
--- a/render/box.h
+++ b/content/handlers/html/box.h
@@ -17,7 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Box tree construction and manipulation (interface).
*
* This stage of rendering converts a tree of dom_nodes (produced by libdom)
@@ -83,14 +84,16 @@
* \endcode
*/
-#ifndef _NETSURF_RENDER_BOX_H_
-#define _NETSURF_RENDER_BOX_H_
+#ifndef NETSURF_HTML_BOX_H
+#define NETSURF_HTML_BOX_H
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <libcss/libcss.h>
+#include "content/handlers/css/utils.h"
+
struct content;
struct box;
struct browser_window;
@@ -319,7 +322,7 @@ extern const char *TARGET_BLANK;
struct box * box_create(css_select_results *styles, css_computed_style *style,
- bool style_owned, struct nsurl *href, const char *target,
+ bool style_owned, struct 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);
@@ -328,7 +331,9 @@ 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,
+struct box *box_at_point(
+ const nscss_len_ctx *len_ctx,
+ struct box *box, const int x, const int y,
int *box_x, int *box_y);
struct box *box_pick_text_box(struct html_content *html,
int x, int y, int dir, int *dx, int *dy);
@@ -356,6 +361,20 @@ bool box_hscrollbar_present(const struct box *box);
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);
+bool box_normalise_block(
+ struct box *block,
+ const struct box *root,
+ struct html_content *c);
+
+/**
+ * Check if layout box is a first child.
+ *
+ * \param[in] b Box to check.
+ * \return true iff box is first child.
+ */
+static inline bool box_is_first_child(struct box *b)
+{
+ return (b->parent == NULL || b == b->parent->children);
+}
#endif
diff --git a/render/box_construct.c b/content/handlers/html/box_construct.c
similarity index 98%
rename from render/box_construct.c
rename to content/handlers/html/box_construct.c
index 1982622..5650fbf 100644
--- a/render/box_construct.c
+++ b/content/handlers/html/box_construct.c
@@ -49,10 +49,11 @@
#include "css/utils.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/box_textarea.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
+#include "html/html.h"
+#include "html/box.h"
+#include "html/box_textarea.h"
+#include "html/form_internal.h"
+#include "html/html_internal.h"
/**
* Context for box tree construction
@@ -104,7 +105,8 @@ static bool box_construct_element(struct box_construct_ctx *ctx,
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);
+ const css_computed_style *parent_style,
+ const css_computed_style *root_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, \
@@ -429,7 +431,8 @@ void convert_xml_to_box(struct box_construct_ctx *ctx)
root.children->parent = &root;
/** \todo Remove box_normalise_block */
- if (box_normalise_block(&root, ctx->content) == false) {
+ if (box_normalise_block(&root, ctx->root_box,
+ ctx->content) == false) {
ctx->cb(ctx->content, false);
} else {
ctx->content->layout = root.children;
@@ -741,6 +744,7 @@ bool box_construct_element(struct box_construct_ctx *ctx,
lwc_string *bgimage_uri;
dom_exception err;
struct box_construct_props props;
+ const css_computed_style *root_style = NULL;
assert(ctx->n != NULL);
@@ -748,12 +752,17 @@ bool box_construct_element(struct box_construct_ctx *ctx,
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 */
+ * 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 (props.node_is_root == false) {
+ root_style = ctx->root_box->style;
+ }
+
+ styles = box_get_style(ctx->content, props.parent_style, root_style,
+ ctx->n);
if (styles == NULL)
return false;
@@ -1321,13 +1330,15 @@ bool box_construct_text(struct box_construct_ctx *ctx)
/**
* Get the style for an element.
*
- * \param c content of type CONTENT_HTML that is being processed
+ * \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
+ * \param root_style root node's style, 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)
+ const css_computed_style *parent_style,
+ const css_computed_style *root_style, dom_node *n)
{
dom_string *s;
dom_exception err;
@@ -1359,6 +1370,7 @@ css_select_results *box_get_style(html_content *c,
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
+ ctx.root_style = root_style;
ctx.parent_style = parent_style;
/* Select style for element */
@@ -2057,9 +2069,9 @@ bool box_create_frameset(struct content_html_frames *f, dom_node *n,
/* common extension: frameborder="yes|no" to control all children */
err = dom_element_get_attribute(n, corestring_dom_frameborder, &s);
if (err == DOM_NO_ERR && s != NULL) {
- if (dom_string_caseless_lwc_isequal(s,
- corestring_lwc_no) == 0)
- default_border = false;
+ if (dom_string_caseless_lwc_isequal(s,
+ corestring_lwc_no) == 0)
+ default_border = false;
dom_string_unref(s);
}
@@ -2203,8 +2215,8 @@ bool box_create_frameset(struct content_html_frames *f, dom_node *n,
/* copy url */
if (url != NULL) {
- /* no self-references */
- if (nsurl_compare(content->base_url, url,
+ /* no self-references */
+ if (nsurl_compare(content->base_url, url,
NSURL_COMPLETE) == false)
frame->url = url;
url = NULL;
@@ -3053,7 +3065,7 @@ bool box_get_attribute(dom_node *n, const char *attribute,
}
-/* exported function documented in render/box.h */
+/* exported function documented in html/box.h */
bool
box_extract_link(const html_content *content,
const dom_string *dsrel,
@@ -3121,6 +3133,3 @@ box_extract_link(const html_content *content,
return true;
}
-
-
-
diff --git a/render/box_normalise.c b/content/handlers/html/box_normalise.c
similarity index 89%
rename from render/box_normalise.c
rename to content/handlers/html/box_normalise.c
index 9f78f75..7155cb7 100644
--- a/render/box_normalise.c
+++ b/content/handlers/html/box_normalise.c
@@ -19,7 +19,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Box tree normalisation (implementation).
*/
@@ -31,9 +32,9 @@
#include "utils/errors.h"
#include "css/select.h"
-#include "render/box.h"
-#include "render/html_internal.h"
-#include "render/table.h"
+#include "html/box.h"
+#include "html/html_internal.h"
+#include "html/table.h"
/* Define to enable box normalise debug */
#undef BOX_NORMALISE_DEBUG
@@ -65,24 +66,38 @@ struct columns {
};
-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,
+static bool box_normalise_table(
+ struct box *table,
+ const struct box *root,
+ html_content *c);
+static bool box_normalise_table_spans(
+ struct box *table,
+ const struct box *root,
+ struct span_info *spans,
+ html_content *c);
+static bool box_normalise_table_row_group(
+ struct box *row_group,
+ const struct box *root,
struct columns *col_info,
html_content *c);
-static bool box_normalise_table_row(struct box *row,
+static bool box_normalise_table_row(
+ struct box *row,
+ const struct box *root,
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, struct box *cell);
-static bool box_normalise_inline_container(struct box *cont, html_content *c);
+static bool box_normalise_inline_container(
+ struct box *cont,
+ const struct box *root,
+ 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 root root box of document
* \param c content of boxes
* \return true on success, false on memory exhaustion
*
@@ -100,7 +115,10 @@ static bool box_normalise_inline_container(struct box *cont, html_content *c);
* \endcode
*/
-bool box_normalise_block(struct box *block, html_content *c)
+bool box_normalise_block(
+ struct box *block,
+ const struct box *root,
+ html_content *c)
{
struct box *child;
struct box *next_child;
@@ -109,6 +127,9 @@ bool box_normalise_block(struct box *block, html_content *c)
nscss_select_ctx ctx;
assert(block != NULL);
+ assert(root != NULL);
+
+ ctx.root_style = root->style;
#ifdef BOX_NORMALISE_DEBUG
NSLOG(netsurf, INFO, "block %p, block->type %u", block, block->type);
@@ -128,15 +149,15 @@ bool box_normalise_block(struct box *block, html_content *c)
switch (child->type) {
case BOX_BLOCK:
/* ok */
- if (box_normalise_block(child, c) == false)
+ if (box_normalise_block(child, root, c) == false)
return false;
break;
case BOX_INLINE_CONTAINER:
- if (box_normalise_inline_container(child, c) == false)
+ if (box_normalise_inline_container(child, root, c) == false)
return false;
break;
case BOX_TABLE:
- if (box_normalise_table(child, c) == false)
+ if (box_normalise_table(child, root, c) == false)
return false;
break;
case BOX_INLINE:
@@ -199,7 +220,7 @@ bool box_normalise_block(struct box *block, html_content *c)
block->last = table;
table->parent = block;
- if (box_normalise_table(table, c) == false)
+ if (box_normalise_table(table, root, c) == false)
return false;
break;
default:
@@ -211,7 +232,10 @@ bool box_normalise_block(struct box *block, html_content *c)
}
-bool box_normalise_table(struct box *table, html_content * c)
+bool box_normalise_table(
+ struct box *table,
+ const struct box *root,
+ html_content * c)
{
struct box *child;
struct box *next_child;
@@ -223,6 +247,8 @@ bool box_normalise_table(struct box *table, html_content * c)
assert(table != NULL);
assert(table->type == BOX_TABLE);
+ ctx.root_style = root->style;
+
#ifdef BOX_NORMALISE_DEBUG
NSLOG(netsurf, INFO, "table %p", table);
#endif
@@ -243,7 +269,7 @@ bool box_normalise_table(struct box *table, html_content * c)
switch (child->type) {
case BOX_TABLE_ROW_GROUP:
/* ok */
- if (box_normalise_table_row_group(child,
+ if (box_normalise_table_row_group(child, root,
&col_info, c) == false) {
free(col_info.spans);
return false;
@@ -308,7 +334,7 @@ bool box_normalise_table(struct box *table, html_content * c)
table->last = row_group;
row_group->parent = table;
- if (box_normalise_table_row_group(row_group,
+ if (box_normalise_table_row_group(row_group, root,
&col_info, c) == false) {
free(col_info.spans);
return false;
@@ -390,16 +416,13 @@ bool box_normalise_table(struct box *table, html_content * c)
table->rows = 1;
}
- if (box_normalise_table_spans(table, col_info.spans, c) == false) {
+ if (box_normalise_table_spans(table, root, 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
NSLOG(netsurf, INFO, "table %p done", table);
#endif
@@ -413,12 +436,16 @@ bool box_normalise_table(struct box *table, html_content * c)
* Additionally, generate empty cells.
*
* \param table Table to process
+ * \param root root box of document
* \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,
+bool box_normalise_table_spans(
+ struct box *table,
+ const struct box *root,
+ struct span_info *spans,
html_content *c)
{
struct box *table_row_group;
@@ -429,10 +456,12 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
unsigned int col;
nscss_select_ctx ctx;
+ ctx.root_style = root->style;
+
/* Clear span data */
memset(spans, 0, table->columns * sizeof(struct span_info));
- /* Scan table, filling in width and height of table cells with
+ /* 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;
@@ -481,34 +510,34 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
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.
+ /* 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 ==
+ spans[col].row_span ==
0) {
col++;
}
ctx.ctx = c->select_ctx;
- ctx.quirks = (c->quirks ==
+ 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,
+ style = nscss_get_blank_style(&ctx,
table_row->style);
if (style == NULL)
return false;
- cell = box_create(NULL, style, true,
- table_row->href,
- table_row->target,
+ cell = box_create(NULL, style, true,
+ table_row->href,
+ table_row->target,
NULL, NULL, c->bctx);
if (cell == NULL) {
css_computed_style_destroy(
@@ -525,8 +554,8 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
for (prev = table_row->children;
prev != NULL;
prev = prev->next) {
- if (prev->start_column +
- prev->columns ==
+ if (prev->start_column +
+ prev->columns ==
start)
break;
if (prev->next == NULL)
@@ -541,7 +570,7 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
else
table_row->last = cell;
- cell->next =
+ cell->next =
table_row->children;
table_row->children = cell;
} else {
@@ -572,7 +601,9 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
}
-bool box_normalise_table_row_group(struct box *row_group,
+bool box_normalise_table_row_group(
+ struct box *row_group,
+ const struct box *root,
struct columns *col_info,
html_content * c)
{
@@ -586,6 +617,8 @@ bool box_normalise_table_row_group(struct box *row_group,
assert(row_group != 0);
assert(row_group->type == BOX_TABLE_ROW_GROUP);
+ ctx.root_style = root->style;
+
#ifdef BOX_NORMALISE_DEBUG
NSLOG(netsurf, INFO, "row_group %p", row_group);
#endif
@@ -597,7 +630,7 @@ bool box_normalise_table_row_group(struct box *row_group,
case BOX_TABLE_ROW:
/* ok */
group_row_count++;
- if (box_normalise_table_row(child, col_info,
+ if (box_normalise_table_row(child, root, col_info,
c) == false)
return false;
break;
@@ -657,7 +690,7 @@ bool box_normalise_table_row_group(struct box *row_group,
row->parent = row_group;
group_row_count++;
- if (box_normalise_table_row(row, col_info,
+ if (box_normalise_table_row(row, root, col_info,
c) == false)
return false;
break;
@@ -722,7 +755,9 @@ bool box_normalise_table_row_group(struct box *row_group,
}
-bool box_normalise_table_row(struct box *row,
+bool box_normalise_table_row(
+ struct box *row,
+ const struct box *root,
struct columns *col_info,
html_content * c)
{
@@ -736,6 +771,8 @@ bool box_normalise_table_row(struct box *row,
assert(row != NULL);
assert(row->type == BOX_TABLE_ROW);
+ ctx.root_style = root->style;
+
#ifdef BOX_NORMALISE_DEBUG
NSLOG(netsurf, INFO, "row %p", row);
#endif
@@ -746,7 +783,7 @@ bool box_normalise_table_row(struct box *row,
switch (child->type) {
case BOX_TABLE_CELL:
/* ok */
- if (box_normalise_block(child, c) == false)
+ if (box_normalise_block(child, root, c) == false)
return false;
cell = child;
break;
@@ -805,7 +842,7 @@ bool box_normalise_table_row(struct box *row,
row->last = cell;
cell->parent = row;
- if (box_normalise_block(cell, c) == false)
+ if (box_normalise_block(cell, root, c) == false)
return false;
break;
case BOX_INLINE:
@@ -831,7 +868,7 @@ bool box_normalise_table_row(struct box *row,
/* Update row spanning details for all columns */
for (i = 0; i < col_info->num_columns; i++) {
- if (col_info->spans[i].row_span != 0 &&
+ 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 */
@@ -890,12 +927,12 @@ bool calculate_table_row(struct columns *col_info,
* 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.
+ * the maximum recorded for the table so far.
* Allocate more span records. */
spans = realloc(col_info->spans,
sizeof *spans * (cell_end_col + 1));
@@ -910,7 +947,7 @@ bool calculate_table_row(struct columns *col_info,
col_info->spans[cell_end_col].auto_row = false;
}
- /* This cell may span multiple columns. If it also wants to span
+ /* 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++) {
@@ -928,7 +965,10 @@ bool calculate_table_row(struct columns *col_info,
}
-bool box_normalise_inline_container(struct box *cont, html_content * c)
+bool box_normalise_inline_container(
+ struct box *cont,
+ const struct box *root,
+ html_content * c)
{
struct box *child;
struct box *next_child;
@@ -951,7 +991,7 @@ bool box_normalise_inline_container(struct box *cont, html_content * c)
break;
case BOX_INLINE_BLOCK:
/* ok */
- if (box_normalise_block(child, c) == false)
+ if (box_normalise_block(child, root, c) == false)
return false;
break;
case BOX_FLOAT_LEFT:
@@ -961,12 +1001,12 @@ bool box_normalise_inline_container(struct box *cont, html_content * c)
switch (child->children->type) {
case BOX_BLOCK:
- if (box_normalise_block(child->children,
+ if (box_normalise_block(child->children, root,
c) == false)
return false;
break;
case BOX_TABLE:
- if (box_normalise_table(child->children,
+ if (box_normalise_table(child->children, root,
c) == false)
return false;
break;
diff --git a/render/box_textarea.c b/content/handlers/html/box_textarea.c
similarity index 96%
rename from render/box_textarea.c
rename to content/handlers/html/box_textarea.c
index 3b1e775..c19afbb 100644
--- a/render/box_textarea.c
+++ b/content/handlers/html/box_textarea.c
@@ -16,7 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Box tree treeview box replacement (implementation).
*/
@@ -27,9 +28,11 @@
#include "netsurf/keypress.h"
#include "desktop/textarea.h"
-#include "render/box_textarea.h"
-#include "render/font.h"
-#include "render/form_internal.h"
+#include "html/html_internal.h"
+#include "html/box.h"
+#include "html/box_textarea.h"
+#include "html/font.h"
+#include "html/form_internal.h"
bool box_textarea_keypress(html_content *html, struct box *box, uint32_t key)
@@ -239,7 +242,14 @@ bool box_textarea_create_textarea(html_content *html,
dom_exception err;
textarea_setup ta_setup;
textarea_flags ta_flags;
- plot_font_style_t fstyle;
+ plot_font_style_t fstyle = {
+ .family = PLOT_FONT_FAMILY_SANS_SERIF,
+ .size = 10 * PLOT_STYLE_SCALE,
+ .weight = 400,
+ .flags = FONTF_NONE,
+ .background = 0,
+ .foreground = 0,
+ };
bool read_only = false;
bool disabled = false;
struct form_control *gadget = box->gadget;
@@ -307,8 +317,6 @@ bool box_textarea_create_textarea(html_content *html,
gadget->data.text.data.gadget = gadget;
- font_plot_style_from_css(gadget->box->style, &fstyle);
-
/* Reset to correct values by layout */
ta_setup.width = 200;
ta_setup.height = 20;
@@ -342,4 +350,3 @@ bool box_textarea_create_textarea(html_content *html,
return true;
}
-
diff --git a/render/box_textarea.h b/content/handlers/html/box_textarea.h
similarity index 81%
rename from render/box_textarea.h
rename to content/handlers/html/box_textarea.h
index a7a3770..822fc8b 100644
--- a/render/box_textarea.h
+++ b/content/handlers/html/box_textarea.h
@@ -16,20 +16,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Box tree treeview box replacement (interface).
*/
-
-
-#ifndef _NETSURF_RENDER_BOX_TEXTAREA_H_
-#define _NETSURF_RENDER_BOX_TEXTAREA_H_
-
-
-#include "render/box.h"
-#include "render/html_internal.h"
+#ifndef NETSURF_HTML_BOX_TEXTAREA_H
+#define NETSURF_HTML_BOX_TEXTAREA_H
struct dom_node;
+struct html_content;
+struct box;
/**
* Create textarea widget for a form element
@@ -38,7 +35,7 @@ struct dom_node;
* \param box box with gadget to be given textarea widget
* \param node DOM node for form element
*/
-bool box_textarea_create_textarea(html_content *html,
+bool box_textarea_create_textarea(struct html_content *html,
struct box *box, struct dom_node *node);
@@ -50,6 +47,6 @@ bool box_textarea_create_textarea(html_content *html,
* \param key keypress
* \return true iff keypress handled
*/
-bool box_textarea_keypress(html_content *html, struct box *box, uint32_t key);
+bool box_textarea_keypress(struct html_content *html, struct box *box, uint32_t key);
#endif
diff --git a/render/font.c b/content/handlers/html/font.c
similarity index 84%
rename from render/font.c
rename to content/handlers/html/font.c
index 94ef877..7ebe168 100644
--- a/render/font.c
+++ b/content/handlers/html/font.c
@@ -19,23 +19,23 @@
/**
* \file
*
- * Renderer internal font handling implementation.
+ * HTML internal font handling implementation.
*/
#include "utils/nsoption.h"
#include "netsurf/plot_style.h"
#include "css/utils.h"
-#include "render/font.h"
+#include "html/font.h"
/**
* Map a generic CSS font family to a generic plot font family
*
- * \param css Generic CSS font family
+ * \param css Generic CSS font family
* \return Plot font family
*/
-static plot_font_generic_family_t plot_font_generic_family(
- enum css_font_family_e css)
+static plot_font_generic_family_t
+plot_font_generic_family(enum css_font_family_e css)
{
plot_font_generic_family_t plot;
@@ -131,8 +131,10 @@ static plot_font_flags_t plot_font_flags(enum css_font_style_e style,
}
-/* exported function documented in render/font_internal.h */
-void font_plot_style_from_css(const css_computed_style *css,
+/* exported function documented in html/font.h */
+void font_plot_style_from_css(
+ const nscss_len_ctx *len_ctx,
+ const css_computed_style *css,
plot_font_style_t *fstyle)
{
lwc_string **families;
@@ -142,14 +144,15 @@ void font_plot_style_from_css(const css_computed_style *css,
fstyle->family = plot_font_generic_family(
css_computed_font_family(css, &families));
+ fstyle->families = families;
css_computed_font_size(css, &length, &unit);
- fstyle->size = FIXTOINT(FMUL(nscss_len2pt(length, unit),
- INTTOFIX(FONT_SIZE_SCALE)));
+ fstyle->size = FIXTOINT(FMUL(nscss_len2pt(len_ctx, length, unit),
+ INTTOFIX(PLOT_STYLE_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;
+ if (fstyle->size < (nsoption_int(font_min_size) * PLOT_STYLE_SCALE) / 10)
+ fstyle->size = (nsoption_int(font_min_size) * PLOT_STYLE_SCALE) / 10;
fstyle->weight = plot_font_weight(css_computed_font_weight(css));
fstyle->flags = plot_font_flags(css_computed_font_style(css),
diff --git a/render/font.h b/content/handlers/html/font.h
similarity index 77%
rename from render/font.h
rename to content/handlers/html/font.h
index fba368a..5f69ee7 100644
--- a/render/font.h
+++ b/content/handlers/html/font.h
@@ -16,26 +16,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- *
+/**
+ * \file
* Internal font handling interfaces.
*
* These functions provide font related services. They all work on
* UTF-8 strings with lengths given.
*/
-#ifndef _NETSURF_RENDER_FONT_H_
-#define _NETSURF_RENDER_FONT_H_
+#ifndef NETSURF_HTML_FONT_H
+#define NETSURF_HTML_FONT_H
struct plot_font_style;
/**
* Populate a font style using data from a computed CSS style
*
- * \param css Computed style to consider
- * \param fstyle Font style to populate
+ * \param len_ctx Length conversion context
+ * \param css Computed style to consider
+ * \param fstyle Font style to populate
*/
-void font_plot_style_from_css(const css_computed_style *css,
+void font_plot_style_from_css(const nscss_len_ctx *len_ctx,
+ const css_computed_style *css,
struct plot_font_style *fstyle);
#endif
diff --git a/render/form.c b/content/handlers/html/form.c
similarity index 97%
rename from render/form.c
rename to content/handlers/html/form.c
index 904272d..4a9d710 100644
--- a/render/form.c
+++ b/content/handlers/html/form.c
@@ -52,12 +52,12 @@
#include "desktop/textarea.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/font.h"
-#include "render/form_internal.h"
-#include "render/html.h"
-#include "render/html_internal.h"
-#include "render/layout.h"
+#include "html/box.h"
+#include "html/font.h"
+#include "html/form_internal.h"
+#include "html/html.h"
+#include "html/html_internal.h"
+#include "html/layout.h"
#define MAX_SELECT_HEIGHT 210
#define SELECT_LINE_SPACING 0.2
@@ -96,9 +96,9 @@ static void form_select_menu_clicked(struct form_control *control,
static void form_select_menu_scroll_callback(void *client_data,
struct scrollbar_msg_data *scrollbar_data);
-/* exported interface documented in render/form_internal.h */
-struct form *form_new(void *node, const char *action, const char *target,
- form_method method, const char *charset,
+/* exported interface documented in html/form_internal.h */
+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;
@@ -146,7 +146,7 @@ struct form *form_new(void *node, const char *action, const char *target,
}
-/* exported interface documented in render/form_internal.h */
+/* exported interface documented in html/form_internal.h */
void form_free(struct form *form)
{
struct form_control *c, *d;
@@ -165,7 +165,7 @@ void form_free(struct form *form)
free(form);
}
-/* exported interface documented in render/form_internal.h */
+/* exported interface documented in html/form_internal.h */
struct form_control *form_new_control(void *node, form_control_type type)
{
struct form_control *control;
@@ -327,7 +327,7 @@ bool form_add_option(struct form_control *control, char *value, char *text,
}
-/* exported interface documented in render/form_internal.h */
+/* exported interface documented in html/form_internal.h */
bool form_successful_controls_dom(struct form *_form,
struct form_control *_submit_button,
struct fetch_multipart_data **successful_controls)
@@ -347,7 +347,7 @@ bool form_successful_controls_dom(struct form *_form,
last_success = &sentinel;
sentinel.next = NULL;
-
+
/** \todo Replace this call with something DOMish */
charset = form_acceptable_charset(_form);
if (charset == NULL) {
@@ -361,22 +361,22 @@ bool form_successful_controls_dom(struct form *_form,
form_encode_item(dom_string_data(i), dom_string_byte_length(i), \
charset, _form->document_charset) \
))
-
+
err = dom_html_form_element_get_elements(form, &form_elements);
-
+
if (err != DOM_NO_ERR) {
NSLOG(netsurf, INFO, "Could not get form elements");
goto dom_no_memory;
}
-
-
+
+
err = dom_html_collection_get_length(form_elements, &element_count);
-
+
if (err != DOM_NO_ERR) {
NSLOG(netsurf, INFO, "Could not get form element count");
goto dom_no_memory;
}
-
+
for (index = 0; index < element_count; index++) {
if (form_element != NULL) {
dom_node_unref(form_element);
@@ -501,7 +501,7 @@ bool form_successful_controls_dom(struct form *_form,
continue;
if (inputname == NULL)
continue;
-
+
if (dom_string_isequal(nodename, corestring_dom_TEXTAREA)) {
err = dom_html_text_area_element_get_value(
(dom_html_text_area_element *)form_element,
@@ -565,17 +565,17 @@ bool form_successful_controls_dom(struct form *_form,
"Could not get option value");
goto dom_no_memory;
}
-
+
success_new = calloc(1, sizeof(*success_new));
if (success_new == NULL) {
NSLOG(netsurf, INFO,
"Could not allocate data for option");
goto dom_no_memory;
}
-
+
last_success->next = success_new;
last_success = success_new;
-
+
success_new->name = ENCODE_ITEM(inputname);
if (success_new->name == NULL) {
NSLOG(netsurf, INFO,
@@ -668,7 +668,7 @@ bool form_successful_controls_dom(struct form *_form,
if ((dom_node *)submit_button !=
(dom_node *)form_element)
continue;
-
+
err = dom_node_get_user_data(
form_element,
corestring_dom___ns_key_image_coords_node_data,
@@ -683,9 +683,9 @@ bool form_successful_controls_dom(struct form *_form,
"No XY data on the image input");
goto dom_no_memory;
}
-
+
basename = ENCODE_ITEM(inputname);
-
+
success_new = calloc(1, sizeof(*success_new));
if (success_new == NULL) {
free(basename);
@@ -693,10 +693,10 @@ bool form_successful_controls_dom(struct form *_form,
"Could not allocate data for image.x");
goto dom_no_memory;
}
-
+
last_success->next = success_new;
last_success = success_new;
-
+
success_new->name = malloc(strlen(basename) + 3);
if (success_new->name == NULL) {
free(basename);
@@ -713,7 +713,7 @@ bool form_successful_controls_dom(struct form *_form,
}
sprintf(success_new->name, "%s.x", basename);
sprintf(success_new->value, "%d", coords->x);
-
+
success_new = calloc(1, sizeof(*success_new));
if (success_new == NULL) {
free(basename);
@@ -721,10 +721,10 @@ bool form_successful_controls_dom(struct form *_form,
"Could not allocate data for image.y");
goto dom_no_memory;
}
-
+
last_success->next = success_new;
last_success = success_new;
-
+
success_new->name = malloc(strlen(basename) + 3);
if (success_new->name == NULL) {
free(basename);
@@ -820,17 +820,17 @@ bool form_successful_controls_dom(struct form *_form,
/* Fall out to the allocation */
}
}
-
+
success_new = calloc(1, sizeof(*success_new));
if (success_new == NULL) {
NSLOG(netsurf, INFO,
"Could not allocate data for generic");
goto dom_no_memory;
}
-
+
last_success->next = success_new;
last_success = success_new;
-
+
success_new->name = ENCODE_ITEM(inputname);
if (success_new->name == NULL) {
NSLOG(netsurf, INFO,
@@ -849,7 +849,7 @@ bool form_successful_controls_dom(struct form *_form,
rawfile_temp = NULL;
}
}
-
+
free(charset);
if (form_element != NULL) {
@@ -889,13 +889,13 @@ bool form_successful_controls_dom(struct form *_form,
}
*successful_controls = sentinel.next;
-
+
return true;
-
+
dom_no_memory:
free(charset);
fetch_multipart_data_destroy(sentinel.next);
-
+
if (form_elements != NULL)
dom_html_collection_unref(form_elements);
if (form_element != NULL)
@@ -914,7 +914,7 @@ dom_no_memory:
dom_string_unref(inputtype);
if (rawfile_temp != NULL)
free(rawfile_temp);
-
+
return false;
}
#undef ENCODE_ITEM
@@ -972,6 +972,9 @@ static char *form_url_encode(struct form *form,
assert(url_err == NSERROR_OK);
+ /* resize string to allow for new key/value pair,
+ * equals, amphersand and terminator
+ */
len1 = len + strlen(name) + strlen(value) + 2;
s2 = realloc(s, len1 + 1);
if (!s2) {
@@ -981,7 +984,8 @@ static char *form_url_encode(struct form *form,
return NULL;
}
s = s2;
- sprintf(s + len, "%s=%s&", name, value);
+
+ snprintf(s + len, (len1 + 1) - len, "%s=%s&", name, value);
len = len1;
free(name);
free(value);
@@ -1091,7 +1095,7 @@ char *form_encode_item(const char *item, uint32_t len, const char *charset,
if (err == NSERROR_BAD_ENCODING) {
/* nope, try fallback charset (if any) */
if (fallback) {
- snprintf(cset, sizeof cset,
+ snprintf(cset, sizeof cset,
"%s//TRANSLIT", fallback);
err = utf8_to_enc(item, cset, 0, &ret);
@@ -1122,7 +1126,7 @@ char *form_encode_item(const char *item, uint32_t len, const char *charset,
return ret;
}
-/* exported interface documented in render/form_internal.h */
+/* exported interface documented in html/form_internal.h */
bool form_open_select_menu(void *client_data,
struct form_control *control,
select_menu_redraw_callback callback,
@@ -1133,6 +1137,7 @@ bool form_open_select_menu(void *client_data,
plot_font_style_t fstyle;
int total_height;
struct form_select_menu *menu;
+ html_content *html = (html_content *)c;
/* if the menu is opened for the first time */
@@ -1153,13 +1158,13 @@ bool form_open_select_menu(void *client_data,
box->border[LEFT].width +
box->padding[RIGHT] + box->padding[LEFT];
- font_plot_style_from_css(control->box->style,
+ font_plot_style_from_css(&html->len_ctx, 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)))),
+ INTTOFIX(fstyle.size / PLOT_STYLE_SCALE)))),
F_72));
line_height_with_spacing = menu->line_height +
@@ -1178,7 +1183,7 @@ bool form_open_select_menu(void *client_data,
menu->callback = callback;
if (scrollbar_create(false,
menu->height,
- total_height,
+ total_height,
menu->height,
control,
form_select_menu_scroll_callback,
@@ -1196,7 +1201,7 @@ bool form_open_select_menu(void *client_data,
}
-/* exported interface documented in render/form_internal.h */
+/* exported interface documented in html/form_internal.h */
void form_free_select_menu(struct form_control *control)
{
if (control->data.select.menu->scrollbar != NULL)
@@ -1206,7 +1211,7 @@ void form_free_select_menu(struct form_control *control)
}
-/* exported interface documented in render/form_internal.h */
+/* exported interface documented in html/form_internal.h */
bool form_redraw_select_menu(struct form_control *control, int x, int y,
float scale, const struct rect *clip,
const struct redraw_context *ctx)
@@ -1228,24 +1233,24 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y,
nserror res;
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;
@@ -1253,8 +1258,8 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y,
scroll *= scale;
scroll += i * line_height_with_spacing;
}
-
-
+
+
x0 = x;
y0 = y;
x1 = x + width - 1;
@@ -1301,7 +1306,7 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y,
option = control->data.select.items;
item_y = line_height_with_spacing;
-
+
while (item_y < scroll) {
option = option->next;
item_y += line_height_with_spacing;
@@ -1310,14 +1315,14 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y,
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 (option->selected) {
+ y2 = y + item_y - scroll;
+ y3 = y + item_y + line_height_with_spacing - scroll;
rect.x0 = x0;
rect.y0 = y0 > y2 ? y0 : y2;
@@ -1327,7 +1332,7 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y,
if (res != NSERROR_OK) {
return false;
}
- }
+ }
y2 = text_pos_offset + item_y;
res = ctx->plot->text(ctx,
@@ -1367,16 +1372,16 @@ bool form_clip_inside_select_menu(struct form_control *control, float scale,
{
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;
@@ -1508,26 +1513,26 @@ nserror form_control_bounding_rect(struct form_control *control, struct rect *r)
/**
* 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 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;
@@ -1536,11 +1541,11 @@ void form_select_menu_clicked(struct form_control *control, int x, int y)
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);
}
@@ -1552,7 +1557,7 @@ void form_select_menu_clicked(struct form_control *control, int x, int y)
* \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
+ * to be closed
*/
const char *form_select_mouse_action(struct form_control *control,
browser_mouse_state mouse, int x, int y)
@@ -1561,13 +1566,13 @@ const char *form_select_mouse_action(struct form_control *control,
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
@@ -1578,25 +1583,25 @@ const char *form_select_mouse_action(struct form_control *control,
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;
}
@@ -1633,13 +1638,13 @@ void form_select_mouse_drag_end(struct form_control *control,
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);
@@ -1654,13 +1659,13 @@ void form_select_menu_scroll_callback(void *client_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,
+ 0, 0,
menu->width,
- menu->height);
+ menu->height);
break;
case SCROLLBAR_MSG_SCROLL_START:
{
@@ -1711,10 +1716,10 @@ void form_select_menu_callback(void *client_data,
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] +
@@ -1801,7 +1806,7 @@ void form_submit(nsurl *page_url, struct browser_window *target,
}
/* Replace query segment */
- error = nsurl_replace_query(action_url, data, &action_query);
+ error = nsurl_replace_query(action_url, data, &action_query);
if (error != NSERROR_OK) {
nsurl_unref(action_query);
free(data);
@@ -1841,12 +1846,12 @@ void form_submit(nsurl *page_url, struct browser_window *target,
break;
case method_POST_MULTIPART:
- browser_window_navigate(target,
- action_url,
+ browser_window_navigate(target,
+ action_url,
page_url,
BW_NAVIGATE_HISTORY,
- NULL,
- success,
+ NULL,
+ success,
NULL);
break;
diff --git a/render/form_internal.h b/content/handlers/html/form_internal.h
similarity index 98%
rename from render/form_internal.h
rename to content/handlers/html/form_internal.h
index 0ffb6b4..a77e823 100644
--- a/render/form_internal.h
+++ b/content/handlers/html/form_internal.h
@@ -18,11 +18,11 @@
/**
* \file
- * Interface to form handling functions internal to render.
+ * Interface to form handling functions internal to HTML content handler.
*/
-#ifndef _NETSURF_RENDER_FORM_INTERNAL_H_
-#define _NETSURF_RENDER_FORM_INTERNAL_H_
+#ifndef NETSURF_HTML_FORM_INTERNAL_H
+#define NETSURF_HTML_FORM_INTERNAL_H
#include <stdbool.h>
@@ -229,7 +229,7 @@ bool form_successful_controls_dom(struct form *form,
bool form_open_select_menu(void *client_data,
struct form_control *control,
select_menu_redraw_callback redraw_callback,
- struct content *c);
+ struct content *c);
void form_select_menu_callback(void *client_data,
diff --git a/render/html.c b/content/handlers/html/html.c
similarity index 95%
rename from render/html.c
rename to content/handlers/html/html.c
index 3cfc5e2..62f625f 100644
--- a/render/html.c
+++ b/content/handlers/html/html.c
@@ -19,7 +19,7 @@
/**
* \file
- * Content for text/html (implementation).
+ * Implementation of HTML content handling.
*/
#include <assert.h>
@@ -54,12 +54,14 @@
#include "javascript/js.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-#include "render/imagemap.h"
-#include "render/layout.h"
-#include "render/search.h"
+#include "html/html.h"
+#include "html/html_save.h"
+#include "html/html_internal.h"
+#include "html/box.h"
+#include "html/form_internal.h"
+#include "html/imagemap.h"
+#include "html/layout.h"
+#include "html/search.h"
#define CHUNK 4096
@@ -139,7 +141,7 @@ static void html_box_convert_done(html_content *c, bool success)
exc = dom_document_get_document_element(c->document, (void *) &html);
if ((exc != DOM_NO_ERR) || (html == NULL)) {
/** @todo should this call html_object_free_objects(c);
- * like the other error paths
+ * like the other error paths
*/
NSLOG(netsurf, INFO, "error retrieving html element from dom");
content_broadcast_errorcode(&c->base, NSERROR_DOM);
@@ -568,7 +570,7 @@ static bool html_process_img(html_content *c, dom_node *node)
return success;
}
-/* exported function documented in render/html_internal.h */
+/* exported function documented in html/html_internal.h */
void html_finish_conversion(html_content *htmlc)
{
union content_msg_data msg_data;
@@ -583,6 +585,22 @@ void html_finish_conversion(html_content *htmlc)
return;
}
+ /* If we already have a selection context, then we have already
+ * "finished" conversion. We can get here twice if e.g. some JS
+ * adds a new stylesheet, and the stylesheet gets added after
+ * the HTML content is initially finished.
+ *
+ * If we didn't do this, the HTML content would try to rebuild the
+ * box tree for the html content when this new stylesheet is ready.
+ * NetSurf has no concept of dynamically changing documents, so this
+ * would break badly.
+ */
+ if (htmlc->select_ctx != NULL) {
+ NSLOG(netsurf, INFO,
+ "Ignoring style change: NS layout is static.");
+ return;
+ }
+
/* create new css selection context */
error = html_css_new_selection_context(htmlc, &htmlc->select_ctx);
if (error != NSERROR_OK) {
@@ -998,8 +1016,8 @@ html_create(const content_handler *handler,
static nserror
-html_process_encoding_change(struct content *c,
- const char *data,
+html_process_encoding_change(struct content *c,
+ const char *data,
unsigned int size)
{
html_content *html = (html_content *) c;
@@ -1010,7 +1028,7 @@ html_process_encoding_change(struct content *c,
unsigned long source_size;
/* Retrieve new encoding */
- encoding = dom_hubbub_parser_get_encoding(html->parser,
+ encoding = dom_hubbub_parser_get_encoding(html->parser,
&html->encoding_source);
if (encoding == NULL) {
return NSERROR_NOMEM;
@@ -1070,10 +1088,10 @@ html_process_encoding_change(struct content *c,
/* Reprocess all the data. This is safe because
* the encoding is now specified at parser start which means
- * it cannot be changed again.
+ * it cannot be changed again.
*/
- error = dom_hubbub_parser_parse_chunk(html->parser,
- (const uint8_t *)source_data,
+ error = dom_hubbub_parser_parse_chunk(html->parser,
+ (const uint8_t *)source_data,
source_size);
return libdom_hubbub_error_to_nserror(error);
@@ -1091,8 +1109,8 @@ html_process_data(struct content *c, const char *data, unsigned int size)
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,
+ dom_ret = dom_hubbub_parser_parse_chunk(html->parser,
+ (const uint8_t *) data,
size);
err = libdom_hubbub_error_to_nserror(dom_ret);
@@ -1108,7 +1126,7 @@ html_process_data(struct content *c, const char *data, unsigned int size)
return false;
}
- return true;
+ return true;
}
@@ -1188,14 +1206,14 @@ html_begin_conversion(html_content *htmlc)
dom_string *node_name = NULL;
dom_hubbub_error error;
- /* The act of completing the parse can result in additional data
- * being flushed through the parser. This may result in new style or
- * script nodes, upon which the conversion depends. Thus, once we
- * have completed the parse, we must check again to see if we can
- * begin the conversion. If we can't, we must stop and wait for the
+ /* The act of completing the parse can result in additional data
+ * being flushed through the parser. This may result in new style or
+ * script nodes, upon which the conversion depends. Thus, once we
+ * have completed the parse, we must check again to see if we can
+ * begin the conversion. If we can't, we must stop and wait for the
* new styles/scripts to be processed. Once they have been processed,
- * we will be called again to begin the conversion for real. Thus,
- * we must also ensure that we don't attempt to complete the parse
+ * we will be called again to begin the conversion for real. Thus,
+ * we must also ensure that we don't attempt to complete the parse
* multiple times, so store a flag to indicate that parsing is
* complete to avoid repeating the completion pointlessly.
*/
@@ -1205,8 +1223,8 @@ html_begin_conversion(html_content *htmlc)
error = dom_hubbub_parser_completed(htmlc->parser);
if (error != DOM_HUBBUB_OK) {
NSLOG(netsurf, INFO, "Parsing failed");
-
- content_broadcast_errorcode(&htmlc->base,
+
+ content_broadcast_errorcode(&htmlc->base,
libdom_hubbub_error_to_nserror(error));
return false;
@@ -1243,14 +1261,14 @@ html_begin_conversion(html_content *htmlc)
encoding = dom_hubbub_parser_get_encoding(htmlc->parser,
&htmlc->encoding_source);
if (encoding == NULL) {
- content_broadcast_errorcode(&htmlc->base,
+ content_broadcast_errorcode(&htmlc->base,
NSERROR_NOMEM);
return false;
}
htmlc->encoding = strdup(encoding);
if (htmlc->encoding == NULL) {
- content_broadcast_errorcode(&htmlc->base,
+ content_broadcast_errorcode(&htmlc->base,
NSERROR_NOMEM);
return false;
}
@@ -1268,7 +1286,7 @@ html_begin_conversion(html_content *htmlc)
if ((exc != DOM_NO_ERR) ||
(node_name == NULL) ||
(!dom_string_caseless_lwc_isequal(node_name,
- corestring_lwc_html))) {
+ corestring_lwc_html))) {
NSLOG(netsurf, INFO, "root element not html");
content_broadcast_errorcode(&htmlc->base, NSERROR_DOM);
dom_node_unref(html);
@@ -1287,11 +1305,11 @@ html_begin_conversion(html_content *htmlc)
/* 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),
+ nsurl_access(doc_addr),
&action);
} else {
- ns_error = nsurl_join(htmlc->base_url,
- f->action,
+ ns_error = nsurl_join(htmlc->base_url,
+ f->action,
&action);
}
@@ -1306,7 +1324,7 @@ html_begin_conversion(html_content *htmlc)
f->action = strdup(nsurl_access(action));
nsurl_unref(action);
if (f->action == NULL) {
- content_broadcast_errorcode(&htmlc->base,
+ content_broadcast_errorcode(&htmlc->base,
NSERROR_NOMEM);
dom_node_unref(html);
@@ -1317,7 +1335,7 @@ html_begin_conversion(html_content *htmlc)
if (f->document_charset == NULL) {
f->document_charset = strdup(htmlc->encoding);
if (f->document_charset == NULL) {
- content_broadcast_errorcode(&htmlc->base,
+ content_broadcast_errorcode(&htmlc->base,
NSERROR_NOMEM);
dom_node_unref(html);
return false;
@@ -1363,7 +1381,7 @@ static void html_stop(struct content *c)
html_object_abort_objects(htmlc);
/* If there are no further active fetches and we're still
- * in the READY state, transition to the DONE state. */
+ * in the READY state, transition to the DONE state. */
if (c->status == CONTENT_STATUS_READY && c->active == 0) {
content_set_done(c);
}
@@ -1398,6 +1416,10 @@ static void html_reformat(struct content *c, int width, int height)
htmlc->reflowing = true;
+ htmlc->len_ctx.vw = width;
+ htmlc->len_ctx.vh = height;
+ htmlc->len_ctx.root_style = htmlc->layout->style;
+
layout_document(htmlc, width, height);
layout = htmlc->layout;
@@ -1489,8 +1511,8 @@ static void html_destroy_frameset(struct content_html_frames *frameset)
nsurl_unref(frameset->children[i].url);
frameset->children[i].url = NULL;
}
- if (frameset->children[i].children)
- html_destroy_frameset(&frameset->children[i]);
+ if (frameset->children[i].children)
+ html_destroy_frameset(&frameset->children[i]);
}
talloc_free(frameset->children);
frameset->children = NULL;
@@ -1518,7 +1540,7 @@ static void html_free_layout(html_content *htmlc)
{
if (htmlc->bctx != NULL) {
/* freeing talloc context should let the entire box
- * set be destroyed
+ * set be destroyed
*/
talloc_free(htmlc->bctx);
}
@@ -1573,8 +1595,8 @@ static void html_destroy(struct content *c)
/* Free base target */
if (html->base_target != NULL) {
- free(html->base_target);
- html->base_target = NULL;
+ free(html->base_target);
+ html->base_target = NULL;
}
/* Free frameset */
@@ -1647,7 +1669,7 @@ html_open(struct content *c,
html->drag_owner.no_owner = true;
/* text selection */
- selection_init(&html->sel, html->layout);
+ selection_init(&html->sel, html->layout, &html->len_ctx);
html->selection_type = HTML_SELECTION_NONE;
html->selection_owner.none = true;
@@ -1768,7 +1790,8 @@ html_get_contextual_content(struct content *c, int x, int y,
struct box *next;
int box_x = 0, box_y = 0;
- while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
+ while ((next = box_at_point(&html->len_ctx, box, x, y,
+ &box_x, &box_y)) != NULL) {
box = next;
/* hidden boxes are ignored */
@@ -1845,7 +1868,8 @@ html_scroll_at_point(struct content *c, int x, int y, int scrx, int scry)
/* TODO: invert order; visit deepest box first */
- while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) {
+ while ((next = box_at_point(&html->len_ctx, box, x, y,
+ &box_x, &box_y)) != NULL) {
box = next;
if (box->style && css_computed_visibility(box->style) ==
@@ -1941,9 +1965,9 @@ static void html__set_file_gadget_filename(struct content *c,
NSLOG(netsurf, INFO,
"utf8 to local encoding conversion failed");
/* Load was for us - just no memory */
- return;
+ return;
}
-
+
form_gadget_update_value(gadget, utf8_fn);
/* corestring_dom___ns_key_file_name_node_data */
@@ -1956,7 +1980,7 @@ static void html__set_file_gadget_filename(struct content *c,
}
/* Redraw box. */
- html__redraw_a_box(html, file_box);
+ html__redraw_a_box(html, file_box);
}
void html_set_file_gadget_filename(struct hlcache_handle *hl,
@@ -1987,7 +2011,8 @@ static bool html_drop_file_at_point(struct content *c, int x, int y, char *file)
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) {
+ while ((next = box_at_point(&html->len_ctx, box, x, y,
+ &box_x, &box_y)) != NULL) {
box = next;
if (box->style && css_computed_visibility(box->style) ==
@@ -2253,7 +2278,8 @@ dom_document *html_get_document(hlcache_handle *h)
* \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/
+ * \todo This API must die, as must all use of the box tree outside of
+ * HTML content handler
*/
struct box *html_get_box_tree(hlcache_handle *h)
{
diff --git a/render/html.h b/content/handlers/html/html.h
similarity index 81%
rename from render/html.h
rename to content/handlers/html/html.h
index 30219a3..8d1c779 100644
--- a/render/html.h
+++ b/content/handlers/html/html.h
@@ -16,20 +16,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Content for text/html (interface).
+/**
+ * \file
+ * Interface to text/html content handler.
*
* These functions should in general be called via the content interface.
*/
-#ifndef _NETSURF_RENDER_HTML_H_
-#define _NETSURF_RENDER_HTML_H_
+#ifndef NETSURF_HTML_HTML_H
+#define NETSURF_HTML_HTML_H
#include <stdbool.h>
-#include <dom/dom.h>
-#include <dom/bindings/hubbub/parser.h>
-
#include "netsurf/types.h"
#include "netsurf/content_type.h"
#include "netsurf/browser_window.h"
@@ -64,6 +62,7 @@ struct html_stylesheet {
bool unused;
};
+
/**
* Container for scripts used by an HTML document
*/
@@ -88,7 +87,9 @@ struct html_script {
};
-/** An object (img, object, etc. tag) in a CONTENT_HTML document. */
+/**
+ * An object (img, object, etc. tag) in a CONTENT_HTML document.
+ */
struct content_html_object {
struct content *parent; /**< Parent document */
struct content_html_object *next; /**< Next in chain */
@@ -100,12 +101,10 @@ struct content_html_object {
bool background; /**< This object is a background image. */
};
-struct html_scrollbar_data {
- struct content *c;
- struct box *box;
-};
-/** Frame tree (frameset or frame tag) */
+/**
+ * Frame tree (frameset or frame tag)
+ */
struct content_html_frames {
int cols; /** number of columns in frameset */
int rows; /** number of rows in frameset */
@@ -126,9 +125,11 @@ struct content_html_frames {
struct content_html_frames *children; /** [cols * rows] children */
};
-/** Inline frame list (iframe tag) */
+/**
+ * Inline frame list (iframe tag)
+ */
struct content_html_iframe {
- struct box *box;
+ struct box *box;
int margin_width; /** frame margin width */
int margin_height; /** frame margin height */
@@ -140,7 +141,7 @@ struct content_html_iframe {
bool border; /** frame has a border */
colour border_colour; /** frame border colour */
- struct content_html_iframe *next;
+ struct content_html_iframe *next;
};
/* entries in stylesheet_content */
@@ -150,32 +151,46 @@ struct content_html_iframe {
#define STYLESHEET_USER 3 /* user stylesheet */
#define STYLESHEET_START 4 /* start of document stylesheets */
+/**
+ * initialise content handler
+ *
+ * \return NSERROR_OK on success otherwise appropriate error code
+ */
nserror html_init(void);
+/**
+ * redraw a specific box
+ *
+ * used by core browser
+ */
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 struct plot_font_style *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);
+/**
+ * obtain html frame content from handle
+ *
+ * used by core browser
+ */
struct content_html_frames *html_get_frameset(struct hlcache_handle *h);
+
+/**
+ * obtain html iframe content from handle
+ *
+ * used by core browser
+ */
struct content_html_iframe *html_get_iframe(struct hlcache_handle *h);
-struct nsurl *html_get_base_url(struct hlcache_handle *h);
+
+/**
+ * obtain html base target from handle
+ *
+ * used by core browser
+ */
const char *html_get_base_target(struct hlcache_handle *h);
+
+/**
+ * set filename on a file gadget
+ *
+ * used by core browser
+ */
void html_set_file_gadget_filename(struct hlcache_handle *hl,
struct form_control *gadget, const char *fn);
@@ -189,8 +204,19 @@ void html_set_file_gadget_filename(struct hlcache_handle *hl,
struct html_stylesheet *html_get_stylesheets(struct hlcache_handle *h,
unsigned int *n);
+/**
+ * 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 array of objects
+ */
struct content_html_object *html_get_objects(struct hlcache_handle *h,
unsigned int *n);
+
+/**
+ * get the offset within the docuemnt of a fragment id
+ */
bool html_get_id_offset(struct hlcache_handle *h, lwc_string *frag_id,
int *x, int *y);
diff --git a/render/html_css.c b/content/handlers/html/html_css.c
similarity index 98%
rename from render/html_css.c
rename to content/handlers/html/html_css.c
index 45bc16f..7b2d469 100644
--- a/render/html_css.c
+++ b/content/handlers/html/html_css.c
@@ -16,7 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Processing for html content css operations.
*/
@@ -37,7 +38,8 @@
#include "css/css.h"
#include "desktop/gui_internal.h"
-#include "render/html_internal.h"
+#include "html/html.h"
+#include "html/html_internal.h"
static nsurl *html_default_stylesheet_url;
static nsurl *html_adblock_stylesheet_url;
@@ -472,7 +474,7 @@ no_memory:
return false;
}
-/* exported interface documented in render/html.h */
+/* exported interface documented in html/html.h */
struct html_stylesheet *html_get_stylesheets(hlcache_handle *h, unsigned int *n)
{
html_content *c = (html_content *) hlcache_handle_get_content(h);
@@ -486,7 +488,7 @@ struct html_stylesheet *html_get_stylesheets(hlcache_handle *h, unsigned int *n)
}
-/* exported interface documented in render/html_internal.h */
+/* exported interface documented in html/html_internal.h */
nserror html_css_free_stylesheets(html_content *html)
{
unsigned int i;
@@ -506,7 +508,7 @@ nserror html_css_free_stylesheets(html_content *html)
return NSERROR_OK;
}
-/* exported interface documented in render/html_internal.h */
+/* exported interface documented in html/html_internal.h */
nserror html_css_quirks_stylesheets(html_content *c)
{
nserror ns_error = NSERROR_OK;
@@ -534,7 +536,7 @@ nserror html_css_quirks_stylesheets(html_content *c)
return ns_error;
}
-/* exported interface documented in render/html_internal.h */
+/* exported interface documented in html/html_internal.h */
nserror html_css_new_stylesheets(html_content *c)
{
nserror ns_error;
diff --git a/render/html_css_fetcher.c b/content/handlers/html/html_css_fetcher.c
similarity index 93%
rename from render/html_css_fetcher.c
rename to content/handlers/html/html_css_fetcher.c
index 0f8809a..7987ea0 100644
--- a/render/html_css_fetcher.c
+++ b/content/handlers/html/html_css_fetcher.c
@@ -17,6 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * HTML fetcher for CSS objects
+ */
+
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
@@ -33,7 +38,7 @@
#include "content/fetch.h"
#include "content/fetchers.h"
-#include "render/html_internal.h"
+#include "html/html_internal.h"
typedef struct html_css_fetcher_item {
uint32_t key;
@@ -51,7 +56,7 @@ typedef struct html_css_fetcher_context {
bool aborted;
bool locked;
-
+
struct html_css_fetcher_context *r_next, *r_prev;
} html_css_fetcher_context;
@@ -86,7 +91,7 @@ static void *html_css_fetcher_setup(struct fetch *parent_fetch, nsurl *url,
lwc_string *path;
uint32_t key;
html_css_fetcher_item *item, *found = NULL;
-
+
/* format of a x-ns-css URL is:
* x-ns-url:<key>
* Where key is an unsigned 32bit integer
@@ -131,7 +136,7 @@ static void *html_css_fetcher_setup(struct fetch *parent_fetch, nsurl *url,
ctx->item = found;
RING_INSERT(ring, ctx);
-
+
return ctx;
}
@@ -160,14 +165,14 @@ static void html_css_fetcher_abort(void *ctx)
html_css_fetcher_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.
+ * disappearing from under it, we simply flag the abort here.
* The poll loop itself will perform the appropriate cleanup.
*/
c->aborted = true;
}
-static void html_css_fetcher_send_callback(const fetch_msg *msg,
- html_css_fetcher_context *c)
+static void html_css_fetcher_send_callback(const fetch_msg *msg,
+ html_css_fetcher_context *c)
{
c->locked = true;
fetch_send_callback(msg, c->parent_fetch);
@@ -178,16 +183,16 @@ static void html_css_fetcher_poll(lwc_string *scheme)
{
fetch_msg msg;
html_css_fetcher_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
+ * the interested party causes fetch_poll() to be called
* again.
*/
if (c->locked == true) {
@@ -213,26 +218,26 @@ static void html_css_fetcher_poll(lwc_string *scheme)
msg.type = FETCH_HEADER;
msg.data.header_or_data.buf = (const uint8_t *) header;
msg.data.header_or_data.len = strlen(header);
- html_css_fetcher_send_callback(&msg, c);
+ html_css_fetcher_send_callback(&msg, c);
if (c->aborted == false) {
- snprintf(header, sizeof header,
+ snprintf(header, sizeof header,
"Content-Length: %"PRIsizet,
dom_string_byte_length(c->item->data));
msg.type = FETCH_HEADER;
- msg.data.header_or_data.buf =
+ msg.data.header_or_data.buf =
(const uint8_t *) header;
msg.data.header_or_data.len = strlen(header);
html_css_fetcher_send_callback(&msg, c);
}
if (c->aborted == false) {
- snprintf(header, sizeof header,
+ snprintf(header, sizeof header,
"X-NS-Base: %.*s",
(int) nsurl_length(c->item->base_url),
nsurl_access(c->item->base_url));
msg.type = FETCH_HEADER;
- msg.data.header_or_data.buf =
+ msg.data.header_or_data.buf =
(const uint8_t *) header;
msg.data.header_or_data.len = strlen(header);
html_css_fetcher_send_callback(&msg, c);
@@ -240,8 +245,8 @@ static void html_css_fetcher_poll(lwc_string *scheme)
if (c->aborted == false) {
msg.type = FETCH_DATA;
- msg.data.header_or_data.buf =
- (const uint8_t *)
+ msg.data.header_or_data.buf =
+ (const uint8_t *)
dom_string_data(c->item->data);
msg.data.header_or_data.len =
dom_string_byte_length(c->item->data);
@@ -256,7 +261,7 @@ static void html_css_fetcher_poll(lwc_string *scheme)
NSLOG(netsurf, INFO, "Processing of %s failed!",
nsurl_access(c->url));
- /* Ensure that we're unlocked here. If we aren't,
+ /* Ensure that we're unlocked here. If we aren't,
* then html_css_fetcher_process() is broken.
*/
assert(c->locked == false);
@@ -318,4 +323,3 @@ html_css_fetcher_add_item(dom_string *data, nsurl *base_url, uint32_t *key)
return NSERROR_OK;
}
-
diff --git a/render/html_forms.c b/content/handlers/html/html_forms.c
similarity index 99%
rename from render/html_forms.c
rename to content/handlers/html/html_forms.c
index 39bc690..915eb00 100644
--- a/render/html_forms.c
+++ b/content/handlers/html/html_forms.c
@@ -16,14 +16,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * HTML form handling implementation
+ */
+
#include "utils/config.h"
#include "utils/corestrings.h"
#include "utils/log.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
+#include "html/form_internal.h"
+#include "html/html_internal.h"
-/**
+/**
* process form element from dom
*/
static struct form *
@@ -572,4 +577,3 @@ struct form_control *html_forms_get_control_for_node(struct form *forms,
return ctl;
}
-
diff --git a/render/html_interaction.c b/content/handlers/html/html_interaction.c
similarity index 97%
rename from render/html_interaction.c
rename to content/handlers/html/html_interaction.c
index 30adaa0..648d274 100644
--- a/render/html_interaction.c
+++ b/content/handlers/html/html_interaction.c
@@ -2,7 +2,7 @@
* Copyright 2006 James Bursa <bursa(a)users.sourceforge.net>
* Copyright 2006 Richard Wilson <info(a)tinct.net>
* Copyright 2008 Michael Drake <tlsa(a)netsurf-browser.org>
- * Copyright 2009 Paul Blokus <paul_pl(a)users.sourceforge.net>
+ * Copyright 2009 Paul Blokus <paul_pl(a)users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -21,7 +21,7 @@
/**
* \file
- * User interaction with a CONTENT_HTML (implementation).
+ * implementation of user interaction with a CONTENT_HTML.
*/
#include <assert.h>
@@ -48,13 +48,13 @@
#include "javascript/js.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/box_textarea.h"
-#include "render/font.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-#include "render/imagemap.h"
-#include "render/search.h"
+#include "html/box.h"
+#include "html/box_textarea.h"
+#include "html/font.h"
+#include "html/form_internal.h"
+#include "html/html_internal.h"
+#include "html/imagemap.h"
+#include "html/search.h"
/**
* Get pointer shape for given box
@@ -208,7 +208,7 @@ static size_t html_selection_drag_end(struct html_content *html,
if (box) {
plot_font_style_t fstyle;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(&html->len_ctx, box->style, &fstyle);
guit->layout->position(&fstyle, box->text, box->length,
dx, &idx, &pixel_offset);
@@ -294,6 +294,45 @@ html__image_coords_dom_user_data_handler(dom_node_operation operation,
}
}
+
+/**
+ * End overflow scroll scrollbar drags
+ *
+ * \param scrollbar scrollbar widget
+ * \param mouse state of mouse buttons and modifier keys
+ * \param x coordinate of mouse
+ * \param y coordinate of mouse
+ */
+static 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);
+ }
+}
+
+
/**
* Handle mouse clicks and movements in an HTML content window.
*
@@ -415,7 +454,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
size_t idx;
plot_font_style_t fstyle;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(&html->len_ctx,
+ box->style, &fstyle);
guit->layout->position(&fstyle,
box->text, box->length,
@@ -504,7 +544,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
assert(html->drag_type == HTML_DRAG_NONE);
/* search the box tree for a link, imagemap, form control, or
- * box with scrollbars
+ * box with scrollbars
*/
box = html->layout;
@@ -514,7 +554,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
box_y = box->margin[TOP];
/* descend through visible boxes setting more specific values for:
- * box - deepest box at point
+ * box - deepest box at point
* html_object_box - html object
* html_object_pos_x - html object
* html_object_pos_y - html object
@@ -539,13 +579,13 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
* 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
*/
do {
- if ((box->style != NULL) &&
- (css_computed_visibility(box->style) ==
+ if ((box->style != NULL) &&
+ (css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN)) {
continue;
}
@@ -597,8 +637,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
}
pointer = get_pointer_shape(box, false);
-
- if ((box->scroll_x != NULL) ||
+
+ if ((box->scroll_x != NULL) ||
(box->scroll_y != NULL)) {
if (drag_candidate == NULL) {
@@ -613,29 +653,29 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
scrollbar_get_offset(box->scroll_y);
padding_bottom = padding_top + box->padding[TOP] +
box->height + box->padding[BOTTOM];
-
- if ((x > padding_left) &&
+
+ if ((x > padding_left) &&
(x < padding_right) &&
- (y > padding_top) &&
+ (y > padding_top) &&
(y < padding_bottom)) {
/* mouse inside padding box */
-
- if ((box->scroll_y != NULL) &&
+
+ 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))) {
+ SCROLLBAR_WIDTH))) {
/* mouse above horizontal box scroll */
-
+
scrollbar = box->scroll_x;
scroll_mouse_x = x - padding_left;
scroll_mouse_y = y - (padding_bottom -
@@ -649,7 +689,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
text_box = box;
text_box_x = box_x;
}
- } while ((box = box_at_point(box, x, y, &box_x, &box_y)) != NULL);
+ } while ((box = box_at_point(&html->len_ctx, box, x, y,
+ &box_x, &box_y)) != NULL);
/* 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 */
@@ -892,7 +933,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
/* if clicking in the main page, remove the selection from any
* text areas */
if (!done) {
-
+
if (click && html->focus_type != HTML_FOCUS_SELF) {
union html_focus_owner fo;
fo.self = true;
@@ -910,8 +951,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
int pixel_offset;
size_t idx;
- font_plot_style_from_css(text_box->style,
- &fstyle);
+ font_plot_style_from_css(&html->len_ctx,
+ text_box->style, &fstyle);
guit->layout->position(&fstyle,
text_box->text,
@@ -1188,7 +1229,7 @@ void html_overflow_scroll_callback(void *client_data,
union content_msg_data msg_data;
html_drag_type drag_type;
union html_drag_owner drag_owner;
-
+
switch(scrollbar_data->msg) {
case SCROLLBAR_MSG_MOVED:
@@ -1225,41 +1266,6 @@ void html_overflow_scroll_callback(void *client_data,
}
-/**
- * End overflow scroll scrollbar drags
- *
- * \param scrollbar 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);
- }
-}
-
/* Documented in html_internal.h */
void html_set_drag_type(html_content *html, html_drag_type drag_type,
union html_drag_owner drag_owner, const struct rect *rect)
diff --git a/render/html_internal.h b/content/handlers/html/html_internal.h
similarity index 92%
rename from render/html_internal.h
rename to content/handlers/html/html_internal.h
index 2f84cf8..77354c3 100644
--- a/render/html_internal.h
+++ b/content/handlers/html/html_internal.h
@@ -18,19 +18,21 @@
/**
* \file
- * Content for text/html (private data).
+ * Private data for text/html content.
*/
-#ifndef NETSURF_RENDER_HTML_INTERNAL_H_
-#define NETSURF_RENDER_HTML_INTERNAL_H_
+#ifndef NETSURF_HTML_HTML_INTERNAL_H
+#define NETSURF_HTML_HTML_INTERNAL_H
#include <libcss/libcss.h>
+#include <dom/bindings/hubbub/parser.h>
+#include "netsurf/types.h"
#include "content/content_protected.h"
#include "desktop/selection.h"
-#include "render/html.h"
struct gui_layout_table;
+struct scrollbar_msg_data;
typedef enum {
HTML_DRAG_NONE, /** No drag */
@@ -42,12 +44,15 @@ typedef enum {
HTML_DRAG_CONTENT_SCROLL /** Not own; drag in child content */
} html_drag_type;
+/**
+ * For drags we don't own
+ */
union html_drag_owner {
bool no_owner;
struct box *content;
struct scrollbar *scrollbar;
struct box *textarea;
-}; /**< For drags we don't own */
+};
typedef enum {
HTML_SELECTION_NONE, /** No selection */
@@ -55,24 +60,39 @@ typedef enum {
HTML_SELECTION_SELF, /** Selection in this html content */
HTML_SELECTION_CONTENT /** Selection in child content */
} html_selection_type;
+
+/**
+ * For getting at selections in this content or things in this content
+ */
union html_selection_owner {
bool none;
struct box *textarea;
struct box *content;
-}; /**< For getting at selections in this content or things in this content */
+};
typedef enum {
- HTML_FOCUS_SELF, /** Focus is our own */
- HTML_FOCUS_CONTENT, /** Focus belongs to child content */
- HTML_FOCUS_TEXTAREA /** Focus belongs to textarea */
+ HTML_FOCUS_SELF, /**< Focus is our own */
+ HTML_FOCUS_CONTENT, /**< Focus belongs to child content */
+ HTML_FOCUS_TEXTAREA /**< Focus belongs to textarea */
} html_focus_type;
+
+/**
+ * For directing input
+ */
union html_focus_owner {
bool self;
struct box *textarea;
struct box *content;
-}; /**< For directing input */
+};
+
+struct html_scrollbar_data {
+ struct content *c;
+ struct box *box;
+};
-/** Data specific to CONTENT_HTML. */
+/**
+ * Data specific to CONTENT_HTML.
+ */
typedef struct html_content {
struct content base;
@@ -94,6 +114,9 @@ typedef struct html_content {
/** Base target */
char *base_target;
+ /** CSS length conversion context for document. */
+ nscss_len_ctx len_ctx;
+
/** Content has been aborted in the LOADING state */
bool aborted;
@@ -109,7 +132,7 @@ typedef struct html_content {
/* Title element node */
dom_node *title;
- /** A talloc context purely for the render box tree */
+ /** A talloc context purely for the render box tree */
int *bctx;
/** Box tree, or NULL. */
struct box *layout;
@@ -153,7 +176,7 @@ typedef struct html_content {
/** Inline frame information */
struct content_html_iframe *iframe;
- /** Content of type CONTENT_HTML containing this, or NULL if not an
+ /** Content of type CONTENT_HTML containing this, or NULL if not an
* object within a page. */
struct html_content *page;
@@ -254,11 +277,11 @@ bool html_can_begin_conversion(html_content *htmlc);
*/
bool html_begin_conversion(html_content *htmlc);
-/* in render/html_redraw.c */
+/* in html/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_redraw_border.c */
+/* in html/html_redraw_border.c */
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);
@@ -267,7 +290,7 @@ 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);
-/* in render/html_interaction.c */
+/* in html/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,
@@ -280,7 +303,7 @@ void html_search(struct content *c, void *context,
void html_search_clear(struct content *c);
-/* in render/html_script.c */
+/* in html/html_script.c */
dom_hubbub_error html_process_script(void *ctx, dom_node *node);
/**
@@ -310,12 +333,12 @@ nserror html_script_free(html_content *htmlc);
*/
nserror html_script_invalidate_ctx(html_content *htmlc);
-/* in render/html_forms.c */
+/* in html/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);
-/* in render/html_css.c */
+/* in html/html_css.c */
nserror html_css_init(void);
void html_css_fini(void);
@@ -336,7 +359,7 @@ bool html_css_update_style(html_content *c, dom_node *style);
nserror html_css_new_selection_context(html_content *c,
css_select_ctx **ret_select_ctx);
-/* in render/html_css_fetcher.c */
+/* in html/html_css_fetcher.c */
/**
* Register the fetcher for the pseudo x-ns-css scheme.
*
@@ -346,7 +369,7 @@ nserror html_css_fetcher_register(void);
nserror html_css_fetcher_add_item(dom_string *data, nsurl *base_url,
uint32_t *key);
-/* in render/html_object.c */
+/* in html/html_object.c */
/**
* Start a fetch for an object required by a page.
@@ -402,5 +425,3 @@ extern struct dom_string *html_dom_string_type;
extern struct dom_string *html_dom_string_src;
#endif
-
-
diff --git a/render/html_object.c b/content/handlers/html/html_object.c
similarity index 90%
rename from render/html_object.c
rename to content/handlers/html/html_object.c
index e98bdba..7eab466 100644
--- a/render/html_object.c
+++ b/content/handlers/html/html_object.c
@@ -16,7 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Processing for html content object operations.
*/
@@ -39,8 +40,9 @@
#include "desktop/scrollbar.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/html_internal.h"
+#include "html/html.h"
+#include "html/box.h"
+#include "html/html_internal.h"
/* break reference loop */
static void html_object_refresh(void *p);
@@ -97,6 +99,16 @@ html_object_done(struct box *box,
box->object = object;
+ /* Normalise the box type, now it has been replaced. */
+ switch (box->type) {
+ case BOX_TABLE:
+ box->type = BOX_BLOCK;
+ break;
+ default:
+ /* TODO: Any other box types need mapping? */
+ break;
+ }
+
if (!(box->flags & REPLACE_DIM)) {
/* invalidate parent min, max widths */
for (b = box; b; b = b->parent)
@@ -227,7 +239,8 @@ html_object_callback(hlcache_handle *object,
if (hunit == CSS_UNIT_PCT) {
l = (width - w) * hpos / INTTOFIX(100);
} else {
- l = FIXTOINT(nscss_len2px(hpos, hunit,
+ l = FIXTOINT(nscss_len2px(&c->len_ctx,
+ hpos, hunit,
box->style));
}
@@ -235,7 +248,8 @@ html_object_callback(hlcache_handle *object,
if (vunit == CSS_UNIT_PCT) {
t = (height - h) * vpos / INTTOFIX(100);
} else {
- t = FIXTOINT(nscss_len2px(vpos, vunit,
+ t = FIXTOINT(nscss_len2px(&c->len_ctx,
+ vpos, vunit,
box->style));
}
@@ -438,40 +452,40 @@ html_object_callback(hlcache_handle *object,
}
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 ||
- event->type == CONTENT_MSG_ERRORCODE)) {
+ c->base.active == 0 &&
+ (event->type == CONTENT_MSG_LOADING ||
+ event->type == CONTENT_MSG_DONE ||
+ event->type == CONTENT_MSG_ERROR ||
+ event->type == CONTENT_MSG_ERRORCODE)) {
/* all objects have arrived */
content__reformat(&c->base, false, c->base.available_width,
c->base.height);
content_set_done(&c->base);
} else if (nsoption_bool(incremental_reflow) &&
- event->type == CONTENT_MSG_DONE &&
- box != NULL &&
- !(box->flags & REPLACE_DIM) &&
- (c->base.status == CONTENT_STATUS_READY ||
- c->base.status == CONTENT_STATUS_DONE)) {
- /* 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,
- */
- uint64_t ms_now;
- nsu_getmonotonic_ms(&ms_now);
- if (ms_now > c->base.reformat_time) {
- /* The time since the previous reformat is
- * more than the configured minimum time
- * between reformats so reformat the page to
- * display newly fetched objects
- */
- content__reformat(&c->base,
- false,
- c->base.available_width,
- c->base.height);
- }
+ event->type == CONTENT_MSG_DONE &&
+ box != NULL &&
+ !(box->flags & REPLACE_DIM) &&
+ (c->base.status == CONTENT_STATUS_READY ||
+ c->base.status == CONTENT_STATUS_DONE)) {
+ /* 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,
+ */
+ uint64_t ms_now;
+ nsu_getmonotonic_ms(&ms_now);
+ if (ms_now > c->base.reformat_time) {
+ /* The time since the previous reformat is
+ * more than the configured minimum time
+ * between reformats so reformat the page to
+ * display newly fetched objects
+ */
+ content__reformat(&c->base,
+ false,
+ c->base.available_width,
+ c->base.height);
+ }
}
return NSERROR_OK;
@@ -664,7 +678,7 @@ nserror html_object_free_objects(html_content *html)
-/* exported interface documented in render/html_internal.h */
+/* exported interface documented in html/html_internal.h */
bool html_fetch_object(html_content *c, nsurl *url, struct box *box,
content_type permitted_types,
int available_width, int available_height,
@@ -698,7 +712,7 @@ bool html_fetch_object(html_content *c, nsurl *url, struct box *box,
content_get_url(&c->base), NULL,
html_object_callback, object, &child,
object->permitted_types, &object->content);
- if (error != NSERROR_OK) {
+ if (error != NSERROR_OK) {
free(object);
return error != NSERROR_NOMEM;
}
diff --git a/render/html_redraw.c b/content/handlers/html/html_redraw.c
similarity index 96%
rename from render/html_redraw.c
rename to content/handlers/html/html_redraw.c
index 2f87306..d05df87 100644
--- a/render/html_redraw.c
+++ b/content/handlers/html/html_redraw.c
@@ -5,7 +5,7 @@
* Copyright 2005-2006 Adrian Lees <adrianl(a)users.sourceforge.net>
* Copyright 2006 Rob Kendrick <rjek(a)netsurf-browser.org>
* Copyright 2008 Michael Drake <tlsa(a)netsurf-browser.org>
- * Copyright 2009 Paul Blokus <paul_pl(a)users.sourceforge.net>
+ * Copyright 2009 Paul Blokus <paul_pl(a)users.sourceforge.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -53,12 +53,12 @@
#include "desktop/textarea.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/font.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-#include "render/layout.h"
-#include "render/search.h"
+#include "html/box.h"
+#include "html/font.h"
+#include "html/form_internal.h"
+#include "html/html_internal.h"
+#include "html/layout.h"
+#include "html/search.h"
bool html_redraw_debug = false;
@@ -150,7 +150,7 @@ static struct box *html_redraw_find_bg_box(struct box *box)
* \return true iff successful and redraw should proceed
*/
-bool
+static bool
text_redraw(const char *utf8_text,
size_t utf8_len,
size_t offset,
@@ -401,7 +401,7 @@ static bool html_redraw_checkbox(int x, int y, int width, int height,
return false;
}
- /* light line across bottom */
+ /* light line across bottom */
rect.x0 = x;
rect.y0 = y + height;
res = ctx->plot->line(ctx, plot_style_stroke_lightwbasec, &rect);
@@ -521,12 +521,14 @@ static bool html_redraw_radio(int x, int y, int width, int height,
* \param box box of input
* \param scale scale for redraw
* \param background_colour current background colour
+ * \param len_ctx Length conversion context
* \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 nscss_len_ctx *len_ctx,
const struct redraw_context *ctx)
{
int text_width;
@@ -535,7 +537,7 @@ static bool html_redraw_file(int x, int y, int width, int height,
plot_font_style_t fstyle;
nserror res;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(len_ctx, box->style, &fstyle);
fstyle.background = background_colour;
if (box->gadget->value) {
@@ -578,13 +580,16 @@ static bool html_redraw_file(int x, int y, int width, int height,
* \param clip current clip rectangle
* \param background_colour current background colour
* \param background box containing background details (usually \a box)
- * \param ctx current redraw context
+ * \param len_ctx Length conversion context
+ * \param ctx current redraw context
* \return true if successful, false otherwise
*/
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)
+ struct box *background,
+ const nscss_len_ctx *len_ctx,
+ const struct redraw_context *ctx)
{
bool repeat_x = false;
bool repeat_y = false;
@@ -656,20 +661,20 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale,
css_computed_background_position(background->style,
&hpos, &hunit, &vpos, &vunit);
if (hunit == CSS_UNIT_PCT) {
- x += (width -
+ x += (width -
content_get_width(background->background)) *
scale * FIXTOFLT(hpos) / 100.;
} else {
- x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit,
+ x += (int) (FIXTOFLT(nscss_len2px(len_ctx, hpos, hunit,
background->style)) * scale);
}
if (vunit == CSS_UNIT_PCT) {
- y += (height -
+ y += (height -
content_get_height(background->background)) *
scale * FIXTOFLT(vpos) / 100.;
} else {
- y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
+ y += (int) (FIXTOFLT(nscss_len2px(len_ctx, vpos, vunit,
background->style)) * scale);
}
}
@@ -719,10 +724,10 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale,
/* if the background content is opaque there
* is no need to plot underneath it.
*/
- if ((r.x0 >= r.x1) ||
+ if ((r.x0 >= r.x1) ||
(r.y0 >= r.y1) ||
(nscss_color_is_transparent(bgcol) == false) ||
- ((clip_box->background != NULL) &&
+ ((clip_box->background != NULL) &&
content_get_opaque(clip_box->background)))
continue;
}
@@ -802,13 +807,15 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale,
* \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
+ * \param len_ctx Length conversion context
+ * \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 nscss_len_ctx *len_ctx,
const struct redraw_context *ctx)
{
struct rect r = *clip;
@@ -836,7 +843,7 @@ static bool html_redraw_inline_background(int x, int y, struct box *box,
case CSS_BACKGROUND_REPEAT_REPEAT:
repeat_x = repeat_y = true;
/* optimisation: only plot the colour if
- * bitmap is not opaque
+ * bitmap is not opaque
*/
plot_colour = !content_get_opaque(box->background);
break;
@@ -861,15 +868,15 @@ static bool html_redraw_inline_background(int x, int y, struct box *box,
&hpos, &hunit, &vpos, &vunit);
if (hunit == CSS_UNIT_PCT) {
x += (b.x1 - b.x0 -
- content_get_width(box->background) *
+ content_get_width(box->background) *
scale) * FIXTOFLT(hpos) / 100.;
- if (!repeat_x && ((hpos < 2 && !first) ||
+ if (!repeat_x && ((hpos < 2 && !first) ||
(hpos > 98 && !last))){
plot_content = false;
}
} else {
- x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit,
+ x += (int) (FIXTOFLT(nscss_len2px(len_ctx, hpos, hunit,
box->style)) * scale);
}
@@ -878,7 +885,7 @@ static bool html_redraw_inline_background(int x, int y, struct box *box,
content_get_height(box->background) *
scale) * FIXTOFLT(vpos) / 100.;
} else {
- y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
+ y += (int) (FIXTOFLT(nscss_len2px(len_ctx, vpos, vunit,
box->style)) * scale);
}
}
@@ -1075,7 +1082,7 @@ static bool html_redraw_text_decoration(struct box *box,
if (!box->inline_end)
return true;
for (i = 0; i != NOF_ELEMENTS(decoration); i++)
- if (css_computed_text_decoration(box->style) &
+ if (css_computed_text_decoration(box->style) &
decoration[i])
if (!html_redraw_text_decoration_inline(box,
x_parent, y_parent, scale,
@@ -1083,7 +1090,7 @@ static bool html_redraw_text_decoration(struct box *box,
return false;
} else {
for (i = 0; i != NOF_ELEMENTS(decoration); i++)
- if (css_computed_text_decoration(box->style) &
+ if (css_computed_text_decoration(box->style) &
decoration[i])
if (!html_redraw_text_decoration_block(box,
x_parent + box->x,
@@ -1120,7 +1127,7 @@ static bool html_redraw_text_box(const html_content *html, struct box *box,
bool excluded = (box->object != NULL);
plot_font_style_t fstyle;
- font_plot_style_from_css(box->style, &fstyle);
+ font_plot_style_from_css(&html->len_ctx, box->style, &fstyle);
fstyle.background = current_background_color;
if (!text_redraw(box->text, box->length, box->byte_offset,
@@ -1358,7 +1365,7 @@ bool html_redraw_box(const html_content *html, struct box *box,
}
/* if visibility is hidden render children only */
- if (box->style && css_computed_visibility(box->style) ==
+ if (box->style && css_computed_visibility(box->style) ==
CSS_VISIBILITY_HIDDEN) {
if ((ctx->plot->group_start) &&
(ctx->plot->group_start(ctx, "hidden box") != NSERROR_OK))
@@ -1382,21 +1389,25 @@ bool html_redraw_box(const html_content *html, struct box *box,
/* We have an absolutly positioned box with a clip rect */
if (css_rect.left_auto == false)
r.x0 = x - border_left + FIXTOINT(nscss_len2px(
+ &html->len_ctx,
css_rect.left, css_rect.lunit,
box->style));
if (css_rect.top_auto == false)
r.y0 = y - border_top + FIXTOINT(nscss_len2px(
+ &html->len_ctx,
css_rect.top, css_rect.tunit,
box->style));
if (css_rect.right_auto == false)
r.x1 = x - border_left + FIXTOINT(nscss_len2px(
+ &html->len_ctx,
css_rect.right, css_rect.runit,
box->style));
if (css_rect.bottom_auto == false)
r.y1 = y - border_top + FIXTOINT(nscss_len2px(
+ &html->len_ctx,
css_rect.bottom, css_rect.bunit,
box->style));
@@ -1486,7 +1497,8 @@ bool html_redraw_box(const html_content *html, struct box *box,
if ((p.x0 < p.x1) && (p.y0 < p.y1)) {
/* plot background */
if (!html_redraw_background(x, y, box, scale, &p,
- ¤t_background_color, bg_box, ctx))
+ ¤t_background_color, bg_box,
+ &html->len_ctx, ctx))
return false;
/* restore previous graphics window */
if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
@@ -1565,7 +1577,8 @@ bool html_redraw_box(const html_content *html, struct box *box,
if (!html_redraw_inline_background(
x, y, box, scale, &p, b,
first, false,
- ¤t_background_color, ctx))
+ ¤t_background_color,
+ &html->len_ctx, ctx))
return false;
/* restore previous graphics window */
if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
@@ -1597,7 +1610,8 @@ bool html_redraw_box(const html_content *html, struct box *box,
/* plot background and borders for last rectangle of
* the inline */
if (!html_redraw_inline_background(x, ib_y, box, scale, &p, b,
- first, true, ¤t_background_color, ctx))
+ first, true, ¤t_background_color,
+ &html->len_ctx, ctx))
return false;
/* restore previous graphics window */
if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
@@ -1768,7 +1782,6 @@ bool html_redraw_box(const html_content *html, struct box *box,
obj, sizeof(obj) - 1) != NSERROR_OK)
return false;
}
-
} else if (box->iframe) {
/* Offset is passed to browser window redraw unscaled */
@@ -1789,7 +1802,7 @@ bool html_redraw_box(const html_content *html, struct box *box,
} 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))
+ current_background_color, &html->len_ctx, ctx))
return false;
} else if (box->gadget &&
@@ -1842,11 +1855,11 @@ bool html_redraw_box(const html_content *html, struct box *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] +
+ y_parent + box->y + box->padding[TOP] +
box->height + box->padding[BOTTOM] -
SCROLLBAR_WIDTH, clip, scale, ctx);
if (box->scroll_y != NULL)
@@ -1906,16 +1919,16 @@ bool html_redraw(struct content *c, struct content_redraw_data *data,
select_only = form_clip_inside_select_menu(control,
data->scale, clip);
}
-
+
if (!select_only) {
/* clear to background colour */
result = (ctx->plot->clip(ctx, clip) == NSERROR_OK);
-
+
if (html->background_colour != NS_TRANSPARENT)
pstyle_fill_bg.fill_colour = html->background_colour;
result &= (ctx->plot->rectangle(ctx, &pstyle_fill_bg, clip) == NSERROR_OK);
-
+
result &= html_redraw_box(html, box, data->x, data->y, clip,
data->scale, pstyle_fill_bg.fill_colour, ctx);
}
@@ -1924,7 +1937,7 @@ bool html_redraw(struct content *c, struct content_redraw_data *data,
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];
diff --git a/render/html_redraw_border.c b/content/handlers/html/html_redraw_border.c
similarity index 99%
rename from render/html_redraw_border.c
rename to content/handlers/html/html_redraw_border.c
index 07c503c..0b3d858 100644
--- a/render/html_redraw_border.c
+++ b/content/handlers/html/html_redraw_border.c
@@ -29,8 +29,8 @@
#include "netsurf/plotters.h"
#include "netsurf/css.h"
-#include "render/box.h"
-#include "render/html_internal.h"
+#include "html/box.h"
+#include "html/html_internal.h"
static plot_style_t plot_style_bdr = {
@@ -111,7 +111,7 @@ html_redraw_border_plot(const int side,
plot_style_bdr.stroke_type = PLOT_OP_TYPE_DASH;
plot_style_bdr.stroke_colour = c;
- plot_style_bdr.stroke_width = thickness;
+ plot_style_bdr.stroke_width = (thickness << PLOT_STYLE_RADIX);
plot_style_fillbdr.fill_colour = c;
plot_style_fillbdr_dark.fill_colour = darken_colour(c);
plot_style_fillbdr_light.fill_colour = lighten_colour(c);
diff --git a/content/handlers/pdf/pdf.h b/content/handlers/html/html_save.h
similarity index 55%
copy from content/handlers/pdf/pdf.h
copy to content/handlers/html/html_save.h
index 2171b80..c173922 100644
--- a/content/handlers/pdf/pdf.h
+++ b/content/handlers/html/html_save.h
@@ -18,12 +18,29 @@
/**
* \file
- * Interface for PDF content handler.
+ * Interface to HTML content handler to save documents.
+ *
+ * \todo Investigate altering this API as it is only used for
+ * exporting the html content to disc.
+ */
+
+#ifndef NETSURF_HTML_HTML_SAVE_H
+#define NETSURF_HTML_HTML_SAVE_H
+
+/**
+ * get the dom document of a html content from a handle
*/
+dom_document *html_get_document(struct hlcache_handle *h);
-#ifndef NETSURF_PDF_PDF_H_
-#define NETSURF_PDF_PDF_H_
-nserror nspdf_init(void);
+/**
+ * get the render box tree of a html content from a handle
+ */
+struct box *html_get_box_tree(struct hlcache_handle *h);
+
+/**
+ * get the base url of an html content from a handle
+ */
+struct nsurl *html_get_base_url(struct hlcache_handle *h);
#endif
diff --git a/render/html_script.c b/content/handlers/html/html_script.c
similarity index 97%
rename from render/html_script.c
rename to content/handlers/html/html_script.c
index c73a480..80992b9 100644
--- a/render/html_script.c
+++ b/content/handlers/html/html_script.c
@@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Content for text/html scripts (implementation).
+/**
+ * \file
+ * implementation of content handling for text/html scripts.
*/
#include <assert.h>
@@ -38,7 +39,8 @@
#include "content/fetch.h"
#include "content/hlcache.h"
-#include "render/html_internal.h"
+#include "html/html.h"
+#include "html/html_internal.h"
typedef bool (script_handler_t)(struct jscontext *jscontext, const char *data, size_t size) ;
@@ -52,7 +54,7 @@ static script_handler_t *select_script_handler(content_type ctype)
}
-/* exported internal interface documented in render/html_internal.h */
+/* exported internal interface documented in html/html_internal.h */
nserror html_script_exec(html_content *c)
{
unsigned int i;
@@ -568,7 +570,7 @@ html_process_script(void *ctx, dom_node *node)
return err;
}
-/* exported internal interface documented in render/html_internal.h */
+/* exported internal interface documented in html/html_internal.h */
nserror html_script_free(html_content *html)
{
unsigned int i;
@@ -595,7 +597,7 @@ nserror html_script_free(html_content *html)
return NSERROR_OK;
}
-/* exported internal interface documented in render/html_internal.h */
+/* exported internal interface documented in html/html_internal.h */
nserror html_script_invalidate_ctx(html_content *htmlc)
{
htmlc->jscontext = NULL;
diff --git a/render/imagemap.c b/content/handlers/html/imagemap.c
similarity index 97%
rename from render/imagemap.c
rename to content/handlers/html/imagemap.c
index 0d3b42a..d26ba5f 100644
--- a/render/imagemap.c
+++ b/content/handlers/html/imagemap.c
@@ -16,8 +16,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/*
- * Much of this shamelessly copied from utils/messages.c
+/**
+ * \file
+ * Implementation of HTML image maps
+ *
+ * \todo should this should use the general hashmap instead of its own
*/
#include <assert.h>
@@ -32,9 +35,9 @@
#include "content/content_protected.h"
#include "content/hlcache.h"
-#include "render/box.h"
-#include "render/html_internal.h"
-#include "render/imagemap.h"
+#include "html/box.h"
+#include "html/html_internal.h"
+#include "html/imagemap.h"
#define HASH_SIZE 31 /* fixed size hash table */
@@ -296,8 +299,11 @@ void imagemap_dump(html_content *c)
* \return false on memory exhaustion, true otherwise
*/
static bool
-imagemap_addtolist(const struct html_content *c, dom_node *n, nsurl *base_url,
- struct mapentry **entry, dom_string *tagtype)
+imagemap_addtolist(const struct html_content *c,
+ dom_node *n,
+ nsurl *base_url,
+ struct mapentry **entry,
+ dom_string *tagtype)
{
dom_exception exc;
dom_string *href = NULL, *target = NULL, *shape = NULL;
@@ -374,9 +380,12 @@ imagemap_addtolist(const struct html_content *c, dom_node *n, nsurl *base_url,
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));
+
+ strncpy(new_map->target,
+ dom_string_data(target),
+ dom_string_byte_length(target));
+
+ new_map->target[dom_string_byte_length(target)] = 0;
}
if (new_map->type != IMAGEMAP_DEFAULT) {
diff --git a/render/imagemap.h b/content/handlers/html/imagemap.h
similarity index 90%
rename from render/imagemap.h
rename to content/handlers/html/imagemap.h
index 3ae6819..8e189a0 100644
--- a/render/imagemap.h
+++ b/content/handlers/html/imagemap.h
@@ -16,8 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _NETSURF_RENDER_IMAGEMAP_H_
-#define _NETSURF_RENDER_IMAGEMAP_H_
+/**
+ * \file
+ * Interface to HTML imagemap
+ */
+
+#ifndef NETSURF_HTML_IMAGEMAP_H
+#define NETSURF_HTML_IMAGEMAP_H
#include <dom/dom.h>
diff --git a/render/layout.c b/content/handlers/html/layout.c
similarity index 88%
rename from render/layout.c
rename to content/handlers/html/layout.c
index 7ca688f..d52dbf8 100644
--- a/render/layout.c
+++ b/content/handlers/html/layout.c
@@ -56,21 +56,78 @@
#include "desktop/scrollbar.h"
#include "desktop/textarea.h"
-#include "render/box.h"
-#include "render/font.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-#include "render/layout.h"
-#include "render/table.h"
+#include "html/html.h"
+#include "html/html_save.h"
+#include "html/html_internal.h"
+#include "html/box.h"
+#include "html/font.h"
+#include "html/form_internal.h"
+#include "html/layout.h"
+#include "html/table.h"
#define AUTO INT_MIN
/* Fixed point percentage (a) of an integer (b), to an integer */
#define FPCT_OF_INT_TOINT(a, b) (FIXTOINT(FDIV((a * b), F_100)))
+typedef uint8_t (*css_len_func)(
+ const css_computed_style *style,
+ css_fixed *length, css_unit *unit);
+typedef uint8_t (*css_border_style_func)(
+ const css_computed_style *style);
+typedef uint8_t (*css_border_color_func)(
+ const css_computed_style *style,
+ css_color *color);
+
+/** Array of per-side access functions for computed style margins. */
+static const css_len_func margin_funcs[4] = {
+ [TOP] = css_computed_margin_top,
+ [RIGHT] = css_computed_margin_right,
+ [BOTTOM] = css_computed_margin_bottom,
+ [LEFT] = css_computed_margin_left,
+};
+
+/** Array of per-side access functions for computed style paddings. */
+static const css_len_func padding_funcs[4] = {
+ [TOP] = css_computed_padding_top,
+ [RIGHT] = css_computed_padding_right,
+ [BOTTOM] = css_computed_padding_bottom,
+ [LEFT] = css_computed_padding_left,
+};
+
+/** Array of per-side access functions for computed style border_widths. */
+static const css_len_func border_width_funcs[4] = {
+ [TOP] = css_computed_border_top_width,
+ [RIGHT] = css_computed_border_right_width,
+ [BOTTOM] = css_computed_border_bottom_width,
+ [LEFT] = css_computed_border_left_width,
+};
+
+/** Array of per-side access functions for computed style border styles. */
+static const css_border_style_func border_style_funcs[4] = {
+ [TOP] = css_computed_border_top_style,
+ [RIGHT] = css_computed_border_right_style,
+ [BOTTOM] = css_computed_border_bottom_style,
+ [LEFT] = css_computed_border_left_style,
+};
+
+/** Array of per-side access functions for computed style border colors. */
+static const css_border_color_func border_color_funcs[4] = {
+ [TOP] = css_computed_border_top_color,
+ [RIGHT] = css_computed_border_right_color,
+ [BOTTOM] = css_computed_border_bottom_color,
+ [LEFT] = css_computed_border_left_color,
+};
+
/* forward declaration to break cycles */
-static bool layout_block_context(struct box *block, int viewport_height, html_content *content);
-static void layout_minmax_block(struct box *block, const struct gui_layout_table *font_func);
+static bool layout_block_context(
+ struct box *block,
+ int viewport_height,
+ html_content *content);
+static void layout_minmax_block(
+ struct box *block,
+ const struct gui_layout_table *font_func,
+ const html_content *content);
/**
@@ -179,7 +236,9 @@ layout_get_object_dimensions(struct box *box,
* \param width width of containing block
* \return length of indent
*/
-static int layout_text_indent(const css_computed_style *style, int width)
+static int layout_text_indent(
+ const nscss_len_ctx *len_ctx,
+ const css_computed_style *style, int width)
{
css_fixed value = 0;
css_unit unit = CSS_UNIT_PX;
@@ -189,7 +248,7 @@ static int layout_text_indent(const css_computed_style *style, int width)
if (unit == CSS_UNIT_PCT) {
return FPCT_OF_INT_TOINT(value, width);
} else {
- return FIXTOINT(nscss_len2px(value, unit, style));
+ return FIXTOINT(nscss_len2px(len_ctx, value, unit, style));
}
}
@@ -197,6 +256,7 @@ static int layout_text_indent(const css_computed_style *style, int width)
/**
* Determine width of margin, borders, and padding on one side of a box.
*
+ * \param len_ctx CSS length conversion context for document
* \param style style to measure
* \param side side of box to measure
* \param margin whether margin width is required
@@ -206,7 +266,8 @@ static int layout_text_indent(const css_computed_style *style, int width)
* \param frac increased by sum of fractional margin and padding
*/
static void
-calculate_mbp_width(const css_computed_style *style,
+calculate_mbp_width(const nscss_len_ctx *len_ctx,
+ const css_computed_style *style,
unsigned int side,
bool margin,
bool border,
@@ -214,35 +275,6 @@ calculate_mbp_width(const css_computed_style *style,
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;
@@ -257,19 +289,20 @@ calculate_mbp_width(const css_computed_style *style,
if (unit == CSS_UNIT_PCT) {
*frac += FIXTOINT(FDIV(value, F_100));
} else {
- *fixed += FIXTOINT(nscss_len2px(value, unit,
- style));
+ *fixed += FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
}
}
/* border */
if (border) {
- if (border_funcs[side].style(style) !=
+ if (border_style_funcs[side](style) !=
CSS_BORDER_STYLE_NONE) {
- border_funcs[side].width(style, &value, &unit);
+ border_width_funcs[side](style, &value, &unit);
- *fixed += FIXTOINT(nscss_len2px(value, unit, style));
+ *fixed += FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
}
@@ -279,11 +312,216 @@ calculate_mbp_width(const css_computed_style *style,
if (unit == CSS_UNIT_PCT) {
*frac += FIXTOINT(FDIV(value, F_100));
} else {
- *fixed += FIXTOINT(nscss_len2px(value, unit, style));
+ *fixed += FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
+ }
+ }
+}
+
+
+/**
+ * Calculate minimum and maximum width of a table.
+ *
+ * \param table box of type TABLE
+ * \param font_func Font functions
+ * \param content The HTML content we are laying out.
+ * \post table->min_width and table->max_width filled in,
+ * 0 <= table->min_width <= table->max_width
+ */
+static void layout_minmax_table(struct box *table,
+ const struct gui_layout_table *font_func,
+ const html_content *content)
+{
+ 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;
+ 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;
+
+ if (table_calculate_column_types(&content->len_ctx, table) == false) {
+ NSLOG(netsurf, WARNING,
+ "Could not establish table column types.");
+ return;
+ }
+ col = table->col;
+
+ /* 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(&content->len_ctx,
+ 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, content);
+ 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, content);
+ 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, true);
+ 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(&content->len_ctx,
+ 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(&content->len_ctx,
+ table->style, LEFT, true, true, true,
+ &extra_fixed, &extra_frac);
+ calculate_mbp_width(&content->len_ctx,
+ 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);
}
+/**
+ * Helper to check if a box has percentage max width.
+ *
+ * \param[in] b Box to check.
+ * \return true iff box has percnetage max width.
+ */
+static inline bool box_has_percentage_max_width(struct box *b)
+{
+ css_unit unit = CSS_UNIT_PX;
+ enum css_max_width_e type;
+ css_fixed value = 0;
+
+ assert(b != NULL);
+
+ type = css_computed_max_width(b->style, &value, &unit);
+ return ((type == CSS_MAX_WIDTH_SET) && (unit == CSS_UNIT_PCT));
+}
/**
* Calculate minimum and maximum width of a line.
@@ -303,7 +541,8 @@ layout_minmax_line(struct box *first,
int *line_max,
bool first_line,
bool *line_has_height,
- const struct gui_layout_table *font_func)
+ const struct gui_layout_table *font_func,
+ const html_content *content)
{
int min = 0, max = 0, width, height, fixed;
float frac;
@@ -349,9 +588,11 @@ layout_minmax_line(struct box *first,
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);
+ layout_minmax_block(b->children, font_func,
+ content);
else
- layout_minmax_table(b->children, font_func);
+ layout_minmax_table(b->children, font_func,
+ content);
b->min_width = b->children->min_width;
b->max_width = b->children->max_width;
if (min < b->min_width)
@@ -361,7 +602,7 @@ layout_minmax_line(struct box *first,
}
if (b->type == BOX_INLINE_BLOCK) {
- layout_minmax_block(b, font_func);
+ layout_minmax_block(b, font_func, content);
if (min < b->min_width)
min = b->min_width;
max += b->max_width;
@@ -372,16 +613,18 @@ layout_minmax_line(struct box *first,
}
assert(b->style);
- font_plot_style_from_css(b->style, &fstyle);
+ font_plot_style_from_css(&content->len_ctx, 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,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT, true, true, true,
&fixed, &frac);
if (!b->inline_end)
- calculate_mbp_width(b->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
true, true, true,
&fixed, &frac);
if (0 < fixed)
@@ -390,7 +633,8 @@ layout_minmax_line(struct box *first,
/* \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,
+ calculate_mbp_width(&content->len_ctx,
+ b->inline_end->style, RIGHT,
true, true, true,
&fixed, &frac);
if (0 < fixed)
@@ -505,21 +749,19 @@ layout_minmax_line(struct box *first,
bs = css_computed_box_sizing(block->style);
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));
+ width = FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, b->style));
if (bs == CSS_BOX_SIZING_BORDER_BOX) {
fixed = frac = 0;
- calculate_mbp_width(block->style, LEFT,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, LEFT,
false, true, true,
&fixed, &frac);
- calculate_mbp_width(block->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, RIGHT,
false, true, true,
&fixed, &frac);
if (width < fixed) {
@@ -536,7 +778,8 @@ layout_minmax_line(struct box *first,
/* height */
htype = css_computed_height(b->style, &value, &unit);
if (htype == CSS_HEIGHT_SET) {
- height = FIXTOINT(nscss_len2px(value, unit, b->style));
+ height = FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, b->style));
} else {
height = AUTO;
}
@@ -552,17 +795,21 @@ layout_minmax_line(struct box *first,
fixed = frac = 0;
if (bs == CSS_BOX_SIZING_BORDER_BOX) {
- calculate_mbp_width(b->style, LEFT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT,
true, false, false,
&fixed, &frac);
- calculate_mbp_width(b->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
true, false, false,
&fixed, &frac);
} else {
- calculate_mbp_width(b->style, LEFT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT,
true, true, true,
&fixed, &frac);
- calculate_mbp_width(b->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
true, true, true,
&fixed, &frac);
}
@@ -575,17 +822,21 @@ layout_minmax_line(struct box *first,
fixed = frac = 0;
if (bs == CSS_BOX_SIZING_BORDER_BOX) {
- calculate_mbp_width(b->style, LEFT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT,
true, false, false,
&fixed, &frac);
- calculate_mbp_width(b->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
true, false, false,
&fixed, &frac);
} else {
- calculate_mbp_width(b->style, LEFT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, LEFT,
true, true, true,
&fixed, &frac);
- calculate_mbp_width(b->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ b->style, RIGHT,
true, true, true,
&fixed, &frac);
}
@@ -596,13 +847,16 @@ layout_minmax_line(struct box *first,
} else {
/* form control with no object */
if (width == AUTO)
- width = FIXTOINT(nscss_len2px(INTTOFIX(1),
- CSS_UNIT_EM, b->style));
+ width = FIXTOINT(nscss_len2px(
+ &content->len_ctx,
+ INTTOFIX(1), CSS_UNIT_EM,
+ b->style));
}
- if (min < width)
+ if (min < width && !box_has_percentage_max_width(b))
min = width;
- max += width;
+ if (width > 0)
+ max += width;
*line_has_height = true;
}
@@ -610,7 +864,7 @@ layout_minmax_line(struct box *first,
if (first_line) {
/* todo: handle percentage values properly */
/* todo: handle text-indent interaction with floats */
- int text_indent = layout_text_indent(
+ int text_indent = layout_text_indent(&content->len_ctx,
first->parent->parent->style, 100);
min = (min + text_indent < 0) ? 0 : min + text_indent;
max = (max + text_indent < 0) ? 0 : max + text_indent;
@@ -640,7 +894,8 @@ layout_minmax_line(struct box *first,
static void
layout_minmax_inline_container(struct box *inline_container,
bool *has_height,
- const struct gui_layout_table *font_func)
+ const struct gui_layout_table *font_func,
+ const html_content *content)
{
struct box *child;
int line_min = 0, line_max = 0;
@@ -658,7 +913,8 @@ layout_minmax_inline_container(struct box *inline_container,
for (child = inline_container->children; child; ) {
child = layout_minmax_line(child, &line_min, &line_max,
- first_line, &line_has_height, font_func);
+ first_line, &line_has_height, font_func,
+ content);
if (min < line_min)
min = line_min;
if (max < line_max)
@@ -681,11 +937,14 @@ layout_minmax_inline_container(struct box *inline_container,
*
* \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
* \param font_func font functions
+ * \param content The HTML content being layed out.
* \post block->min_width and block->max_width filled in,
* 0 <= block->min_width <= block->max_width
*/
-static void
-layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
+static void layout_minmax_block(
+ struct box *block,
+ const struct gui_layout_table *font_func,
+ const html_content *content)
{
struct box *child;
int min = 0, max = 0;
@@ -738,7 +997,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
css_fixed size = INTTOFIX(10);
css_unit unit = CSS_UNIT_EM;
- min = max = FIXTOINT(nscss_len2px(size, unit, block->style));
+ min = max = FIXTOINT(nscss_len2px(&content->len_ctx,
+ size, unit, block->style));
block->flags |= HAS_HEIGHT;
}
@@ -751,7 +1011,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
/* form checkbox or radio button
* if width is AUTO, set it to 1em */
- min = max = FIXTOINT(nscss_len2px(size, unit, block->style));
+ min = max = FIXTOINT(nscss_len2px(&content->len_ctx,
+ size, unit, block->style));
block->flags |= HAS_HEIGHT;
}
@@ -759,7 +1020,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
if (block->object) {
if (content_get_type(block->object) == CONTENT_HTML) {
layout_minmax_block(html_get_box_tree(block->object),
- font_func);
+ font_func, content);
min = html_get_box_tree(block->object)->min_width;
max = html_get_box_tree(block->object)->max_width;
} else {
@@ -776,7 +1037,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
for (child = block->children; child; child = child->next) {
switch (child->type) {
case BOX_BLOCK:
- layout_minmax_block(child, font_func);
+ layout_minmax_block(child, font_func,
+ content);
if (child->flags & HAS_HEIGHT)
child_has_height = true;
break;
@@ -785,7 +1047,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
child->flags |= NEED_MIN;
layout_minmax_inline_container(child,
- &child_has_height, font_func);
+ &child_has_height, font_func,
+ content);
if (child_has_height &&
child ==
child->parent->children) {
@@ -793,7 +1056,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
}
break;
case BOX_TABLE:
- layout_minmax_table(child, font_func);
+ layout_minmax_table(child, font_func,
+ content);
/* todo: fix for zero height tables */
child_has_height = true;
child->flags |= MAKE_HEIGHT;
@@ -831,14 +1095,17 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
/* 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));
+ min = max = FIXTOINT(nscss_len2px(&content->len_ctx,
+ width, wunit, block->style));
if (bs == CSS_BOX_SIZING_BORDER_BOX) {
int border_box_fixed = 0;
float border_box_frac = 0;
- calculate_mbp_width(block->style, LEFT,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, LEFT,
false, true, true,
&border_box_fixed, &border_box_frac);
- calculate_mbp_width(block->style, RIGHT,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, RIGHT,
false, true, true,
&border_box_fixed, &border_box_frac);
if (min < border_box_fixed) {
@@ -858,14 +1125,18 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
* and paddings are wrong. */
if (bs == CSS_BOX_SIZING_BORDER_BOX && wtype == CSS_WIDTH_SET) {
/* Border and padding included in width, so just get margin */
- calculate_mbp_width(block->style, LEFT, true, false, false,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, LEFT, true, false, false,
&extra_fixed, &extra_frac);
- calculate_mbp_width(block->style, RIGHT, true, false, false,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, RIGHT, true, false, false,
&extra_fixed, &extra_frac);
} else {
- calculate_mbp_width(block->style, LEFT, true, true, true,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, LEFT, true, true, true,
&extra_fixed, &extra_frac);
- calculate_mbp_width(block->style, RIGHT, true, true, true,
+ calculate_mbp_width(&content->len_ctx,
+ block->style, RIGHT, true, true, true,
&extra_fixed, &extra_frac);
}
if (extra_fixed < 0)
@@ -895,6 +1166,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
*
* This turns the specified dimension into a content-box dimension.
*
+ * \param len_ctx Length conversion context
* \param box gadget to adjust dimensions of
* \param available_width width of containing block
* \param setwidth set true if the dimension to be tweaked is a width,
@@ -904,6 +1176,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func)
* gadget properties.
*/
static void layout_handle_box_sizing(
+ const nscss_len_ctx *len_ctx,
struct box *box,
int available_width,
bool setwidth,
@@ -920,9 +1193,11 @@ static void layout_handle_box_sizing(
int fixed = 0;
float frac = 0;
- calculate_mbp_width(box->style, setwidth ? LEFT : TOP,
+ calculate_mbp_width(len_ctx, box->style,
+ setwidth ? LEFT : TOP,
false, true, true, &fixed, &frac);
- calculate_mbp_width(box->style, setwidth ? RIGHT : BOTTOM,
+ calculate_mbp_width(len_ctx, box->style,
+ setwidth ? RIGHT : BOTTOM,
false, true, true, &fixed, &frac);
orig -= frac * available_width + fixed;
*dimension = orig > 0 ? orig : 0;
@@ -933,6 +1208,7 @@ static void layout_handle_box_sizing(
/**
* Calculate width, height, and thickness of margins, paddings, and borders.
*
+ * \param len_ctx Length conversion context
* \param available_width width of containing block
* \param viewport_height height of viewport in pixels or -ve if unknown
* \param box current box
@@ -949,7 +1225,8 @@ static void layout_handle_box_sizing(
* \param border filled with border widths, may be NULL
*/
static void
-layout_find_dimensions(int available_width,
+layout_find_dimensions(const nscss_len_ctx *len_ctx,
+ int available_width,
int viewport_height,
struct box *box,
const css_computed_style *style,
@@ -978,15 +1255,15 @@ layout_find_dimensions(int available_width,
*width = FPCT_OF_INT_TOINT(
value, available_width);
} else {
- *width = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
*width = AUTO;
}
if (*width != AUTO) {
- layout_handle_box_sizing(box, available_width,
+ layout_handle_box_sizing(len_ctx, box, available_width,
true, width);
}
}
@@ -1066,15 +1343,15 @@ layout_find_dimensions(int available_width,
*height = AUTO;
}
} else {
- *height = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *height = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
*height = AUTO;
}
if (*height != AUTO) {
- layout_handle_box_sizing(box, available_width,
+ layout_handle_box_sizing(len_ctx, box, available_width,
false, height);
}
}
@@ -1091,8 +1368,8 @@ layout_find_dimensions(int available_width,
*max_width = FPCT_OF_INT_TOINT(value,
available_width);
} else {
- *max_width = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *max_width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
/* Inadmissible */
@@ -1100,7 +1377,7 @@ layout_find_dimensions(int available_width,
}
if (*max_width != -1) {
- layout_handle_box_sizing(box, available_width,
+ layout_handle_box_sizing(len_ctx, box, available_width,
true, max_width);
}
}
@@ -1117,8 +1394,8 @@ layout_find_dimensions(int available_width,
*min_width = FPCT_OF_INT_TOINT(value,
available_width);
} else {
- *min_width = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *min_width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
/* Inadmissible */
@@ -1126,7 +1403,7 @@ layout_find_dimensions(int available_width,
}
if (*min_width != 0) {
- layout_handle_box_sizing(box, available_width,
+ layout_handle_box_sizing(len_ctx, box, available_width,
true, min_width);
}
}
@@ -1143,8 +1420,8 @@ layout_find_dimensions(int available_width,
/* TODO: handle percentage */
*max_height = -1;
} else {
- *max_height = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *max_height = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
/* Inadmissible */
@@ -1164,8 +1441,8 @@ layout_find_dimensions(int available_width,
/* TODO: handle percentage */
*min_height = 0;
} else {
- *min_height = FIXTOINT(nscss_len2px(value, unit,
- style));
+ *min_height = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
} else {
/* Inadmissible */
@@ -1179,32 +1456,16 @@ layout_find_dimensions(int available_width,
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;
- }
+ type = margin_funcs[i](style, &value, &unit);
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));
+ margin[i] = FIXTOINT(nscss_len2px(
+ len_ctx,
+ value, unit, style));
}
} else {
margin[i] = AUTO;
@@ -1215,29 +1476,14 @@ layout_find_dimensions(int available_width,
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;
- }
+ padding_funcs[i](style, &value, &unit);
if (unit == CSS_UNIT_PCT) {
padding[i] = FPCT_OF_INT_TOINT(value,
available_width);
} else {
- padding[i] = FIXTOINT(nscss_len2px(value, unit,
- style));
+ padding[i] = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
}
}
@@ -1248,33 +1494,9 @@ layout_find_dimensions(int available_width,
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_width_funcs[i](style, &value, &unit);
+ bstyle = border_style_funcs[i](style);
+ border_color_funcs[i](style, &color);
border[i].style = bstyle;
border[i].c = color;
@@ -1284,8 +1506,8 @@ layout_find_dimensions(int available_width,
/* spec unclear: following Mozilla */
border[i].width = 0;
else
- border[i].width = FIXTOINT(nscss_len2px(value,
- unit, style));
+ border[i].width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, style));
/* Special case for border-collapse: make all borders
* on table/table-row-group/table-row zero width. */
@@ -1303,6 +1525,7 @@ layout_find_dimensions(int available_width,
/**
* Find next block that current margin collapses to.
*
+ * \param len_ctx Length conversion context
* \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
@@ -1311,7 +1534,8 @@ layout_find_dimensions(int available_width,
* \return next box that current margin collapses to, or NULL if none.
*/
static struct box*
-layout_next_margin_block(struct box *box,
+layout_next_margin_block(const nscss_len_ctx *len_ctx,
+ struct box *box,
struct box *block,
int viewport_height,
int *max_pos_margin,
@@ -1330,7 +1554,8 @@ layout_next_margin_block(struct box *box,
/* Get margins */
if (box->style) {
- layout_find_dimensions(box->parent->width,
+ layout_find_dimensions(len_ctx,
+ box->parent->width,
viewport_height, box,
box->style,
NULL, NULL, NULL, NULL,
@@ -1353,7 +1578,7 @@ layout_next_margin_block(struct box *box,
css_computed_overflow_y(box->style) !=
CSS_OVERFLOW_VISIBLE) ||
(box->type == BOX_INLINE_CONTAINER &&
- box != box->parent->children)) {
+ !box_is_first_child(box))) {
/* Collapse to this box; return it */
return box;
}
@@ -1404,7 +1629,8 @@ layout_next_margin_block(struct box *box,
/* Get margins */
if (box->style) {
- layout_find_dimensions(box->parent->width,
+ layout_find_dimensions(len_ctx,
+ box->parent->width,
viewport_height, box,
box->style,
NULL, NULL, NULL, NULL,
@@ -1640,6 +1866,7 @@ layout_solve_width(struct box *box,
* Compute dimensions of box, margins, paddings, and borders for a block-level
* element.
*
+ * \param len_ctx Length conversion context
* \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.
@@ -1652,7 +1879,8 @@ layout_solve_width(struct box *box,
* See CSS 2.1 10.3.3, 10.3.4, 10.6.2, and 10.6.3.
*/
static void
-layout_block_find_dimensions(int available_width,
+layout_block_find_dimensions(const nscss_len_ctx *len_ctx,
+ int available_width,
int viewport_height,
int lm,
int rm,
@@ -1665,8 +1893,8 @@ layout_block_find_dimensions(int available_width,
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,
+ layout_find_dimensions(len_ctx, available_width, viewport_height, box,
+ style, &width, &height, &max_width, &min_width,
&max_height, &min_height, margin, padding, border);
if (box->object && !(box->flags & REPLACE_DIM) &&
@@ -1819,8 +2047,9 @@ static bool layout_table(struct box *table, int available_width,
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,
- 0, 0, table->margin, table->padding, table->border);
+ layout_find_dimensions(&content->len_ctx, available_width, -1, table,
+ style, 0, 0, 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) {
@@ -1829,9 +2058,11 @@ static bool layout_table(struct box *table, int available_width,
enum css_overflow_e overflow_y;
assert(c->style);
- table_used_border_for_cell(c);
- layout_find_dimensions(available_width, -1,
- c, c->style, 0, 0, 0, 0, 0, 0,
+ table_used_border_for_cell(
+ &content->len_ctx, c);
+ layout_find_dimensions(&content->len_ctx,
+ available_width, -1, c,
+ c->style, 0, 0, 0, 0, 0, 0,
0, c->padding, c->border);
overflow_x = css_computed_overflow_x(c->style);
@@ -1859,8 +2090,10 @@ static bool layout_table(struct box *table, int available_width,
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));
+ border_spacing_h = FIXTOINT(nscss_len2px(&content->len_ctx,
+ h, hu, style));
+ border_spacing_v = FIXTOINT(nscss_len2px(&content->len_ctx,
+ v, vu, style));
}
/* find specified table width, or available width if auto-width */
@@ -1870,7 +2103,8 @@ static bool layout_table(struct box *table, int available_width,
table_width = FPCT_OF_INT_TOINT(value, available_width);
} else {
table_width =
- FIXTOINT(nscss_len2px(value, unit, style));
+ FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, style));
}
/* specified width includes border */
@@ -1948,14 +2182,15 @@ static bool layout_table(struct box *table, int available_width,
} else {
/* This is the minimum height for the table
* (see 17.5.3) */
- min_height = FIXTOINT(nscss_len2px(value, unit, style));
+ min_height = FIXTOINT(nscss_len2px(&content->len_ctx,
+ value, unit, style));
}
}
/* calculate width required by cells */
for (i = 0; i != columns; i++) {
- NSLOG(layout, DEBUG,
+ NSLOG(layout, DEBUG,
"table %p, column %u: type %s, width %i, min %i, max %i",
table,
i,
@@ -1992,7 +2227,7 @@ static bool layout_table(struct box *table, int available_width,
required_width += (columns + 1 - positioned_columns) *
border_spacing_h;
- NSLOG(layout, DEBUG,
+ NSLOG(layout, DEBUG,
"width %i, min %i, max %i, auto %i, required %i", table_width,
table->min_width, table->max_width, auto_width, required_width);
@@ -2138,8 +2373,9 @@ static bool layout_table(struct box *table, int available_width,
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));
+ row_height = FIXTOINT(nscss_len2px(
+ &content->len_ctx,
+ value, unit, row->style));
}
for (c = row->children; c; c = c->next) {
assert(c->style);
@@ -2176,8 +2412,9 @@ static bool layout_table(struct box *table, int available_width,
/* 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));
+ int h = FIXTOINT(nscss_len2px(
+ &content->len_ctx,
+ value, unit, c->style));
if (c->height < h)
c->height = h;
}
@@ -2321,12 +2558,16 @@ static bool layout_table(struct box *table, int available_width,
/**
* Manimpulate box height according to CSS min-height and max-height properties
*
+ * \param len_ctx CSS length conversion context for document.
* \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
*/
-static bool layout_apply_minmax_height(struct box *box, struct box *container)
+static bool layout_apply_minmax_height(
+ const nscss_len_ctx *len_ctx,
+ struct box *box,
+ struct box *container)
{
int h;
struct box *containing_block = NULL;
@@ -2385,8 +2626,8 @@ static bool layout_apply_minmax_height(struct box *box, struct box *container)
}
}
} else {
- h = FIXTOINT(nscss_len2px(value, unit,
- box->style));
+ h = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
if (h < box->height) {
box->height = h;
updated = true;
@@ -2415,8 +2656,8 @@ static bool layout_apply_minmax_height(struct box *box, struct box *container)
}
}
} else {
- h = FIXTOINT(nscss_len2px(value, unit,
- box->style));
+ h = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, box->style));
if (h > box->height) {
box->height = h;
updated = true;
@@ -2459,2643 +2700,2482 @@ static bool layout_block_object(struct box *block)
/**
- * Layout a block formatting context.
+ * Insert a float into a container.
*
- * \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
+ * \param cont block formatting context block, used to contain float
+ * \param b box to add to float
*
- * This function carries out layout of a block and its children, as described
- * in CSS 2.1 9.4.1.
+ * This sorts floats in order of descending bottom edges.
*/
-static bool
-layout_block_context(struct box *block,
- int viewport_height,
- html_content *content)
+static void add_float_to_container(struct box *cont, struct box *b)
{
- 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);
+ struct box *box = cont->float_children;
+ int b_bottom = b->y + b->height;
- block->float_children = NULL;
- block->cached_place_below_level = 0;
- block->clear_level = 0;
+ assert(b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT);
- /* 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,
- INT_MIN, INT_MAX);
- return true;
- } else if (block->flags & REPLACE_DIM) {
- return true;
+ if (box == NULL) {
+ /* No other float children */
+ b->next_float = NULL;
+ cont->float_children = b;
+ return;
+ } else if (b_bottom >= box->y + box->height) {
+ /* Goes at start of list */
+ b->next_float = cont->float_children;
+ cont->float_children = b;
+ } else {
+ struct box *prev = NULL;
+ while (box != NULL && b_bottom < box->y + box->height) {
+ prev = box;
+ box = box->next_float;
+ }
+ if (prev != NULL) {
+ b->next_float = prev->next_float;
+ prev->next_float = b;
+ }
}
+}
- /* 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));
+
+/**
+ * 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 gui_layout_table *font_func = content->font_func;
+ bool space = (split_box->text[new_length] == ' ');
+ int used_length = new_length + (space ? 1 : 0);
+
+ if ((space && space_width == 0) || space_width == UNKNOWN_WIDTH) {
+ /* We're need to add a space, and we don't know how big
+ * it's to be, OR we have a space of unknown width anyway;
+ * Calculate space width */
+ font_func->width(fstyle, " ", 1, &space_width);
}
- 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];
+ if (split_box->space == UNKNOWN_WIDTH)
+ split_box->space = space_width;
+ if (!space)
+ space_width = 0;
- /* 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) {
- enum css_overflow_e overflow_x = CSS_OVERFLOW_VISIBLE;
- enum css_overflow_e overflow_y = CSS_OVERFLOW_VISIBLE;
+ /* Create clone of split_box, c2 */
+ c2 = talloc_memdup(content->bctx, split_box, sizeof *c2);
+ if (!c2)
+ return false;
+ c2->flags |= CLONE;
- assert(box->type == BOX_BLOCK || box->type == BOX_TABLE ||
- box->type == BOX_INLINE_CONTAINER);
+ /* Set remaining text in c2 */
+ c2->text += used_length;
- /* 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.
- */
+ /* 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 - used_length;
- 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;
- }
+ /* 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;
- /* 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;
- }
+ /* 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;
- /* 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));
+ NSLOG(layout, DEBUG,
+ "split_box %p len: %" PRIsizet " \"%.*s\"",
+ split_box,
+ split_box->length,
+ (int)split_box->length,
+ split_box->text);
+ NSLOG(layout, DEBUG,
+ " new_box %p len: %" PRIsizet " \"%.*s\"",
+ c2,
+ c2->length,
+ (int)c2->length,
+ c2->text);
- /* Find box's overflow properties */
- if (box->style) {
- overflow_x = css_computed_overflow_x(box->style);
- overflow_y = css_computed_overflow_y(box->style);
- }
+ return true;
+}
- /* 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 &&
- (overflow_x != CSS_OVERFLOW_VISIBLE ||
- overflow_y != 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;
+/**
+ * Compute dimensions of box, margins, paddings, and borders for a floating
+ * element using shrink-to-fit. Also used for inline-blocks.
+ *
+ * \param len_ctx CSS length conversion context for document.
+ * \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.
+ */
+static void
+layout_float_find_dimensions(
+ const nscss_len_ctx *len_ctx,
+ int available_width,
+ const css_computed_style *style,
+ struct box *box)
+{
+ int width, height, max_width, min_width, max_height, min_height;
+ int *margin = box->margin;
+ int *padding = box->padding;
+ struct box_border *border = box->border;
+ enum css_overflow_e overflow_x = css_computed_overflow_x(style);
+ enum css_overflow_e overflow_y = css_computed_overflow_y(style);
+ int scrollbar_width_x =
+ (overflow_x == CSS_OVERFLOW_SCROLL ||
+ overflow_x == CSS_OVERFLOW_AUTO) ?
+ SCROLLBAR_WIDTH : 0;
+ int scrollbar_width_y =
+ (overflow_y == CSS_OVERFLOW_SCROLL ||
+ overflow_y == CSS_OVERFLOW_AUTO) ?
+ SCROLLBAR_WIDTH : 0;
- wtype = css_computed_width(box->style, &width,
- &unit);
+ layout_find_dimensions(len_ctx, available_width, -1, box, style,
+ &width, &height, &max_width, &min_width,
+ &max_height, &min_height, margin, padding, border);
- 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 (margin[LEFT] == AUTO)
+ margin[LEFT] = 0;
+ if (margin[RIGHT] == AUTO)
+ margin[RIGHT] = 0;
+
+ if (box->gadget == NULL) {
+ padding[RIGHT] += scrollbar_width_y;
+ padding[BOTTOM] += scrollbar_width_x;
+ }
+
+ 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, min_height, max_height);
+ } 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(len_ctx,
+ size, unit, box->style));
+ }
+ if (box->gadget->type == GADGET_FILE &&
+ height == AUTO) {
+ size = FLTTOFIX(1.5);
+ height = FIXTOINT(nscss_len2px(len_ctx,
+ size, unit, box->style));
+ }
+ }
+ if (box->gadget->type == GADGET_TEXTAREA) {
+ if (width == AUTO) {
+ size = INTTOFIX(10);
+ width = FIXTOINT(nscss_len2px(len_ctx,
+ size, unit, box->style));
+ }
+ if (height == AUTO) {
+ size = INTTOFIX(4);
+ height = FIXTOINT(nscss_len2px(len_ctx,
+ size, unit, box->style));
}
- 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);
}
+ } else if (width == AUTO) {
+ /* CSS 2.1 section 10.3.5 */
+ width = min(max(box->min_width, available_width),
+ box->max_width);
- /* Position box: horizontal. */
- box->x = box->parent->padding[LEFT] + box->margin[LEFT] +
- box->border[LEFT].width;
- cx += box->x;
+ /* 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(len_ctx, box->style, LEFT,
+ true, true, true, &fixed, &frac);
+ calculate_mbp_width(len_ctx, box->style, RIGHT,
+ true, true, true, &fixed, &frac);
+ if (fixed < 0)
+ fixed = 0;
- /* Position box: vertical. */
- if (box->border[TOP].width) {
- box->y += box->border[TOP].width;
- cy += box->border[TOP].width;
+ width -= fixed;
}
- /* 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;
+ if (max_width >= 0 && width > max_width) width = max_width;
+ if (min_width > 0 && width < min_width) width = min_width;
- /* Current margin has been applied. */
- in_margin = false;
- max_pos_margin = max_neg_margin = 0;
- }
+ } else {
+ if (max_width >= 0 && width > max_width) width = max_width;
+ if (min_width > 0 && width < min_width) width = min_width;
+ width -= scrollbar_width_y;
+ }
- /* Handle clearance */
- if (box->type != BOX_INLINE_CONTAINER &&
- (y > 0) && (cy < y)) {
- /* box clears something*/
- box->y += y - cy;
- cy = y;
- }
+ box->width = width;
+ box->height = height;
- /* Unless the box has an overflow style of visible, the box
- * establishes a new block context. */
- if (box->type == BOX_BLOCK && box->style &&
- (overflow_x != CSS_OVERFLOW_VISIBLE ||
- overflow_y != CSS_OVERFLOW_VISIBLE)) {
+ if (margin[TOP] == AUTO)
+ margin[TOP] = 0;
+ if (margin[BOTTOM] == AUTO)
+ margin[BOTTOM] = 0;
+}
- layout_block_context(box, viewport_height, content);
- cy += box->padding[TOP];
+/**
+ * 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
+ */
+static 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(&content->len_ctx, 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;
+}
- 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;
+/**
+ * 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
+ */
+static void
+place_float_below(struct box *c, int width, int cx, int y, struct box *cont)
+{
+ int x0, x1, yy;
+ struct box *left;
+ struct box *right;
- /* Skip children, because they are done in the new
- * block context */
- goto advance_to_next_box;
+ yy = y > cont->cached_place_below_level ?
+ y : cont->cached_place_below_level;
+
+ NSLOG(layout, DEBUG,
+ "c %p, width %i, cx %i, y %i, cont %p", c,
+ width, cx, y, cont);
+
+ 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));
- NSLOG(layout, DEBUG, "box %p, cx %i, cy %i", box, cx, cy);
+ if (c->type == BOX_FLOAT_LEFT) {
+ c->x = x0;
+ } else {
+ c->x = x1 - c->width;
+ }
+ c->y = y;
+ cont->cached_place_below_level = y;
+}
- /* 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;
+/**
+ * Calculate line height from a style.
+ */
+static int line_height(
+ const nscss_len_ctx *len_ctx,
+ 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;
- } 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;
+ assert(style);
- wtype = css_computed_width(box->style,
- &width, &unit);
+ 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;
+ }
- 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;
- }
+ if (lhtype == CSS_LINE_HEIGHT_NUMBER ||
+ lhunit == CSS_UNIT_PCT) {
+ line_height = nscss_len2px(len_ctx,
+ lhvalue, CSS_UNIT_EM, style);
- /* Advance to next box. */
- if (box->type == BOX_BLOCK && !box->object && !(box->iframe) &&
- box->children) {
- /* Down into children. */
+ if (lhtype != CSS_LINE_HEIGHT_NUMBER)
+ line_height = FDIV(line_height, F_100);
+ } else {
+ assert(lhunit != CSS_UNIT_PCT);
- if (box == margin_collapse) {
- /* Current margin collapsed though to this box.
- * Unset margin_collapse. */
- margin_collapse = NULL;
- }
+ line_height = nscss_len2px(len_ctx,
+ lhvalue, lhunit, style);
+ }
- 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];
+ return FIXTOINT(line_height);
+}
- 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;
+/**
+ * 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
+ */
+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)
+{
+ 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 gui_layout_table *font_func = content->font_func;
+ plot_font_style_t fstyle;
- advance_to_next_box:
- if (!box->next) {
- /* No more siblings:
- * up to first ancestor with a sibling. */
+ NSLOG(layout, DEBUG,
+ "first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i",
+ first,
+ (int)first->length,
+ first->text,
+ *width,
+ *y,
+ cx,
+ cy);
- do {
- if (box == margin_collapse) {
- /* Current margin collapsed though to
- * this box. Unset margin_collapse. */
- margin_collapse = NULL;
- }
+ /* 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;
- /* 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];
+ if (indent)
+ x0 += layout_text_indent(&content->len_ctx,
+ first->parent->parent->style, *width);
- box = box->parent;
- if (box == block)
- break;
+ if (x1 < x0)
+ x1 = x0;
- /* 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;
- }
+ /* 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(&content->len_ctx,
+ 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;
- if (box->height == AUTO) {
- box->height = y - box->padding[TOP];
+ /* 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() */
- if (box->type == BOX_BLOCK)
- layout_block_add_scrollbar(box,
- BOTTOM);
- } else
- cy += box->height -
- (y - box->padding[TOP]);
+ NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
- /* 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;
+ for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) {
+ int min_width, max_width, min_height, max_height;
- } while (box->next == NULL);
- if (box == block)
- break;
- }
+ 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);
- /* To next sibling. */
- if (box == margin_collapse) {
- /* Current margin collapsed though to this box.
- * Unset margin_collapse. */
- margin_collapse = NULL;
- }
+ NSLOG(layout, DEBUG, "pass 1: b %p, x %i", b, x);
- 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;
- }
+ if (b->type == BOX_BR)
+ break;
- /* Account for bottom margin of last contained block */
- cy += max_pos_margin - max_neg_margin;
+ 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;
- /* 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;
- }
+ assert(b->style != NULL);
+ font_plot_style_from_css(&content->len_ctx, b->style, &fstyle);
- if (block->height == AUTO) {
- block->height = cy - block->padding[TOP];
- if (block->type == BOX_BLOCK)
- layout_block_add_scrollbar(block, BOTTOM);
- }
+ x += space_after;
- if (block->style && css_computed_position(block->style) !=
- CSS_POSITION_ABSOLUTE) {
- /* Block is in normal flow */
- layout_apply_minmax_height(block, NULL);
- }
+ 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 (block->gadget &&
- (block->gadget->type == GADGET_TEXTAREA ||
- block->gadget->type == GADGET_PASSWORD ||
- block->gadget->type == GADGET_TEXTBOX)) {
- int ta_width = block->padding[LEFT] + block->width +
- block->padding[RIGHT];
- int ta_height = block->padding[TOP] + block->height +
- block->padding[BOTTOM];
- textarea_set_layout(block->gadget->data.text.ta,
- ta_width, ta_height,
- block->padding[TOP], block->padding[RIGHT],
- block->padding[BOTTOM], block->padding[LEFT]);
- }
-
- return true;
-}
-
-
-/**
- * Calculate line height from a style.
- */
-static 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);
-}
-
-
-/**
- * Layout list markers.
- */
-static void
-layout_lists(struct box *box,
- const struct gui_layout_table *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->width(&fstyle,
- marker->text,
- marker->length,
- &marker->width);
- marker->flags |= MEASURED;
- }
- marker->x = -marker->width;
- marker->y = 0;
- marker->height = line_height(marker->style);
+ if (b->type == BOX_INLINE) {
+ /* calculate borders, margins, and padding */
+ layout_find_dimensions(&content->len_ctx,
+ *width, -1, b, b->style, 0, 0, 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 {
- marker->x = 0;
- marker->y = 0;
- marker->width = 0;
- marker->height = 0;
+ x += b->padding[RIGHT] +
+ b->border[RIGHT].width +
+ b->margin[RIGHT];
}
- /* Gap between marker and content */
- marker->x -= 4;
- }
- layout_lists(child, font_func);
- }
-}
-
-
-/**
- * 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.
- */
-static 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;
- }
+ } else if (b->type == BOX_INLINE_END) {
+ b->width = 0;
+ if (b->space == UNKNOWN_WIDTH) {
+ font_func->width(&fstyle, " ", 1, &b->space);
+ /** \todo handle errors */
+ }
+ space_after = b->space;
- /* 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));
+ x += b->padding[RIGHT] + b->border[RIGHT].width +
+ b->margin[RIGHT];
+ continue;
}
- } 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;
- }
+ 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(&content->len_ctx,
+ b->style ? b->style :
+ b->parent->parent->style);
+ if (height < b->height)
+ height = b->height;
- /* 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;
- }
-}
+ if (!b->text) {
+ b->width = 0;
+ space_after = 0;
+ continue;
+ }
+ if (b->width == UNKNOWN_WIDTH) {
+ /** \todo handle errors */
-/**
- * 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
- */
-static 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;
+ /* 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;
- assert(box->type == BOX_BLOCK || box->type == BOX_TABLE ||
- box->type == BOX_INLINE_BLOCK);
+ for (o = b->parent->parent->gadget->
+ data.select.items; o;
+ o = o->next) {
+ int opt_width;
+ font_func->width(&fstyle,
+ o->text,
+ strlen(o->text),
+ &opt_width);
- /* 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 (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->width(&fstyle, b->text,
+ b->length, &b->width);
+ b->flags |= MEASURED;
+ }
+ }
- 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,
- 0, 0, margin, padding, border);
- box->float_container = NULL;
-
- /* 10.3.7 */
- NSLOG(layout, DEBUG,
- "%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);
-
-
- 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 (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 (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 (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 (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 (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 (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];
- }
- }
-
- NSLOG(layout, DEBUG,
- "%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);
-
- 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 */
- NSLOG(layout, DEBUG,
- "%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);
-
- 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];
- }
- }
-
- NSLOG(layout, DEBUG,
- "%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);
-
- 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;
-}
-
-
-/**
- * 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
- */
-static 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 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->width(&fstyle, b->text,
+ b->length, &b->width);
+ b->flags |= MEASURED;
}
- if (!layout_position_absolute(c, containing_block,
- cx + px, cy + py, content))
- return false;
+
+ x += b->width;
+ if (b->space == UNKNOWN_WIDTH) {
+ font_func->width(&fstyle, " ", 1, &b->space);
+ /** \todo handle errors */
+ }
+ space_after = b->space;
+ continue;
}
- }
- return true;
-}
+ space_after = 0;
+ /* inline replaced, 10.3.2 and 10.6.2 */
+ assert(b->style);
-/**
- * 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.
- */
-static void layout_compute_relative_offset(struct box *box, int *x, int *y)
-{
- int left, right, top, bottom;
- struct box *containing_block;
+ layout_find_dimensions(&content->len_ctx,
+ *width, -1, b, b->style,
+ &b->width, &b->height,
+ &max_width, &min_width,
+ &max_height, &min_height,
+ NULL, NULL, NULL);
- assert(box && box->parent && box->style &&
- css_computed_position(box->style) ==
- CSS_POSITION_RELATIVE);
+ if (b->object && !(b->flags & REPLACE_DIM)) {
+ layout_get_object_dimensions(b, &b->width, &b->height,
+ min_width, max_width,
+ min_height, max_height);
+ } 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;
- 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;
- }
+ /* 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(
+ &content->len_ctx, INTTOFIX(1),
+ CSS_UNIT_EM, b->style));
+ if (b->height == AUTO)
+ b->height = FIXTOINT(nscss_len2px(
+ &content->len_ctx, INTTOFIX(1),
+ CSS_UNIT_EM, b->style));
+ }
- layout_compute_offsets(box, containing_block,
- &top, &right, &bottom, &left);
+ /* 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);
- 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;
+ content_reformat(b->object, false, b->width, b->height);
+
+ if (htype == CSS_HEIGHT_AUTO)
+ b->height = content_get_height(b->object);
}
- }
- assert(left == -right);
+ if (height < b->height)
+ height = b->height;
- if (top == AUTO && bottom == AUTO) {
- top = bottom = 0;
- } else if (top == AUTO) {
- top = -bottom;
- } else {
- /* bottom is AUTO, or neither are AUTO */
- bottom = -top;
+ x += b->width;
}
- NSLOG(layout, DEBUG, "left %i, right %i, top %i, bottom %i", left,
- right, top, bottom);
+ /* 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;
- *x = left;
- *y = top;
-}
+ if (indent)
+ x0 += layout_text_indent(&content->len_ctx,
+ first->parent->parent->style, *width);
+ if (x1 < x0)
+ x1 = x0;
-/**
- * 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"
- */
-static 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" */
+ space_after = space_before = 0;
- /**\todo ensure containing box is large enough after moving boxes */
+ /* pass 2: place boxes in line: loop body executed at least once */
- assert(root);
+ NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
- /* Normal children */
- for (box = root->children; box; box = box->next) {
+ for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) {
- if (box->type == BOX_TEXT)
- continue;
+ NSLOG(layout, DEBUG, "pass 2: b %p, x %i", b, x);
- /* 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;
+ 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;
- /* 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;
+ } 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(
+ &content->len_ctx,
+ b->style, &fstyle);
+ /** \todo handle errors */
+ font_func->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;
- 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;
+ /* float */
+ NSLOG(layout, DEBUG, "float %p", b);
- box->x += x;
- box->y += y;
+ d = b->children;
+ d->float_children = 0;
+ d->cached_place_below_level = 0;
+ b->float_container = d->float_container = cont;
- /* 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;
- }
- }
- }
-}
+ if (!layout_float(d, *width, content))
+ return false;
+ NSLOG(layout, DEBUG,
+ "%p : %d %d",
+ d,
+ d->margin[TOP],
+ d->border[TOP].width);
-/* exported function documented in render/layout.h */
-bool layout_document(html_content *content, int width, int height)
-{
- bool ret;
- struct box *doc = content->layout;
- const struct gui_layout_table *font_func = content->font_func;
+ 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];
- layout_minmax_block(doc, font_func);
+ 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 &&
+ cy >= cont->cached_place_below_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;
+ fcy = (fcy > cont->cached_place_below_level) ?
+ fcy :
+ cont->cached_place_below_level;
+ fy = (fy > fcy) ? fy : fcy;
+ fy = (fy == cy) ? fy + height : fy;
- 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;
+ 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;
- ret = layout_block_context(doc, height, content);
+ 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;
+ }
+ add_float_to_container(cont, b);
- /* 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]);
+ split_box = 0;
+ }
}
- 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);
+ if (x1 - x0 < x && split_box) {
+ /* the last box went over the end */
+ size_t split = 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;
- return ret;
-}
+ x = x_previous;
+ if (!no_wrap &&
+ (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) {
-/**
- * Insert a float into a container.
- *
- * \param cont block formatting context block, used to contain float
- * \param b box to add to float
- *
- * This sorts floats in order of descending bottom edges.
- */
-static void add_float_to_container(struct box *cont, struct box *b)
-{
- struct box *box = cont->float_children;
- int b_bottom = b->y + b->height;
+ font_plot_style_from_css(&content->len_ctx,
+ split_box->style, &fstyle);
+ /** \todo handle errors */
+ font_func->split(&fstyle,
+ split_box->text,
+ split_box->length,
+ x1 - x0 - x - space_before,
+ &split,
+ &w);
+ }
- assert(b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT);
+ /* split == 0 implies that text can't be split */
- if (box == NULL) {
- /* No other float children */
- b->next_float = NULL;
- cont->float_children = b;
- return;
- } else if (b_bottom >= box->y + box->height) {
- /* Goes at start of list */
- b->next_float = cont->float_children;
- cont->float_children = b;
- } else {
- struct box *prev = NULL;
- while (box != NULL && b_bottom < box->y + box->height) {
- prev = box;
- box = box->next_float;
- }
- if (prev != NULL) {
- b->next_float = prev->next_float;
- prev->next_float = b;
- }
- }
-}
+ if (split == 0)
+ w = split_box->width;
-/**
- * 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 gui_layout_table *font_func = content->font_func;
- bool space = (split_box->text[new_length] == ' ');
- int used_length = new_length + (space ? 1 : 0);
+ NSLOG(layout, DEBUG,
+ "splitting: split_box %p \"%.*s\", spilt %"PRIsizet
+ ", w %i, left %p, right %p, inline_count %u",
+ split_box,
+ (int)split_box->length,
+ split_box->text,
+ split,
+ w,
+ left,
+ right,
+ inline_count);
- if ((space && space_width == 0) || space_width == UNKNOWN_WIDTH) {
- /* We're need to add a space, and we don't know how big
- * it's to be, OR we have a space of unknown width anyway;
- * Calculate space width */
- font_func->width(fstyle, " ", 1, &space_width);
- }
+ if ((split == 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 (split == 0 || split == split_box->length) {
+ /* 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, split, w))
+ return false;
+ b = split_box->next;
+ }
+ x += space_before + w;
- if (split_box->space == UNKNOWN_WIDTH)
- split_box->space = space_width;
- if (!space)
- space_width = 0;
+ NSLOG(layout, DEBUG, "forcing");
- /* Create clone of split_box, c2 */
- c2 = talloc_memdup(content->bctx, split_box, sizeof *c2);
- if (!c2)
- return false;
- c2->flags |= CLONE;
+ } else if ((split == 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) {
- /* Set remaining text in c2 */
- c2->text += used_length;
+ NSLOG(layout, DEBUG,
+ "cy %i, left->y %i, left->height %i",
+ cy,
+ left->y,
+ left->height);
- /* 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 - used_length;
+ used_height = left->y + left->height - cy + 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;
+ NSLOG(layout, DEBUG, "used_height %i",
+ used_height);
- /* 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;
+ }
+ if (right && used_height <
+ right->y + right->height - cy + 1)
+ used_height = right->y + right->height - cy + 1;
- NSLOG(layout, DEBUG,
- "split_box %p len: %" PRIsizet " \"%.*s\"",
- split_box,
- split_box->length,
- (int)split_box->length,
- split_box->text);
- NSLOG(layout, DEBUG,
- " new_box %p len: %" PRIsizet " \"%.*s\"",
- c2,
- c2->length,
- (int)c2->length,
- c2->text);
+ if (used_height < 0)
+ used_height = 0;
- return true;
-}
+ b = split_box;
+ NSLOG(layout, DEBUG, "moving below float");
-/**
- * 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.
- */
-static void
-layout_float_find_dimensions(int available_width,
- const css_computed_style *style,
- struct box *box)
-{
- int width, height, max_width, min_width, max_height, min_height;
- int *margin = box->margin;
- int *padding = box->padding;
- struct box_border *border = box->border;
- enum css_overflow_e overflow_x = css_computed_overflow_x(style);
- enum css_overflow_e overflow_y = css_computed_overflow_y(style);
- int scrollbar_width_x =
- (overflow_x == CSS_OVERFLOW_SCROLL ||
- overflow_x == CSS_OVERFLOW_AUTO) ?
- SCROLLBAR_WIDTH : 0;
- int scrollbar_width_y =
- (overflow_y == CSS_OVERFLOW_SCROLL ||
- overflow_y == CSS_OVERFLOW_AUTO) ?
- SCROLLBAR_WIDTH : 0;
+ } else if (split == 0 || x1 - x0 <= x + space_before + w) {
+ /* first word of box doesn't fit so leave box for next
+ * line */
+ b = split_box;
- layout_find_dimensions(available_width, -1, box, style, &width, &height,
- &max_width, &min_width, &max_height, &min_height,
- margin, padding, border);
+ NSLOG(layout, DEBUG, "leaving for next line");
- if (margin[LEFT] == AUTO)
- margin[LEFT] = 0;
- if (margin[RIGHT] == AUTO)
- margin[RIGHT] = 0;
+ } else {
+ /* fit as many words as possible */
+ assert(split != 0);
- if (box->gadget == NULL) {
- padding[RIGHT] += scrollbar_width_y;
- padding[BOTTOM] += scrollbar_width_x;
- }
+ NSLOG(layout, DEBUG,
+ "'%.*s' %i %"PRIsizet" %i",
+ (int)split_box->length, split_box->text,
+ x1 - x0, split, w);
- 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, min_height, max_height);
- } 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;
+ if (split != split_box->length) {
+ if (!layout_text_box_split(content, &fstyle,
+ split_box, split, w))
+ return false;
+ b = split_box->next;
+ }
+ x += space_before + w;
- /* Give sensible dimensions to gadgets, with auto width/height,
- * that don't shrink to fit contained text. */
- assert(box->style);
+ NSLOG(layout, DEBUG, "fitting words");
- 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));
- }
- 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;
+ move_y = true;
+ }
- width -= fixed;
+ /* 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;
+ }
- if (max_width >= 0 && width > max_width) width = max_width;
- if (min_width > 0 && width < min_width) width = min_width;
+ for (d = first; d != b; d = d->next) {
+ d->flags &= ~NEW_LINE;
- } else {
- if (max_width >= 0 && width > max_width) width = max_width;
- if (min_width > 0 && width < min_width) width = min_width;
- width -= scrollbar_width_y;
+ 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;
+ }
}
- box->width = width;
- box->height = height;
+ first->flags |= NEW_LINE;
- if (margin[TOP] == AUTO)
- margin[TOP] = 0;
- if (margin[BOTTOM] == AUTO)
- margin[BOTTOM] = 0;
-}
+ 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;
+ }
+ }
+ }
-/**
- * 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
- */
-static 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);
+ /* 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;
}
/**
- * Position a float in the first available space.
+ * Layout lines of text or inline boxes with floats.
*
- * \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
+ * \param box inline container box
+ * \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
*/
-static void
-place_float_below(struct box *c, int width, int cx, int y, struct box *cont)
+static bool layout_inline_container(struct box *inline_container, int width,
+ struct box *cont, int cx, int cy, html_content *content)
{
- int x0, x1, yy;
- struct box *left;
- struct box *right;
+ bool first_line = true;
+ bool has_text_children;
+ struct box *c, *next;
+ int y = 0;
+ int curwidth,maxwidth = width;
- yy = y > cont->cached_place_below_level ?
- y : cont->cached_place_below_level;
+ assert(inline_container->type == BOX_INLINE_CONTAINER);
NSLOG(layout, DEBUG,
- "c %p, width %i, cx %i, y %i, cont %p", c,
- width, cx, y, cont);
+ "inline_container %p, width %i, cont %p, cx %i, cy %i",
+ inline_container,
+ width,
+ cont,
+ cx,
+ cy);
- 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;
+
+ 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);
}
- } while ((left != 0 || right != 0) && (c->width > x1 - x0));
- if (c->type == BOX_FLOAT_LEFT) {
- c->x = x0;
- } else {
- c->x = x1 - c->width;
+ if ((!c->object && !(c->flags & REPLACE_DIM) &&
+ !(c->flags & IFRAME) &&
+ c->text && (c->length || is_pre)) ||
+ c->type == BOX_BR)
+ has_text_children = true;
}
- c->y = y;
- cont->cached_place_below_level = y;
+
+ /** \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; ) {
+
+ NSLOG(layout, DEBUG, "c %p", c);
+
+ 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;
}
/**
- * Position a line of boxes in inline formatting context.
+ * Layout a block 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
+ * \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.
*/
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)
+layout_block_context(struct box *block,
+ int viewport_height,
+ html_content *content)
{
- 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 gui_layout_table *font_func = content->font_func;
- plot_font_style_t fstyle;
+ 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 */
- NSLOG(layout, DEBUG,
- "first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i",
- first,
- (int)first->length,
- first->text,
- *width,
- *y,
- cx,
- cy);
+ 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->cached_place_below_level = 0;
+ 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,
+ INT_MIN, INT_MAX);
+ return true;
+ } else if (block->flags & REPLACE_DIM) {
+ return true;
+ }
- /* 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;
+ /* 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(
+ &content->len_ctx, gadget_size,
+ gadget_unit, block->style));
+ }
- if (indent)
- x0 += layout_text_indent(first->parent->parent->style, *width);
+ 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];
- if (x1 < x0)
- x1 = x0;
+ /* 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) {
+ enum css_overflow_e overflow_x = CSS_OVERFLOW_VISIBLE;
+ enum css_overflow_e overflow_y = CSS_OVERFLOW_VISIBLE;
- /* 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;
+ assert(box->type == BOX_BLOCK || box->type == BOX_TABLE ||
+ box->type == BOX_INLINE_CONTAINER);
- /* 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() */
+ /* 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.
+ */
- NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
+ 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(
+ &content->len_ctx, box, block,
+ viewport_height,
+ &max_pos_margin, &max_neg_margin);
+ /* We have a margin that has not yet been applied. */
+ in_margin = true;
+ }
- for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) {
- int min_width, max_width, min_height, max_height;
+ /* 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));
- 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);
+ /* Find box's overflow properties */
+ if (box->style) {
+ overflow_x = css_computed_overflow_x(box->style);
+ overflow_y = css_computed_overflow_y(box->style);
+ }
+ /* Blocks establishing a block formatting context get minimum
+ * left and right margins to avoid any floats. */
+ lm = rm = 0;
- NSLOG(layout, DEBUG, "pass 1: b %p, x %i", b, x);
+ if (box->type == BOX_BLOCK || box->flags & IFRAME) {
+ if (!box->object && !(box->flags & IFRAME) &&
+ !(box->flags & REPLACE_DIM) &&
+ box->style &&
+ (overflow_x != CSS_OVERFLOW_VISIBLE ||
+ overflow_y != 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(&content->len_ctx,
+ 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 (b->type == BOX_BR)
- break;
+ 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);
+ }
- 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;
+ /* Position box: horizontal. */
+ box->x = box->parent->padding[LEFT] + box->margin[LEFT] +
+ box->border[LEFT].width;
+ cx += box->x;
- assert(b->style != NULL);
- font_plot_style_from_css(b->style, &fstyle);
+ /* Position box: vertical. */
+ if (box->border[TOP].width) {
+ box->y += box->border[TOP].width;
+ cy += box->border[TOP].width;
+ }
- x += space_after;
+ /* Vertical margin */
+ if (((box->type == BOX_BLOCK && (box->flags & HAS_HEIGHT)) ||
+ box->type == BOX_TABLE ||
+ (box->type == BOX_INLINE_CONTAINER &&
+ !box_is_first_child(box)) ||
+ 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;
- 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;
+ /* Current margin has been applied. */
+ in_margin = false;
+ max_pos_margin = max_neg_margin = 0;
}
- if (b->type == BOX_INLINE) {
- /* calculate borders, margins, and padding */
- layout_find_dimensions(*width, -1, b, b->style, 0, 0,
- 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->width(&fstyle, " ", 1, &b->space);
- /** \todo handle errors */
+ /* 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 &&
+ (overflow_x != CSS_OVERFLOW_VISIBLE ||
+ overflow_y != 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);
}
- space_after = b->space;
- x += b->padding[RIGHT] + b->border[RIGHT].width +
- b->margin[RIGHT];
- continue;
+ 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;
}
- 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;
+ NSLOG(layout, DEBUG, "box %p, cx %i, cy %i", box, cx, cy);
- if (!b->text) {
- b->width = 0;
- space_after = 0;
- continue;
- }
+ /* Layout (except tables). */
+ if (box->object) {
+ if (!layout_block_object(box))
+ return false;
- if (b->width == UNKNOWN_WIDTH) {
- /** \todo handle errors */
+ } 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;
- /* 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;
+ } 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;
- for (o = b->parent->parent->gadget->
- data.select.items; o;
- o = o->next) {
- int opt_width;
- font_func->width(&fstyle,
- o->text,
- strlen(o->text),
- &opt_width);
+ wtype = css_computed_width(box->style,
+ &width, &unit);
- 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->width(&fstyle, b->text,
- b->length, &b->width);
- b->flags |= MEASURED;
- }
+ 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;
+ }
- /* 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->width(&fstyle, b->text,
- b->length, &b->width);
- b->flags |= MEASURED;
- }
+ /* Advance to next box. */
+ if (box->type == BOX_BLOCK && !box->object && !(box->iframe) &&
+ box->children) {
+ /* Down into children. */
- x += b->width;
- if (b->space == UNKNOWN_WIDTH) {
- font_func->width(&fstyle, " ", 1, &b->space);
- /** \todo handle errors */
+ if (box == margin_collapse) {
+ /* Current margin collapsed though to this box.
+ * Unset margin_collapse. */
+ margin_collapse = NULL;
}
- space_after = b->space;
+
+ 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);
}
- space_after = 0;
+ 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;
- /* inline replaced, 10.3.2 and 10.6.2 */
- assert(b->style);
+ advance_to_next_box:
+ if (!box->next) {
+ /* No more siblings:
+ * up to first ancestor with a sibling. */
- layout_find_dimensions(*width, -1, b, b->style,
- &b->width, &b->height, &max_width, &min_width,
- &max_height, &min_height, NULL, NULL, NULL);
+ do {
+ if (box == margin_collapse) {
+ /* Current margin collapsed though to
+ * this box. Unset margin_collapse. */
+ margin_collapse = NULL;
+ }
- if (b->object && !(b->flags & REPLACE_DIM)) {
- layout_get_object_dimensions(b, &b->width, &b->height,
- min_width, max_width,
- min_height, max_height);
- } 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;
+ /* 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];
- /* 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));
- }
+ box = box->parent;
+ if (box == block)
+ break;
- /* 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);
+ /* 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;
+ }
- content_reformat(b->object, false, b->width, b->height);
+ if (box->height == AUTO) {
+ box->height = y - box->padding[TOP];
- if (htype == CSS_HEIGHT_AUTO)
- b->height = content_get_height(b->object);
- }
+ if (box->type == BOX_BLOCK)
+ layout_block_add_scrollbar(box,
+ BOTTOM);
+ } else
+ cy += box->height -
+ (y - box->padding[TOP]);
- if (height < b->height)
- height = b->height;
+ /* 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(
+ &content->len_ctx,
+ box, NULL)) {
+ /* Height altered */
+ /* Set current cy */
+ cy += box->height -
+ (y - box->padding[TOP]);
+ }
- x += b->width;
- }
+ 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;
- /* 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;
+ } while (box->next == NULL);
+ if (box == block)
+ break;
+ }
- if (indent)
- x0 += layout_text_indent(first->parent->parent->style, *width);
+ /* To next sibling. */
- if (x1 < x0)
- x1 = x0;
+ if (box == margin_collapse) {
+ /* Current margin collapsed though to this box.
+ * Unset margin_collapse. */
+ margin_collapse = NULL;
+ }
- space_after = space_before = 0;
+ 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];
- /* pass 2: place boxes in line: loop body executed at least once */
+ box = box->next;
+ box->y = y;
+ }
- NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
+ /* Account for bottom margin of last contained block */
+ cy += max_pos_margin - max_neg_margin;
- for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) {
+ /* 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;
+ }
- NSLOG(layout, DEBUG, "pass 2: b %p, x %i", b, x);
+ if (block->height == AUTO) {
+ block->height = cy - block->padding[TOP];
+ if (block->type == BOX_BLOCK)
+ layout_block_add_scrollbar(block, BOTTOM);
+ }
- 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;
+ if (block->style && css_computed_position(block->style) !=
+ CSS_POSITION_ABSOLUTE) {
+ /* Block is in normal flow */
+ layout_apply_minmax_height(&content->len_ctx, block, NULL);
+ }
- } 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);
+ if (block->gadget &&
+ (block->gadget->type == GADGET_TEXTAREA ||
+ block->gadget->type == GADGET_PASSWORD ||
+ block->gadget->type == GADGET_TEXTBOX)) {
+ plot_font_style_t fstyle;
+ int ta_width = block->padding[LEFT] + block->width +
+ block->padding[RIGHT];
+ int ta_height = block->padding[TOP] + block->height +
+ block->padding[BOTTOM];
+ font_plot_style_from_css(&content->len_ctx,
+ block->style, &fstyle);
+ fstyle.background = NS_TRANSPARENT;
+ textarea_set_layout(block->gadget->data.text.ta,
+ &fstyle, ta_width, ta_height,
+ block->padding[TOP], block->padding[RIGHT],
+ block->padding[BOTTOM], block->padding[LEFT]);
+ }
- x_previous = x;
- x += space_after;
- b->x = x;
+ return true;
+}
- 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->width(&fstyle, " ", 1,
- &b->space);
+/**
+ * Layout list markers.
+ */
+static void
+layout_lists(struct box *box,
+ const struct gui_layout_table *font_func,
+ const nscss_len_ctx *len_ctx)
+{
+ 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(len_ctx,
+ marker->style) -
+ marker->height) / 2;
+ } else if (marker->text) {
+ if (marker->width == UNKNOWN_WIDTH) {
+ font_plot_style_from_css(len_ctx,
+ marker->style, &fstyle);
+ font_func->width(&fstyle,
+ marker->text,
+ marker->length,
+ &marker->width);
+ marker->flags |= MEASURED;
}
- space_after = b->space;
+ marker->x = -marker->width;
+ marker->y = 0;
+ marker->height = line_height(len_ctx,
+ marker->style);
} else {
- space_after = 0;
+ marker->x = 0;
+ marker->y = 0;
+ marker->width = 0;
+ marker->height = 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 */
- NSLOG(layout, DEBUG, "float %p", b);
-
- d = b->children;
- d->float_children = 0;
- d->cached_place_below_level = 0;
- b->float_container = d->float_container = cont;
+ /* Gap between marker and content */
+ marker->x -= 4;
+ }
+ layout_lists(child, font_func, len_ctx);
+ }
+}
- if (!layout_float(d, *width, content))
- return false;
- NSLOG(layout, DEBUG,
- "%p : %d %d",
- d,
- d->margin[TOP],
- d->border[TOP].width);
+/**
+ * Compute box offsets for a relatively or absolutely positioned box with
+ * respect to a box.
+ *
+ * \param len_ctx Length conversion context
+ * \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.
+ */
+static void
+layout_compute_offsets(const nscss_len_ctx *len_ctx,
+ 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;
- 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];
+ assert(containing_block->width != UNKNOWN_WIDTH &&
+ containing_block->width != AUTO &&
+ containing_block->height != AUTO);
- 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 &&
- cy >= cont->cached_place_below_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;
- fcy = (fcy > cont->cached_place_below_level) ?
- fcy :
- cont->cached_place_below_level;
- fy = (fy > fcy) ? fy : fcy;
- fy = (fy == cy) ? fy + height : fy;
+ /* 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(len_ctx,
+ value, unit, box->style));
+ }
+ } else {
+ *left = AUTO;
+ }
- 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;
+ /* 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(len_ctx,
+ value, unit, box->style));
+ }
+ } else {
+ *right = AUTO;
+ }
- 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;
- }
- add_float_to_container(cont, b);
+ /* 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(len_ctx,
+ value, unit, box->style));
+ }
+ } else {
+ *top = AUTO;
+ }
- split_box = 0;
+ /* 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(len_ctx,
+ value, unit, box->style));
}
+ } else {
+ *bottom = AUTO;
}
+}
- if (x1 - x0 < x && split_box) {
- /* the last box went over the end */
- size_t split = 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;
+/**
+ * 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
+ */
+static 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;
- if (!no_wrap &&
- (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) {
+ assert(box->type == BOX_BLOCK || box->type == BOX_TABLE ||
+ box->type == BOX_INLINE_BLOCK);
- font_plot_style_from_css(split_box->style, &fstyle);
- /** \todo handle errors */
- font_func->split(&fstyle,
- split_box->text,
- split_box->length,
- x1 - x0 - x - space_before,
- &split,
- &w);
- }
+ /* 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;
- /* split == 0 implies that text can't be split */
+ 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 */
+ }
- if (split == 0)
- w = split_box->width;
+ layout_compute_offsets(&content->len_ctx, 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(&content->len_ctx, available_width, -1,
+ box, box->style, &width, &height,
+ &max_width, &min_width, 0, 0,
+ margin, padding, border);
+ box->float_container = NULL;
- NSLOG(layout, DEBUG,
- "splitting: split_box %p \"%.*s\", spilt %zu, w %i, "
- "left %p, right %p, inline_count %u",
- split_box,
- (int)split_box->length,
- split_box->text,
- split,
- w,
- left,
- right,
- inline_count);
+ /* 10.3.7 */
+ NSLOG(layout, DEBUG,
+ "%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);
- if ((split == 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 (split == 0 || split == split_box->length) {
- /* only one word in this box, or not text
- * or white-space:nowrap */
- b = split_box->next;
+
+ 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 (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 {
- /* cut off first word for this line */
- if (!layout_text_box_split(content, &fstyle,
- split_box, split, w))
- return false;
- b = split_box->next;
+ margin[LEFT] = margin[RIGHT] = space / 2;
}
- x += space_before + w;
-
- NSLOG(layout, DEBUG, "forcing");
+ } 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;
- } else if ((split == 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) {
+ if (left == AUTO && width == AUTO && right != AUTO) {
+ available_width -= right;
- NSLOG(layout, DEBUG,
- "cy %i, left->y %i, left->height %i",
- cy,
- left->y,
- left->height);
+ 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];
- used_height = left->y + left->height - cy + 1;
+ /* Adjust for {min|max}-width */
+ if (max_width >= 0 && width > max_width)
+ width = max_width;
+ if (width < min_width)
+ width = min_width;
- NSLOG(layout, DEBUG, "used_height %i",
- used_height);
+ 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) {
- }
- if (right && used_height <
- right->y + right->height - cy + 1)
- used_height = right->y + right->height - cy + 1;
+ /* 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 (used_height < 0)
- used_height = 0;
+ 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;
- b = split_box;
+ 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];
- NSLOG(layout, DEBUG, "moving below float");
+ /* Adjust for {min|max}-width */
+ if (max_width >= 0 && width > max_width)
+ width = max_width;
+ if (width < min_width)
+ width = min_width;
- } else if (split == 0 || x1 - x0 <= x + space_before + w) {
- /* first word of box doesn't fit so leave box for next
- * line */
- b = split_box;
+ 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) {
- NSLOG(layout, DEBUG, "leaving for next line");
+ /* Adjust for {min|max}-width */
+ if (max_width >= 0 && width > max_width)
+ width = max_width;
+ if (width < min_width)
+ width = min_width;
- } else {
- /* fit as many words as possible */
- assert(split != 0);
+ 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;
- NSLOG(layout, DEBUG, "'%.*s' %i %zu %i",
- (int)split_box->length, split_box->text,
- x1 - x0, split, w);
+ /* Adjust for {min|max}-width */
+ if (max_width >= 0 && width > max_width)
+ width = max_width;
+ if (width < min_width)
+ width = min_width;
- if (split != split_box->length) {
- if (!layout_text_box_split(content, &fstyle,
- split_box, split, w))
- return false;
- b = split_box->next;
- }
- x += space_before + w;
+ } else if (left != AUTO && width != AUTO && right == AUTO) {
- NSLOG(layout, DEBUG, "fitting words");
+ /* Adjust for {min|max}-width */
+ if (max_width >= 0 && width > max_width)
+ width = max_width;
+ if (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];
}
- 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;
+ NSLOG(layout, DEBUG,
+ "%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);
+
+ 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;
- for (d = first; d != b; d = d->next) {
- d->flags &= ~NEW_LINE;
+ 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);
+ }
- 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];
+ /* 10.6.4 */
+ NSLOG(layout, DEBUG,
+ "%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);
- 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;
+ 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];
}
}
- 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;
- }
- }
- }
+ NSLOG(layout, DEBUG,
+ "%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);
- /* 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;
+ 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(&content->len_ctx, box, containing_block);
- if (move_y)
- *y += used_height;
- *next_box = b;
- *width = x; /* return actual width */
return true;
}
-/* exported function documented in render/layout.h */
-bool layout_inline_container(struct box *inline_container, int width,
- struct box *cont, int cx, int cy, html_content *content)
+/**
+ * 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
+ */
+static bool
+layout_position_absolute(struct box *box,
+ struct box *containing_block,
+ 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);
-
- NSLOG(layout, DEBUG,
- "inline_container %p, width %i, cont %p, cx %i, cy %i",
- inline_container,
- width,
- cont,
- cx,
- cy);
-
-
- 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);
+ struct box *c;
- is_pre = (whitespace == CSS_WHITE_SPACE_PRE ||
- whitespace == CSS_WHITE_SPACE_PRE_LINE ||
- whitespace == CSS_WHITE_SPACE_PRE_WRAP);
+ 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;
}
-
- 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; ) {
-
- NSLOG(layout, DEBUG, "c %p", c);
-
- 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;
}
-/* exported function documented in render/layout.h */
-void
-layout_minmax_table(struct box *table, const struct gui_layout_table *font_func)
+/**
+ * Compute a box's relative offset as per CSS 2.1 9.4.3
+ *
+ * \param len_ctx Length conversion context
+ * \param box Box to compute relative offsets for.
+ * \param x Receives relative offset in x.
+ * \param y Receives relative offset in y.
+ */
+static void layout_compute_relative_offset(
+ const nscss_len_ctx *len_ctx,
+ struct box *box,
+ int *x,
+ int *y)
{
- 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;
+ int left, right, top, bottom;
+ struct box *containing_block;
- /* check if the widths have already been calculated */
- if (table->max_width != UNKNOWN_MAX_WIDTH)
- return;
+ assert(box && box->parent && box->style &&
+ css_computed_position(box->style) ==
+ CSS_POSITION_RELATIVE);
- /* 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;
+ 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(len_ctx, 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;
+ }
}
- /* 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);
+ assert(left == -right);
- border_spacing_h = FIXTOINT(nscss_len2px(h, hu, table->style));
+ if (top == AUTO && bottom == AUTO) {
+ top = bottom = 0;
+ } else if (top == AUTO) {
+ top = -bottom;
+ } else {
+ /* bottom is AUTO, or neither are AUTO */
+ bottom = -top;
}
- /* 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);
+ NSLOG(layout, DEBUG, "left %i, right %i, top %i, bottom %i", left,
+ right, top, bottom);
- if (cell->columns != 1)
- continue;
+ *x = left;
+ *y = top;
+}
- layout_minmax_block(cell, font_func);
- i = cell->start_column;
- if (col[i].positioned)
- continue;
+/**
+ * Adjust positions of relatively positioned boxes.
+ *
+ * \param len_ctx Length conversion context
+ * \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"
+ */
+static void
+layout_position_relative(
+ const nscss_len_ctx *len_ctx,
+ 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" */
- /* 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;
- }
+ /**\todo ensure containing box is large enough after moving boxes */
- /* 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;
+ assert(root);
- if (cell->columns == 1)
- continue;
+ /* Normal children */
+ for (box = root->children; box; box = box->next) {
- layout_minmax_block(cell, font_func);
- i = cell->start_column;
+ if (box->type == BOX_TEXT)
+ continue;
- /* 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;
+ /* If relatively positioned, get offsets */
+ if (box->style && css_computed_position(box->style) ==
+ CSS_POSITION_RELATIVE)
+ layout_compute_relative_offset(
+ len_ctx, box, &x, &y);
+ else
+ x = y = 0;
- /* 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;
- }
+ /* 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;
}
}
}
- /* 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;
+ if (box->float_children) {
+ fn = box;
+ fnx = fny = 0;
+ } else {
+ fn = fp;
+ fnx = fx + x;
+ fny = fy + y;
}
- }
- for (i = 0; i != table->columns; i++) {
- if (col[i].max < col[i].min) {
- box_dump(stderr, table, 0, true);
- assert(0);
- }
- table_min += col[i].min;
- table_max += col[i].max;
- }
+ /* recurse first */
+ layout_position_relative(len_ctx, box, fn, fnx, fny);
- /* 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;
- }
+ /* Ignore things we're not interested in. */
+ if (!box->style || (box->style &&
+ css_computed_position(box->style) !=
+ CSS_POSITION_RELATIVE))
+ continue;
- /* 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;
+ box->x += x;
+ box->y += y;
- assert(0 <= table->min_width && table->min_width <= table->max_width);
+ /* 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;
+ }
+ }
+ }
}
/**
* Find a box's bounding box relative to itself, i.e. the box's border edge box
*
+ * \param len_ctx Length conversion context
* \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
@@ -5103,9 +5183,11 @@ layout_minmax_table(struct box *table, const struct gui_layout_table *font_func)
* \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)
+layout_get_box_bbox(
+ const nscss_len_ctx *len_ctx,
+ 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;
@@ -5125,7 +5207,8 @@ layout_get_box_bbox(struct box *box,
int text_height;
css_computed_font_size(box->style, &font_size, &font_unit);
- text_height = nscss_len2px(font_size, font_unit, box->style);
+ text_height = nscss_len2px(len_ctx, font_size, font_unit,
+ box->style);
text_height = FIXTOINT(text_height * 3 / 4);
*desc_y0 = (*desc_y0 < -text_height) ? *desc_y0 : -text_height;
}
@@ -5135,16 +5218,19 @@ layout_get_box_bbox(struct box *box,
/**
* 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
+ * \param len_ctx Length conversion context
+ * \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)
+layout_update_descendant_bbox(
+ const nscss_len_ctx *len_ctx,
+ 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;
@@ -5164,7 +5250,8 @@ layout_update_descendant_bbox(struct box *box,
}
/* Get child's border edge */
- layout_get_box_bbox(child, &child_desc_x0, &child_desc_y0,
+ layout_get_box_bbox(len_ctx, child,
+ &child_desc_x0, &child_desc_y0,
&child_desc_x1, &child_desc_y1);
if (overflow_x == CSS_OVERFLOW_VISIBLE &&
@@ -5197,8 +5284,16 @@ layout_update_descendant_bbox(struct box *box,
}
-/* exported function documented in render/layout.h */
-void layout_calculate_descendant_bboxes(struct box *box)
+/**
+ * Recursively calculate the descendant_[xy][01] values for a laid-out box tree
+ * and inform iframe browser windows of their size and position.
+ *
+ * \param len_ctx Length conversion context
+ * \param box tree of boxes to update
+ */
+static void layout_calculate_descendant_bboxes(
+ const nscss_len_ctx *len_ctx,
+ struct box *box)
{
struct box *child;
@@ -5207,7 +5302,8 @@ void layout_calculate_descendant_bboxes(struct box *box)
/* 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,
+ layout_get_box_bbox(len_ctx, box,
+ &box->descendant_x0, &box->descendant_y0,
&box->descendant_x1, &box->descendant_y1);
/* Extend it to contain HTML contents if box is replaced */
@@ -5240,7 +5336,7 @@ void layout_calculate_descendant_bboxes(struct box *box)
child->type == BOX_FLOAT_RIGHT)
continue;
- layout_update_descendant_bbox(box, child,
+ layout_update_descendant_bbox(len_ctx, box, child,
box->x, box->y);
if (child == box->inline_end)
@@ -5258,7 +5354,7 @@ void layout_calculate_descendant_bboxes(struct box *box)
child->type == BOX_FLOAT_RIGHT)
continue;
- layout_calculate_descendant_bboxes(child);
+ layout_calculate_descendant_bboxes(len_ctx, child);
if (box->style && css_computed_overflow_x(box->style) ==
CSS_OVERFLOW_HIDDEN &&
@@ -5266,22 +5362,73 @@ void layout_calculate_descendant_bboxes(struct box *box)
CSS_OVERFLOW_HIDDEN)
continue;
- layout_update_descendant_bbox(box, child, 0, 0);
+ layout_update_descendant_bbox(len_ctx, 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_calculate_descendant_bboxes(len_ctx, child);
- layout_update_descendant_bbox(box, child, 0, 0);
+ layout_update_descendant_bbox(len_ctx, box, child, 0, 0);
}
if (box->list_marker) {
child = box->list_marker;
- layout_calculate_descendant_bboxes(child);
+ layout_calculate_descendant_bboxes(len_ctx, child);
+
+ layout_update_descendant_bbox(len_ctx, box, child, 0, 0);
+ }
+}
+
+
+/* exported function documented in html/layout.h */
+bool layout_document(html_content *content, int width, int height)
+{
+ bool ret;
+ struct box *doc = content->layout;
+ const struct gui_layout_table *font_func = content->font_func;
+
+ layout_minmax_block(doc, font_func, content);
+
+ layout_block_find_dimensions(&content->len_ctx,
+ 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);
- layout_update_descendant_bbox(box, child, 0, 0);
+ /* 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, &content->len_ctx);
+ layout_position_absolute(doc, doc, 0, 0, content);
+ layout_position_relative(&content->len_ctx, doc, doc, 0, 0);
+
+ layout_calculate_descendant_bboxes(&content->len_ctx, doc);
+
+ return ret;
}
diff --git a/render/layout.h b/content/handlers/html/layout.h
similarity index 52%
rename from render/layout.h
rename to content/handlers/html/layout.h
index 78a3002..0811e81 100644
--- a/render/layout.h
+++ b/content/handlers/html/layout.h
@@ -18,15 +18,15 @@
/**
* \file
- * HTML layout (interface).
+ * interface to HTML layout.
*
* 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_
+#ifndef NETSURF_HTML_LAYOUT_H
+#define NETSURF_HTML_LAYOUT_H
struct box;
struct html_content;
@@ -42,35 +42,4 @@ struct gui_layout_table;
*/
bool layout_document(struct html_content *content, int width, int height);
-/**
- * Layout lines of text or inline boxes with floats.
- *
- * \param box inline container box
- * \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 *box, int width, struct box *cont, int cx, int cy, struct html_content *content);
-
-/**
- * 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);
-
-/**
- * Calculate minimum and maximum width of a table.
- *
- * \param table box of type TABLE
- * \param font_func Font functions
- * \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 gui_layout_table *font_func);
-
#endif
diff --git a/render/search.c b/content/handlers/html/search.c
similarity index 97%
rename from render/search.c
rename to content/handlers/html/search.c
index 8f21d87..9ba2957 100644
--- a/render/search.c
+++ b/content/handlers/html/search.c
@@ -17,7 +17,7 @@
* 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)
@@ -38,11 +38,11 @@
#include "netsurf/misc.h"
#include "desktop/gui_internal.h"
-#include "render/box.h"
-#include "render/html.h"
-#include "render/html_internal.h"
-#include "render/search.h"
-#include "render/textplain.h"
+#include "text/textplain.h"
+#include "html/box.h"
+#include "html/html.h"
+#include "html/html_internal.h"
+#include "html/search.h"
#ifndef NOF_ELEMENTS
#define NOF_ELEMENTS(array) (sizeof(array)/sizeof(*(array)))
@@ -128,7 +128,7 @@ 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
@@ -179,11 +179,11 @@ static const char *find_pattern(const char *string, int s_len,
if (p < pattern || *p == '*') {
char ch;
- /* skip any further asterisks; one is the same as many
+ /* 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 we're at the end of the pattern, yes, it matches
*/
if (p >= ep) break;
@@ -193,7 +193,7 @@ static const char *find_pattern(const char *string, int s_len,
ch = *p;
if (ch != '#') {
- /* scan forwards until we find a match for
+ /* scan forwards until we find a match for
this char */
if (!case_sens) ch = toupper(ch);
while (s < es) {
@@ -206,7 +206,7 @@ static const char *find_pattern(const char *string, int s_len,
}
if (s < es) {
- /* remember where we are in case the match
+ /* remember where we are in case the match
fails; we may then resume */
if (top < (int)NOF_ELEMENTS(context)) {
context[top].ss = ss;
@@ -621,13 +621,14 @@ void search_show_all(bool all, struct search_context *context)
if (!a->sel)
continue;
- selection_init(a->sel, html->layout);
+ selection_init(a->sel, html->layout,
+ &html->len_ctx);
} else {
a->sel = selection_create(context->c, false);
if (!a->sel)
continue;
- selection_init(a->sel, NULL);
+ selection_init(a->sel, NULL, NULL);
}
selection_set_start(a->sel, a->start_idx);
diff --git a/render/search.h b/content/handlers/html/search.h
similarity index 95%
rename from render/search.h
rename to content/handlers/html/search.h
index 79d1ee3..5c9408e 100644
--- a/render/search.h
+++ b/content/handlers/html/search.h
@@ -16,8 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _NETSURF_RENDER_SEARCH_H_
-#define _NETSURF_RENDER_SEARCH_H_
+/**
+ * \file
+ * Interface to HTML searching.
+ */
+
+#ifndef NETSURF_HTML_SEARCH_H
+#define NETSURF_HTML_SEARCH_H
#include <ctype.h>
#include <string.h>
diff --git a/render/table.c b/content/handlers/html/table.c
similarity index 71%
rename from render/table.c
rename to content/handlers/html/table.c
index c41b913..5609e8f 100644
--- a/render/table.c
+++ b/content/handlers/html/table.c
@@ -17,8 +17,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Table processing and layout (implementation).
+/**
+ * \file
+ * implementation of HTML table processing and layout.
*/
#include <assert.h>
@@ -28,8 +29,8 @@
#include "utils/talloc.h"
#include "css/utils.h"
-#include "render/box.h"
-#include "render/table.h"
+#include "html/box.h"
+#include "html/table.h"
/* Define to enable verbose table debug */
#undef TABLE_DEBUG
@@ -45,31 +46,57 @@ struct border {
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,
+static void table_used_left_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
+static void table_used_top_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
+static void table_used_right_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
+static void table_used_bottom_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
+static bool table_border_is_more_eyecatching(
+ const nscss_len_ctx *len_ctx,
+ const struct border *a,
+ box_type a_src,
+ const struct border *b,
+ box_type b_src);
+static void table_cell_top_process_table(
+ const nscss_len_ctx *len_ctx,
+ struct box *table,
+ struct border *a,
+ box_type *a_src);
+static bool table_cell_top_process_group(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell,
+ struct box *group,
+ struct border *a,
+ box_type *a_src);
+static bool table_cell_top_process_row(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell,
+ struct box *row,
+ 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
+ * \param len_ctx Length conversion context
+ * \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)
+bool table_calculate_column_types(
+ const nscss_len_ctx *len_ctx,
+ struct box *table)
{
unsigned int i, j;
struct column *col;
@@ -104,12 +131,12 @@ bool table_calculate_column_types(struct box *table)
continue;
i = cell->start_column;
- if (css_computed_position(cell->style) !=
+ if (css_computed_position(cell->style) !=
CSS_POSITION_ABSOLUTE &&
- css_computed_position(cell->style) !=
+ css_computed_position(cell->style) !=
CSS_POSITION_FIXED) {
col[i].positioned = false;
- }
+ }
type = css_computed_width(cell->style, &value, &unit);
@@ -117,8 +144,8 @@ bool table_calculate_column_types(struct box *table)
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));
+ col[i].width = FIXTOINT(nscss_len2px(len_ctx,
+ value, unit, cell->style));
if (col[i].width < 0)
col[i].width = 0;
continue;
@@ -155,7 +182,7 @@ bool table_calculate_column_types(struct box *table)
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) {
@@ -181,8 +208,8 @@ bool table_calculate_column_types(struct box *table)
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) /
+ int width = (FIXTOFLT(nscss_len2px(len_ctx, value, unit,
+ cell->style)) - fixed_width) /
unknown_columns;
if (width < 0)
width = 0;
@@ -235,75 +262,82 @@ bool table_calculate_column_types(struct box *table)
/**
* Calculate used values of border-{trbl}-{style,color,width} for table cells.
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*
* \post \a cell's border array is populated
*/
-void table_used_border_for_cell(struct box *cell)
+void table_used_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
int side;
assert(cell->type == BOX_TABLE_CELL);
- if (css_computed_border_collapse(cell->style) ==
+ 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 =
+ 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));
+ cell->border[LEFT].width =
+ FIXTOINT(nscss_len2px(len_ctx,
+ width, unit, cell->style));
/* Top border */
- cell->border[TOP].style =
+ 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));
+ cell->border[TOP].width =
+ FIXTOINT(nscss_len2px(len_ctx,
+ width, unit, cell->style));
/* Right border */
- cell->border[RIGHT].style =
+ 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));
+ cell->border[RIGHT].width =
+ FIXTOINT(nscss_len2px(len_ctx,
+ width, unit, cell->style));
/* Bottom border */
- cell->border[BOTTOM].style =
+ 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));
+ cell->border[BOTTOM].width =
+ FIXTOINT(nscss_len2px(len_ctx,
+ width, unit, cell->style));
} else {
/* Left border */
- table_used_left_border_for_cell(cell);
+ table_used_left_border_for_cell(len_ctx, cell);
/* Top border */
- table_used_top_border_for_cell(cell);
+ table_used_top_border_for_cell(len_ctx, cell);
/* Right border */
- table_used_right_border_for_cell(cell);
+ table_used_right_border_for_cell(len_ctx, cell);
/* Bottom border */
- table_used_bottom_border_for_cell(cell);
+ table_used_bottom_border_for_cell(len_ctx, cell);
}
- /* Finally, ensure that any borders configured as
+ /* 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 ==
+ cell->border[side].style ==
CSS_BORDER_STYLE_NONE)
cell->border[side].width = 0;
}
@@ -316,9 +350,12 @@ void table_used_border_for_cell(struct box *cell)
/**
* Calculate used values of border-left-{style,color,width}
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*/
-void table_used_left_border_for_cell(struct box *cell)
+void table_used_left_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
@@ -329,7 +366,7 @@ void table_used_left_border_for_cell(struct box *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.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
@@ -342,10 +379,10 @@ void table_used_left_border_for_cell(struct box *cell)
/* Spanned from a previous row in current row group */
for (row = cell->parent; row != NULL; row = row->prev) {
- for (prev = row->children; prev != NULL;
+ for (prev = row->children; prev != NULL;
prev = prev->next) {
- if (prev->start_column +
- prev->columns ==
+ if (prev->start_column +
+ prev->columns ==
cell->start_column)
break;
}
@@ -362,11 +399,12 @@ void table_used_left_border_for_cell(struct box *cell)
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.width = nscss_len2px(len_ctx, 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)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -384,12 +422,13 @@ void table_used_left_border_for_cell(struct box *cell)
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.width = nscss_len2px(len_ctx,
+ 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)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -403,11 +442,12 @@ void table_used_left_border_for_cell(struct box *cell)
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.width = nscss_len2px(len_ctx, 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)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -416,11 +456,12 @@ void table_used_left_border_for_cell(struct box *cell)
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.width = nscss_len2px(len_ctx, 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)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -429,16 +470,19 @@ void table_used_left_border_for_cell(struct box *cell)
/* 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));
+ cell->border[LEFT].width = FIXTOINT(nscss_len2px(len_ctx,
+ a.width, a.unit, cell->style));
}
/**
* Calculate used values of border-top-{style,color,width}
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*/
-void table_used_top_border_for_cell(struct box *cell)
+void table_used_top_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
@@ -449,7 +493,7 @@ void table_used_top_border_for_cell(struct box *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.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
@@ -457,18 +501,18 @@ void table_used_top_border_for_cell(struct box *cell)
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.width = nscss_len2px(len_ctx, 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)) {
+ if (table_border_is_more_eyecatching(len_ctx, &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,
+ while (table_cell_top_process_row(len_ctx, cell, row->prev,
&a, &a_src) == false) {
if (row->prev->prev == NULL) {
/* Consider row group */
@@ -489,26 +533,29 @@ void table_used_top_border_for_cell(struct box *cell)
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.width = nscss_len2px(len_ctx, 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)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ &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);
+ table_cell_top_process_table(len_ctx,
+ group->parent, &a, &a_src);
} else {
/* Process previous group(s) */
- while (table_cell_top_process_group(cell, group->prev,
+ while (table_cell_top_process_group(len_ctx,
+ cell, group->prev,
&a, &a_src) == false) {
if (group->prev->prev == NULL) {
/* Top border of table */
- table_cell_top_process_table(
- group->parent,
+ table_cell_top_process_table(len_ctx,
+ group->parent,
&a, &a_src);
break;
} else {
@@ -521,16 +568,19 @@ void table_used_top_border_for_cell(struct box *cell)
/* 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));
+ cell->border[TOP].width = FIXTOINT(nscss_len2px(len_ctx,
+ a.width, a.unit, cell->style));
}
/**
* Calculate used values of border-right-{style,color,width}
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*/
-void table_used_right_border_for_cell(struct box *cell)
+void table_used_right_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
@@ -541,11 +591,11 @@ void table_used_right_border_for_cell(struct box *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.width = nscss_len2px(len_ctx, 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 !=
+ 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;
@@ -565,12 +615,13 @@ void table_used_right_border_for_cell(struct box *cell)
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.width = nscss_len2px(len_ctx,
+ 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)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -583,13 +634,14 @@ void table_used_right_border_for_cell(struct box *cell)
/* 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,
+ css_computed_border_right_width(group->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, 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)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -597,13 +649,14 @@ void table_used_right_border_for_cell(struct box *cell)
/* 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,
+ css_computed_border_right_width(table->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, table->style);
+ b.width = nscss_len2px(len_ctx, 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)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -612,16 +665,19 @@ void table_used_right_border_for_cell(struct box *cell)
/* 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));
+ cell->border[RIGHT].width = FIXTOINT(nscss_len2px(len_ctx,
+ a.width, a.unit, cell->style));
}
/**
* Calculate used values of border-bottom-{style,color,width}
*
- * \param cell Table cell to consider
+ * \param len_ctx Length conversion context
+ * \param cell Table cell to consider
*/
-void table_used_bottom_border_for_cell(struct box *cell)
+void table_used_bottom_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell)
{
struct border a, b;
box_type a_src, b_src;
@@ -632,7 +688,7 @@ void table_used_bottom_border_for_cell(struct box *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.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
a.unit = CSS_UNIT_PX;
a_src = BOX_TABLE_CELL;
@@ -656,11 +712,12 @@ void table_used_bottom_border_for_cell(struct box *cell)
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.width = nscss_len2px(len_ctx, 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)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -668,13 +725,14 @@ void table_used_bottom_border_for_cell(struct box *cell)
/* 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,
+ css_computed_border_bottom_width(group->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, group->style);
+ b.width = nscss_len2px(len_ctx, 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)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
a_src = b_src;
}
@@ -682,13 +740,14 @@ void table_used_bottom_border_for_cell(struct box *cell)
/* 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,
+ css_computed_border_bottom_width(table->style,
&b.width, &b.unit);
- b.width = nscss_len2px(b.width, b.unit, table->style);
+ b.width = nscss_len2px(len_ctx, 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)) {
+
+ if (table_border_is_more_eyecatching(len_ctx,
+ &a, a_src, &b, b_src)) {
a = b;
}
}
@@ -696,21 +755,26 @@ void table_used_bottom_border_for_cell(struct box *cell)
/* 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));
+ cell->border[BOTTOM].width = FIXTOINT(nscss_len2px(len_ctx,
+ 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
+ * \param len_ctx Length conversion context
+ * \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)
+bool table_border_is_more_eyecatching(
+ const nscss_len_ctx *len_ctx,
+ const struct border *a,
+ box_type a_src,
+ const struct border *b,
+ box_type b_src)
{
css_fixed awidth, bwidth;
int impact = 0;
@@ -727,12 +791,12 @@ bool table_border_is_more_eyecatching(const struct border *a,
return true;
/* 3a -- wider borders beat narrow ones */
- /* The widths must be absolute, which will be the case
+ /* 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);
+ awidth = nscss_len2px(len_ctx, a->width, a->unit, NULL);
+ bwidth = nscss_len2px(len_ctx, b->width, b->unit, NULL);
if (awidth < bwidth)
return true;
@@ -811,14 +875,18 @@ bool table_border_is_more_eyecatching(const struct border *a,
/**
* Process a table
*
- * \param table Table to process
- * \param a Current border style for cell
- * \param a_src Source of \a a
+ * \param len_ctx Length conversion context
+ * \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,
+void table_cell_top_process_table(
+ const nscss_len_ctx *len_ctx,
+ struct box *table,
+ struct border *a,
box_type *a_src)
{
struct border b;
@@ -828,11 +896,11 @@ void table_cell_top_process_table(struct box *table, struct border *a,
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.width = nscss_len2px(len_ctx, 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)) {
+ if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -841,17 +909,22 @@ void table_cell_top_process_table(struct box *table, struct border *a,
/**
* 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
+ * \param len_ctx Length conversion context
+ * \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)
+bool table_cell_top_process_group(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell,
+ struct box *group,
+ struct border *a,
+ box_type *a_src)
{
struct border b;
box_type b_src;
@@ -860,11 +933,11 @@ bool table_cell_top_process_group(struct box *cell, struct box *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.width = nscss_len2px(len_ctx, 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)) {
+ if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -873,7 +946,7 @@ bool table_cell_top_process_group(struct box *cell, struct box *group,
/* Process rows in group, starting with last */
struct box *row = group->last;
- while (table_cell_top_process_row(cell, row,
+ while (table_cell_top_process_row(len_ctx, cell, row,
a, a_src) == false) {
if (row->prev == NULL) {
return false;
@@ -886,11 +959,12 @@ bool table_cell_top_process_group(struct box *cell, struct box *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.width = nscss_len2px(len_ctx, 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)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -904,17 +978,22 @@ bool table_cell_top_process_group(struct box *cell, struct box *group,
/**
* 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
+ * \param len_ctx Length conversion context
+ * \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)
+bool table_cell_top_process_row(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell,
+ struct box *row,
+ struct border *a,
+ box_type *a_src)
{
struct border b;
box_type b_src;
@@ -923,11 +1002,11 @@ bool table_cell_top_process_row(struct box *cell, struct box *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.width = nscss_len2px(len_ctx, 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)) {
+ if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -937,18 +1016,19 @@ bool table_cell_top_process_row(struct box *cell, struct box *row,
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.width = nscss_len2px(len_ctx, 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)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
return false;
} else {
- /* Process cells that are directly above the cell being
+ /* 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;
@@ -975,13 +1055,13 @@ bool table_cell_top_process_row(struct box *cell, struct box *row,
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.width = nscss_len2px(len_ctx,
+ 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)) {
+ if (table_border_is_more_eyecatching(len_ctx,
+ a, *a_src, &b, b_src)) {
*a = b;
*a_src = b_src;
}
@@ -998,4 +1078,3 @@ bool table_cell_top_process_row(struct box *cell, struct box *row,
return true;
}
-
diff --git a/render/table.h b/content/handlers/html/table.h
similarity index 73%
rename from render/table.h
rename to content/handlers/html/table.h
index ecd3043..11ab653 100644
--- a/render/table.h
+++ b/content/handlers/html/table.h
@@ -17,18 +17,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Table processing and layout (interface).
+/**
+ * \file
+ * Interface to HTML table processing and layout.
*/
-#ifndef _NETSURF_RENDER_TABLE_H_
-#define _NETSURF_RENDER_TABLE_H_
+#ifndef NETSURF_HTML_TABLE_H
+#define NETSURF_HTML_TABLE_H
#include <stdbool.h>
struct box;
-bool table_calculate_column_types(struct box *table);
-void table_used_border_for_cell(struct box *cell);
+bool table_calculate_column_types(
+ const nscss_len_ctx *len_ctx,
+ struct box *table);
+void table_used_border_for_cell(
+ const nscss_len_ctx *len_ctx,
+ struct box *cell);
#endif
diff --git a/content/handlers/image/jpeg.c b/content/handlers/image/jpeg.c
index 95b86cd..6eec61c 100644
--- a/content/handlers/image/jpeg.c
+++ b/content/handlers/image/jpeg.c
@@ -215,7 +215,12 @@ jpeg_cache_convert(struct content *c)
jpeg_read_header(&cinfo, TRUE);
/* set output processing parameters */
- cinfo.out_color_space = JCS_RGB;
+ if (cinfo.jpeg_color_space == JCS_CMYK ||
+ cinfo.jpeg_color_space == JCS_YCCK) {
+ cinfo.out_color_space = JCS_CMYK;
+ } else {
+ cinfo.out_color_space = JCS_RGB;
+ }
cinfo.dct_method = JDCT_ISLOW;
/* commence the decompression, output parameters now valid */
@@ -249,22 +254,42 @@ jpeg_cache_convert(struct content *c)
rowstride * cinfo.output_scanline);
jpeg_read_scanlines(&cinfo, scanlines, 1);
+ if (cinfo.out_color_space == JCS_CMYK) {
+ int i;
+ for (i = width - 1; 0 <= i; i--) {
+ /* Trivial inverse CMYK -> RGBA */
+ const int c = scanlines[0][i * 4 + 0];
+ const int m = scanlines[0][i * 4 + 1];
+ const int y = scanlines[0][i * 4 + 2];
+ const int k = scanlines[0][i * 4 + 3];
+
+ const int ck = c * k;
+ const int mk = m * k;
+ const int yk = y * k;
+
+#define DIV255(x) ((x) + 1 + ((x) >> 8)) >> 8
+ scanlines[0][i * 4 + 0] = DIV255(ck);
+ scanlines[0][i * 4 + 1] = DIV255(mk);
+ scanlines[0][i * 4 + 2] = DIV255(yk);
+ scanlines[0][i * 4 + 3] = 0xff;
+#undef DIV255
+ }
+ } else {
#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;
- }
-}
+ /* 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);
guit->bitmap->modified(bitmap);
diff --git a/content/handlers/image/rsvg.c b/content/handlers/image/rsvg.c
index ca2d81e..2ba1b49 100644
--- a/content/handlers/image/rsvg.c
+++ b/content/handlers/image/rsvg.c
@@ -39,6 +39,8 @@
#include <librsvg/rsvg-cairo.h>
#endif
+#include <nsutils/endian.h>
+
#include "utils/log.h"
#include "utils/utils.h"
#include "utils/messages.h"
@@ -139,15 +141,21 @@ static inline void rsvg_argb_to_abgr(uint8_t *pixels,
int width, int height, size_t rowstride)
{
uint8_t *p = pixels;
+ int boff = 0, roff = 2;
+
+ if (endian_host_is_le() == false) {
+ boff = 1;
+ roff = 3;
+ }
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];
+ const uint8_t r = p[4*x+roff];
- p[x+3] = p[x];
+ p[4*x+roff] = p[4*x+boff];
- p[x] = r;
+ p[4*x+boff] = r;
}
p += rowstride;
diff --git a/content/handlers/image/svg.c b/content/handlers/image/svg.c
index 2edc7bd..5126073 100644
--- a/content/handlers/image/svg.c
+++ b/content/handlers/image/svg.c
@@ -188,14 +188,15 @@ svg_redraw_internal(struct content *c,
for (i = 0; i != diagram->shape_count; i++) {
if (diagram->shape[i].path) {
+ pstyle.stroke_width = plot_style_int_to_fixed(
+ diagram->shape[i].stroke);
pstyle.stroke_colour = BGR(diagram->shape[i].stroke);
pstyle.fill_colour = BGR(diagram->shape[i].fill);
res = ctx->plot->path(ctx,
- &pstyle,
- diagram->shape[i].path,
- diagram->shape[i].path_length,
- diagram->shape[i].stroke_width,
- transform);
+ &pstyle,
+ diagram->shape[i].path,
+ diagram->shape[i].path_length,
+ transform);
if (res != NSERROR_OK) {
return false;
}
@@ -210,7 +211,7 @@ svg_redraw_internal(struct content *c,
fstyle.background = 0xffffff;
fstyle.foreground = 0x000000;
- fstyle.size = (8 * FONT_SIZE_SCALE) * scale;
+ fstyle.size = (8 * PLOT_STYLE_SCALE) * scale;
res = ctx->plot->text(ctx,
&fstyle,
diff --git a/content/handlers/javascript/duktape/Document.bnd b/content/handlers/javascript/duktape/Document.bnd
index ece417d..5de7245 100644
--- a/content/handlers/javascript/duktape/Document.bnd
+++ b/content/handlers/javascript/duktape/Document.bnd
@@ -14,7 +14,7 @@ prologue Document()
#include "utils/libdom.h"
#include "utils/utils.h"
#include "content/hlcache.h"
-#include "render/html_internal.h"
+#include "html/html_internal.h"
#include "content/urldb.h"
#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
diff --git a/content/handlers/javascript/duktape/Makefile b/content/handlers/javascript/duktape/Makefile
index fce79de..2a5c2e7 100644
--- a/content/handlers/javascript/duktape/Makefile
+++ b/content/handlers/javascript/duktape/Makefile
@@ -4,7 +4,7 @@
# Included by javascript/Makefile
#
-content/handlers/javascript/dukky.c: $(OBJROOT)/duktape/binding.h
+content/handlers/javascript/duktape/dukky.c: $(OBJROOT)/duktape/binding.h
BINDINGS := $(wildcard content/handlers/javascript/duktape/*.bnd)
diff --git a/content/handlers/javascript/duktape/Window.bnd b/content/handlers/javascript/duktape/Window.bnd
index 3f680d4..98ba39d 100644
--- a/content/handlers/javascript/duktape/Window.bnd
+++ b/content/handlers/javascript/duktape/Window.bnd
@@ -15,8 +15,8 @@ class Window {
#include "utils/nsurl.h"
#include "netsurf/browser_window.h"
#include "content/hlcache.h"
-#include "render/html.h"
-#include "render/html_internal.h"
+#include "html/html.h"
+#include "html/html_internal.h"
%};
};
@@ -28,7 +28,7 @@ init Window(struct browser_window *win, struct html_content *htmlc)
NSLOG(netsurf, INFO, "win=%p htmlc=%p", priv->win, priv->htmlc);
NSLOG(netsurf, INFO,
- "URL is %s", nsurl_access(browser_window_get_url(priv->win)));
+ "URL is %s", nsurl_access(browser_window_access_url(priv->win)));
%}
prototype Window()
diff --git a/content/handlers/javascript/duktape/duk_config.h b/content/handlers/javascript/duktape/duk_config.h
index 379e9f6..40df0fe 100644
--- a/content/handlers/javascript/duktape/duk_config.h
+++ b/content/handlers/javascript/duktape/duk_config.h
@@ -218,12 +218,6 @@
#define DUK_F_UNIX
#endif
-/* C++ */
-#undef DUK_F_CPP
-#if defined(__cplusplus)
-#define DUK_F_CPP
-#endif
-
/* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers),
* define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32.
* https://sites.google.com/site/x32abi/
@@ -301,6 +295,12 @@
#define DUK_F_CLANG
#endif
+/* C++ */
+#undef DUK_F_CPP
+#if defined(__cplusplus)
+#define DUK_F_CPP
+#endif
+
/* C99 or above */
#undef DUK_F_C99
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
@@ -836,9 +836,7 @@
#include <stdint.h>
#endif
-#if defined(DUK_F_CPP)
-#include <exception> /* std::exception */
-#endif
+/* <exception> is only included if needed, based on DUK_USE_xxx flags. */
/*
* Architecture autodetection
@@ -850,7 +848,16 @@
#if !defined(DUK_USE_BYTEORDER)
#define DUK_USE_BYTEORDER 1
#endif
+
#define DUK_USE_PACKED_TVAL
+
+/* FreeBSD, -m32, and clang prior to 5.0 has union aliasing issues which
+ * break duk_tval copying. Disable packed duk_tval automatically.
+ */
+#if defined(DUK_F_FREEBSD) && defined(DUK_F_X86) && \
+ defined(__clang__) && defined(__clang_major__) && (__clang_major__ < 5)
+#undef DUK_USE_PACKED_TVAL
+#endif
#define DUK_F_PACKED_TVAL_PROVIDED
#elif defined(DUK_F_X64)
/* --- x64 --- */
@@ -924,9 +931,6 @@
/* --- SuperH --- */
#define DUK_USE_ARCH_STRING "sh"
/* Byte order varies, rely on autodetection. */
-/* Based on 'make checkalign' there are no alignment requirements on
- * Linux SH4, but align by 4 is probably a good basic default.
- */
#define DUK_USE_PACKED_TVAL
#define DUK_F_PACKED_TVAL_PROVIDED
#elif defined(DUK_F_M68K)
@@ -1954,8 +1958,8 @@ typedef duk_uint_fast16_t duk_small_uint_fast_t;
/* Boolean values are represented with the platform 'unsigned int'. */
typedef duk_small_uint_t duk_bool_t;
-#define DUK_BOOL_MIN DUK_SMALL_INT_MIN
-#define DUK_BOOL_MAX DUK_SMALL_INT_MAX
+#define DUK_BOOL_MIN DUK_SMALL_UINT_MIN
+#define DUK_BOOL_MAX DUK_SMALL_UINT_MAX
/* Index values must have at least 32-bit signed range. */
typedef duk_int_t duk_idx_t;
@@ -2489,10 +2493,13 @@ typedef struct duk_hthread duk_context;
*
* Assume unaligned accesses are not supported unless specifically allowed
* in the target platform. Some platforms may support unaligned accesses
- * but alignment to 4 or 8 may still be desirable.
+ * but alignment to 4 or 8 may still be desirable. Note that unaligned
+ * accesses (and even pointers) relative to natural alignment (regardless
+ * of target alignment) are technically undefined behavior and thus
+ * compiler/architecture specific.
*/
-/* If not provided, use safe default for alignment. */
+/* If not forced, use safe default for alignment. */
#if !defined(DUK_USE_ALIGN_BY)
#define DUK_USE_ALIGN_BY 8
#endif
@@ -2544,6 +2551,7 @@ typedef struct duk_hthread duk_context;
*/
#define DUK_CAUSE_SEGFAULT() do { *((volatile duk_uint32_t *) NULL) = (duk_uint32_t) 0xdeadbeefUL; } while (0)
#endif
+
#if !defined(DUK_UNREF)
/* Macro for suppressing warnings for potentially unreferenced variables.
* The variables can be actually unreferenced or unreferenced in some
@@ -2553,9 +2561,24 @@ typedef struct duk_hthread duk_context;
*/
#define DUK_UNREF(x) do { (void) (x); } while (0)
#endif
-#if !defined(DUK_NORETURN)
+
+/* Fillin for DUK_NORETURN; DUK_WO_NORETURN() is used to insert dummy
+ * dummy statements after noreturn calls to silence harmless compiler
+ * warnings, e.g.:
+ *
+ * DUK_ERROR_TYPE(thr, "aiee");
+ * DUK_WO_NORETURN(return 0;);
+ *
+ * Statements inside DUK_WO_NORETURN() must NEVER be actually reachable,
+ * and they're only included to satisfy the compiler.
+ */
+#if defined(DUK_NORETURN)
+#define DUK_WO_NORETURN(stmt) do { } while (0)
+#else
#define DUK_NORETURN(decl) decl
+#define DUK_WO_NORETURN(stmt) do { stmt } while (0)
#endif
+
#if !defined(DUK_UNREACHABLE)
/* Don't know how to declare unreachable point, so don't do it; this
* may cause some spurious compilation warnings (e.g. "variable used
@@ -2563,6 +2586,7 @@ typedef struct duk_hthread duk_context;
*/
#define DUK_UNREACHABLE() do { } while (0)
#endif
+
#if !defined(DUK_LOSE_CONST)
/* Convert any input pointer into a "void *", losing a const qualifier.
* This is not fully portable because casting through duk_uintptr_t may
@@ -2730,8 +2754,8 @@ typedef struct duk_hthread duk_context;
#if defined(DUK_F_PACKED_TVAL_POSSIBLE)
#define DUK_USE_PACKED_TVAL
#endif
-
#undef DUK_F_PACKED_TVAL_POSSIBLE
+
#endif /* DUK_F_PACKED_TVAL_PROVIDED */
/* Object property allocation layout has implications for memory and code
* footprint and generated code size/speed. The best layout also depends
@@ -2766,6 +2790,7 @@ typedef struct duk_hthread duk_context;
* Autogenerated defaults
*/
+#undef DUK_USE_ALLOW_UNDEFINED_BEHAVIOR
#define DUK_USE_ARRAY_BUILTIN
#define DUK_USE_ARRAY_FASTPATH
#define DUK_USE_ARRAY_PROP_FASTPATH
@@ -2774,6 +2799,7 @@ typedef struct duk_hthread duk_context;
#define DUK_USE_AUGMENT_ERROR_THROW
#define DUK_USE_AVOID_PLATFORM_FUNCPTRS
#define DUK_USE_BASE64_FASTPATH
+#define DUK_USE_BASE64_SUPPORT
#define DUK_USE_BOOLEAN_BUILTIN
#define DUK_USE_BUFFEROBJECT_SUPPORT
#undef DUK_USE_BUFLEN16
@@ -2851,6 +2877,7 @@ typedef struct duk_hthread duk_context;
#undef DUK_USE_HEAPPTR_DEC16
#undef DUK_USE_HEAPPTR_ENC16
#define DUK_USE_HEX_FASTPATH
+#define DUK_USE_HEX_SUPPORT
#define DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT 2
#define DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT 9
#define DUK_USE_HOBJECT_ARRAY_MINGROW_ADD 16
@@ -2881,11 +2908,10 @@ typedef struct duk_hthread duk_context;
#define DUK_USE_JX
#define DUK_USE_LEXER_SLIDING_WINDOW
#undef DUK_USE_LIGHTFUNC_BUILTINS
+#define DUK_USE_LITCACHE_SIZE 256
#define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256
#define DUK_USE_MATH_BUILTIN
#define DUK_USE_NATIVE_CALL_RECLIMIT 1000
-#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER
-#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER
#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY
@@ -2967,6 +2993,15 @@ typedef struct duk_hthread duk_context;
/* __OVERRIDE_DEFINES__ */
/*
+ * Conditional includes
+ */
+
+#if defined(DUK_F_CPP) && defined(DUK_USE_CPP_EXCEPTIONS)
+#include <exception> /* std::exception */
+#include <stdexcept> /* std::runtime_error */
+#endif
+
+/*
* Date provider selection
*
* User may define DUK_USE_DATE_GET_NOW() etc directly, in which case we'll
diff --git a/content/handlers/javascript/duktape/duktape.c b/content/handlers/javascript/duktape/duktape.c
index 52b9e13..d6a4e31 100644
--- a/content/handlers/javascript/duktape/duktape.c
+++ b/content/handlers/javascript/duktape/duktape.c
@@ -1,7 +1,7 @@
/* Omit from static analysis. */
#ifndef __clang_analyzer__
/*
- * Single source autogenerated distributable for Duktape 2.2.0.
+ * Single source autogenerated distributable for Duktape 2.3.0.
*
* Git commit external (external).
* Git branch external.
@@ -18,7 +18,7 @@
*
* (http://opensource.org/licenses/MIT)
*
-* Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst)
+* Copyright (c) 2013-2018 by Duktape authors (see AUTHORS.rst)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -89,6 +89,14 @@
* * Steven Don (https://github.com/shdon)
* * Simon Stone (https://github.com/sstone1)
* * \J. McC. (https://github.com/jmhmccr)
+* * Jakub Nowakowski (https://github.com/jimvonmoon)
+* * Tommy Nguyen (https://github.com/tn0502)
+* * Fabrice Fontaine (https://github.com/ffontaine)
+* * Christopher Hiller (https://github.com/boneskull)
+* * Gonzalo Diethelm (https://github.com/gonzus)
+* * Michal Kasperek (https://github.com/michalkas)
+* * Andrew Janke (https://github.com/apjanke)
+* * Steve Fan (https://github.com/stevefan1999)
*
* Other contributions
* ===================
@@ -127,6 +135,8 @@
* * https://github.com/chris-y
* * Laurent Zubiaur (https://github.com/lzubiaur)
* * Neil Kolban (https://github.com/nkolban)
+* * Wilhelm Wanecek (https://github.com/wanecek)
+* * Andrew Janke (https://github.com/apjanke)
*
* If you are accidentally missing from this list, send me an e-mail
* (``sami.vaarala(a)iki.fi``) and I'll fix the omission.
@@ -665,20 +675,32 @@ struct duk_jmpbuf {
#endif /* DUK_JMPBUF_H_INCLUDED */
/* #include duk_exception.h */
/*
- * Exception for Duktape internal throws when C++ exceptions are used
+ * Exceptions for Duktape internal throws when C++ exceptions are used
* for long control transfers.
- *
- * Doesn't inherit from any exception base class to minimize the chance
- * that user code would accidentally catch this exception.
*/
#if !defined(DUK_EXCEPTION_H_INCLUDED)
#define DUK_EXCEPTION_H_INCLUDED
#if defined(DUK_USE_CPP_EXCEPTIONS)
+/* Internal exception used as a setjmp-longjmp replacement. User code should
+ * NEVER see or catch this exception, so it doesn't inherit from any base
+ * class which should minimize the chance of user code accidentally catching
+ * the exception.
+ */
class duk_internal_exception {
/* intentionally empty */
};
+
+/* Fatal error, thrown as a specific C++ exception with C++ exceptions
+ * enabled. It is unsafe to continue; doing so may cause crashes or memory
+ * leaks. This is intended to be either uncaught, or caught by user code
+ * aware of the "unsafe to continue" semantics.
+ */
+class duk_fatal_exception : public virtual std::runtime_error {
+ public:
+ duk_fatal_exception(const char *message) : std::runtime_error(message) {}
+};
#endif
#endif /* DUK_EXCEPTION_H_INCLUDED */
@@ -729,8 +751,9 @@ struct duk_breakpoint;
struct duk_activation;
struct duk_catcher;
-struct duk_strcache;
struct duk_ljstate;
+struct duk_strcache_entry;
+struct duk_litcache_entry;
struct duk_strtab_entry;
#if defined(DUK_USE_DEBUG)
@@ -789,8 +812,9 @@ typedef struct duk_breakpoint duk_breakpoint;
typedef struct duk_activation duk_activation;
typedef struct duk_catcher duk_catcher;
-typedef struct duk_strcache duk_strcache;
typedef struct duk_ljstate duk_ljstate;
+typedef struct duk_strcache_entry duk_strcache_entry;
+typedef struct duk_litcache_entry duk_litcache_entry;
typedef struct duk_strtab_entry duk_strtab_entry;
#if defined(DUK_USE_DEBUG)
@@ -1687,278 +1711,290 @@ DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double
#define DUK_STRIDX_OWN_KEYS 75 /* 'ownKeys' */
#define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS)
#define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS)
-#define DUK_STRIDX_SET_PROTOTYPE_OF 76 /* 'setPrototypeOf' */
+#define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE 76 /* '\x81Symbol.toPrimitive\xff' */
+#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE)
+#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE)
+#define DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE 77 /* '\x81Symbol.hasInstance\xff' */
+#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE)
+#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE)
+#define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG 78 /* '\x81Symbol.toStringTag\xff' */
+#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG)
+#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG)
+#define DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE 79 /* '\x81Symbol.isConcatSpreadable\xff' */
+#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE)
+#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE)
+#define DUK_STRIDX_SET_PROTOTYPE_OF 80 /* 'setPrototypeOf' */
#define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF)
#define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF)
-#define DUK_STRIDX___PROTO__ 77 /* '__proto__' */
+#define DUK_STRIDX___PROTO__ 81 /* '__proto__' */
#define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__)
#define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__)
-#define DUK_STRIDX_TO_STRING 78 /* 'toString' */
+#define DUK_STRIDX_TO_STRING 82 /* 'toString' */
#define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
#define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
-#define DUK_STRIDX_TO_JSON 79 /* 'toJSON' */
+#define DUK_STRIDX_TO_JSON 83 /* 'toJSON' */
#define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
#define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
-#define DUK_STRIDX_TYPE 80 /* 'type' */
+#define DUK_STRIDX_TYPE 84 /* 'type' */
#define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE)
#define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE)
-#define DUK_STRIDX_DATA 81 /* 'data' */
+#define DUK_STRIDX_DATA 85 /* 'data' */
#define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA)
#define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA)
-#define DUK_STRIDX_LENGTH 82 /* 'length' */
+#define DUK_STRIDX_LENGTH 86 /* 'length' */
#define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
#define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
-#define DUK_STRIDX_SET 83 /* 'set' */
+#define DUK_STRIDX_SET 87 /* 'set' */
#define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
#define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
-#define DUK_STRIDX_STACK 84 /* 'stack' */
+#define DUK_STRIDX_STACK 88 /* 'stack' */
#define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
#define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
-#define DUK_STRIDX_PC 85 /* 'pc' */
+#define DUK_STRIDX_PC 89 /* 'pc' */
#define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
#define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
-#define DUK_STRIDX_LINE_NUMBER 86 /* 'lineNumber' */
+#define DUK_STRIDX_LINE_NUMBER 90 /* 'lineNumber' */
#define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
#define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
-#define DUK_STRIDX_INT_TRACEDATA 87 /* '\x82Tracedata' */
+#define DUK_STRIDX_INT_TRACEDATA 91 /* '\x82Tracedata' */
#define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA)
#define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA)
-#define DUK_STRIDX_NAME 88 /* 'name' */
+#define DUK_STRIDX_NAME 92 /* 'name' */
#define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
#define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
-#define DUK_STRIDX_FILE_NAME 89 /* 'fileName' */
+#define DUK_STRIDX_FILE_NAME 93 /* 'fileName' */
#define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
#define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
-#define DUK_STRIDX_LC_POINTER 90 /* 'pointer' */
+#define DUK_STRIDX_LC_POINTER 94 /* 'pointer' */
#define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
#define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
-#define DUK_STRIDX_INT_TARGET 91 /* '\x82Target' */
+#define DUK_STRIDX_INT_TARGET 95 /* '\x82Target' */
#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
-#define DUK_STRIDX_INT_NEXT 92 /* '\x82Next' */
+#define DUK_STRIDX_INT_NEXT 96 /* '\x82Next' */
#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
-#define DUK_STRIDX_INT_BYTECODE 93 /* '\x82Bytecode' */
+#define DUK_STRIDX_INT_BYTECODE 97 /* '\x82Bytecode' */
#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
-#define DUK_STRIDX_INT_FORMALS 94 /* '\x82Formals' */
+#define DUK_STRIDX_INT_FORMALS 98 /* '\x82Formals' */
#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
-#define DUK_STRIDX_INT_VARMAP 95 /* '\x82Varmap' */
+#define DUK_STRIDX_INT_VARMAP 99 /* '\x82Varmap' */
#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
-#define DUK_STRIDX_INT_SOURCE 96 /* '\x82Source' */
+#define DUK_STRIDX_INT_SOURCE 100 /* '\x82Source' */
#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
-#define DUK_STRIDX_INT_PC2LINE 97 /* '\x82Pc2line' */
+#define DUK_STRIDX_INT_PC2LINE 101 /* '\x82Pc2line' */
#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
-#define DUK_STRIDX_INT_MAP 98 /* '\x82Map' */
+#define DUK_STRIDX_INT_MAP 102 /* '\x82Map' */
#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
-#define DUK_STRIDX_INT_VARENV 99 /* '\x82Varenv' */
+#define DUK_STRIDX_INT_VARENV 103 /* '\x82Varenv' */
#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
-#define DUK_STRIDX_INT_FINALIZER 100 /* '\x82Finalizer' */
+#define DUK_STRIDX_INT_FINALIZER 104 /* '\x82Finalizer' */
#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
-#define DUK_STRIDX_INT_VALUE 101 /* '\x82Value' */
+#define DUK_STRIDX_INT_VALUE 105 /* '\x82Value' */
#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
-#define DUK_STRIDX_COMPILE 102 /* 'compile' */
+#define DUK_STRIDX_COMPILE 106 /* 'compile' */
#define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
#define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
-#define DUK_STRIDX_INPUT 103 /* 'input' */
+#define DUK_STRIDX_INPUT 107 /* 'input' */
#define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
#define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
-#define DUK_STRIDX_ERR_CREATE 104 /* 'errCreate' */
+#define DUK_STRIDX_ERR_CREATE 108 /* 'errCreate' */
#define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE)
#define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE)
-#define DUK_STRIDX_ERR_THROW 105 /* 'errThrow' */
+#define DUK_STRIDX_ERR_THROW 109 /* 'errThrow' */
#define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW)
#define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW)
-#define DUK_STRIDX_ENV 106 /* 'env' */
+#define DUK_STRIDX_ENV 110 /* 'env' */
#define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
#define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
-#define DUK_STRIDX_HEX 107 /* 'hex' */
+#define DUK_STRIDX_HEX 111 /* 'hex' */
#define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
#define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
-#define DUK_STRIDX_BASE64 108 /* 'base64' */
+#define DUK_STRIDX_BASE64 112 /* 'base64' */
#define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
#define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
-#define DUK_STRIDX_JX 109 /* 'jx' */
+#define DUK_STRIDX_JX 113 /* 'jx' */
#define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX)
#define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX)
-#define DUK_STRIDX_JC 110 /* 'jc' */
+#define DUK_STRIDX_JC 114 /* 'jc' */
#define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC)
#define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC)
-#define DUK_STRIDX_JSON_EXT_UNDEFINED 111 /* '{"_undef":true}' */
+#define DUK_STRIDX_JSON_EXT_UNDEFINED 115 /* '{"_undef":true}' */
#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
-#define DUK_STRIDX_JSON_EXT_NAN 112 /* '{"_nan":true}' */
+#define DUK_STRIDX_JSON_EXT_NAN 116 /* '{"_nan":true}' */
#define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
-#define DUK_STRIDX_JSON_EXT_POSINF 113 /* '{"_inf":true}' */
+#define DUK_STRIDX_JSON_EXT_POSINF 117 /* '{"_inf":true}' */
#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
-#define DUK_STRIDX_JSON_EXT_NEGINF 114 /* '{"_ninf":true}' */
+#define DUK_STRIDX_JSON_EXT_NEGINF 118 /* '{"_ninf":true}' */
#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
-#define DUK_STRIDX_JSON_EXT_FUNCTION1 115 /* '{"_func":true}' */
+#define DUK_STRIDX_JSON_EXT_FUNCTION1 119 /* '{"_func":true}' */
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
-#define DUK_STRIDX_JSON_EXT_FUNCTION2 116 /* '{_func:true}' */
+#define DUK_STRIDX_JSON_EXT_FUNCTION2 120 /* '{_func:true}' */
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
-#define DUK_STRIDX_BREAK 117 /* 'break' */
+#define DUK_STRIDX_BREAK 121 /* 'break' */
#define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
#define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
-#define DUK_STRIDX_CASE 118 /* 'case' */
+#define DUK_STRIDX_CASE 122 /* 'case' */
#define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
#define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
-#define DUK_STRIDX_CATCH 119 /* 'catch' */
+#define DUK_STRIDX_CATCH 123 /* 'catch' */
#define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
#define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
-#define DUK_STRIDX_CONTINUE 120 /* 'continue' */
+#define DUK_STRIDX_CONTINUE 124 /* 'continue' */
#define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
#define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
-#define DUK_STRIDX_DEBUGGER 121 /* 'debugger' */
+#define DUK_STRIDX_DEBUGGER 125 /* 'debugger' */
#define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
#define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
-#define DUK_STRIDX_DEFAULT 122 /* 'default' */
+#define DUK_STRIDX_DEFAULT 126 /* 'default' */
#define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
#define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
-#define DUK_STRIDX_DELETE 123 /* 'delete' */
+#define DUK_STRIDX_DELETE 127 /* 'delete' */
#define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
#define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
-#define DUK_STRIDX_DO 124 /* 'do' */
+#define DUK_STRIDX_DO 128 /* 'do' */
#define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
#define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
-#define DUK_STRIDX_ELSE 125 /* 'else' */
+#define DUK_STRIDX_ELSE 129 /* 'else' */
#define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
#define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
-#define DUK_STRIDX_FINALLY 126 /* 'finally' */
+#define DUK_STRIDX_FINALLY 130 /* 'finally' */
#define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
#define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
-#define DUK_STRIDX_FOR 127 /* 'for' */
+#define DUK_STRIDX_FOR 131 /* 'for' */
#define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
#define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
-#define DUK_STRIDX_LC_FUNCTION 128 /* 'function' */
+#define DUK_STRIDX_LC_FUNCTION 132 /* 'function' */
#define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
#define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
-#define DUK_STRIDX_IF 129 /* 'if' */
+#define DUK_STRIDX_IF 133 /* 'if' */
#define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
#define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
-#define DUK_STRIDX_IN 130 /* 'in' */
+#define DUK_STRIDX_IN 134 /* 'in' */
#define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
#define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
-#define DUK_STRIDX_INSTANCEOF 131 /* 'instanceof' */
+#define DUK_STRIDX_INSTANCEOF 135 /* 'instanceof' */
#define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
#define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
-#define DUK_STRIDX_NEW 132 /* 'new' */
+#define DUK_STRIDX_NEW 136 /* 'new' */
#define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
#define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
-#define DUK_STRIDX_RETURN 133 /* 'return' */
+#define DUK_STRIDX_RETURN 137 /* 'return' */
#define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
#define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
-#define DUK_STRIDX_SWITCH 134 /* 'switch' */
+#define DUK_STRIDX_SWITCH 138 /* 'switch' */
#define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
#define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
-#define DUK_STRIDX_THIS 135 /* 'this' */
+#define DUK_STRIDX_THIS 139 /* 'this' */
#define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
#define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
-#define DUK_STRIDX_THROW 136 /* 'throw' */
+#define DUK_STRIDX_THROW 140 /* 'throw' */
#define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
#define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
-#define DUK_STRIDX_TRY 137 /* 'try' */
+#define DUK_STRIDX_TRY 141 /* 'try' */
#define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
#define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
-#define DUK_STRIDX_TYPEOF 138 /* 'typeof' */
+#define DUK_STRIDX_TYPEOF 142 /* 'typeof' */
#define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
-#define DUK_STRIDX_VAR 139 /* 'var' */
+#define DUK_STRIDX_VAR 143 /* 'var' */
#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
-#define DUK_STRIDX_CONST 140 /* 'const' */
+#define DUK_STRIDX_CONST 144 /* 'const' */
#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
-#define DUK_STRIDX_VOID 141 /* 'void' */
+#define DUK_STRIDX_VOID 145 /* 'void' */
#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
-#define DUK_STRIDX_WHILE 142 /* 'while' */
+#define DUK_STRIDX_WHILE 146 /* 'while' */
#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
#define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
-#define DUK_STRIDX_WITH 143 /* 'with' */
+#define DUK_STRIDX_WITH 147 /* 'with' */
#define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
-#define DUK_STRIDX_CLASS 144 /* 'class' */
+#define DUK_STRIDX_CLASS 148 /* 'class' */
#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
-#define DUK_STRIDX_ENUM 145 /* 'enum' */
+#define DUK_STRIDX_ENUM 149 /* 'enum' */
#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
-#define DUK_STRIDX_EXPORT 146 /* 'export' */
+#define DUK_STRIDX_EXPORT 150 /* 'export' */
#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
#define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
-#define DUK_STRIDX_EXTENDS 147 /* 'extends' */
+#define DUK_STRIDX_EXTENDS 151 /* 'extends' */
#define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
#define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
-#define DUK_STRIDX_IMPORT 148 /* 'import' */
+#define DUK_STRIDX_IMPORT 152 /* 'import' */
#define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
#define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
-#define DUK_STRIDX_SUPER 149 /* 'super' */
+#define DUK_STRIDX_SUPER 153 /* 'super' */
#define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
#define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
-#define DUK_STRIDX_LC_NULL 150 /* 'null' */
+#define DUK_STRIDX_LC_NULL 154 /* 'null' */
#define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL)
#define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL)
-#define DUK_STRIDX_TRUE 151 /* 'true' */
+#define DUK_STRIDX_TRUE 155 /* 'true' */
#define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
#define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
-#define DUK_STRIDX_FALSE 152 /* 'false' */
+#define DUK_STRIDX_FALSE 156 /* 'false' */
#define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
#define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
-#define DUK_STRIDX_IMPLEMENTS 153 /* 'implements' */
+#define DUK_STRIDX_IMPLEMENTS 157 /* 'implements' */
#define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
#define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
-#define DUK_STRIDX_INTERFACE 154 /* 'interface' */
+#define DUK_STRIDX_INTERFACE 158 /* 'interface' */
#define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
#define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
-#define DUK_STRIDX_LET 155 /* 'let' */
+#define DUK_STRIDX_LET 159 /* 'let' */
#define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
#define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
-#define DUK_STRIDX_PACKAGE 156 /* 'package' */
+#define DUK_STRIDX_PACKAGE 160 /* 'package' */
#define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
#define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
-#define DUK_STRIDX_PRIVATE 157 /* 'private' */
+#define DUK_STRIDX_PRIVATE 161 /* 'private' */
#define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
#define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
-#define DUK_STRIDX_PROTECTED 158 /* 'protected' */
+#define DUK_STRIDX_PROTECTED 162 /* 'protected' */
#define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
#define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
-#define DUK_STRIDX_PUBLIC 159 /* 'public' */
+#define DUK_STRIDX_PUBLIC 163 /* 'public' */
#define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
#define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
-#define DUK_STRIDX_STATIC 160 /* 'static' */
+#define DUK_STRIDX_STATIC 164 /* 'static' */
#define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
#define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
-#define DUK_STRIDX_YIELD 161 /* 'yield' */
+#define DUK_STRIDX_YIELD 165 /* 'yield' */
#define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
#define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
-#define DUK_HEAP_NUM_STRINGS 162
-#define DUK_STRIDX_START_RESERVED 117
-#define DUK_STRIDX_START_STRICT_RESERVED 153
-#define DUK_STRIDX_END_RESERVED 162 /* exclusive endpoint */
+#define DUK_HEAP_NUM_STRINGS 166
+#define DUK_STRIDX_START_RESERVED 121
+#define DUK_STRIDX_START_STRICT_RESERVED 157
+#define DUK_STRIDX_END_RESERVED 166 /* exclusive endpoint */
/* To convert a heap stridx to a token number, subtract
* DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
*/
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[892];
+DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[967];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_STRDATA_MAX_STRLEN 17
-#define DUK_STRDATA_DATA_LENGTH 892
+#define DUK_STRDATA_MAX_STRLEN 27
+#define DUK_STRDATA_DATA_LENGTH 967
#endif /* DUK_USE_ROM_STRINGS */
#if defined(DUK_USE_ROM_OBJECTS)
@@ -1975,6 +2011,8 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx);
@@ -1985,8 +2023,6 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx);
@@ -2058,6 +2094,7 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_cont
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx);
+DUK_INTERNAL_DECL duk_ret_t duk_bi_number_check_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx);
@@ -2140,7 +2177,7 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_conte
DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_performance_now(duk_context *ctx);
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[176];
+DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[177];
#endif /* !DUK_SINGLE_FILE */
#define DUK_BIDX_GLOBAL 0
#define DUK_BIDX_GLOBAL_ENV 1
@@ -2195,22 +2232,22 @@ DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[176];
#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 50
#define DUK_NUM_BUILTINS 51
#define DUK_NUM_BIDX_BUILTINS 51
-#define DUK_NUM_ALL_BUILTINS 76
+#define DUK_NUM_ALL_BUILTINS 78
#if defined(DUK_USE_DOUBLE_LE)
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4116];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3972
+#define DUK_BUILTINS_DATA_LENGTH 4116
#elif defined(DUK_USE_DOUBLE_BE)
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4116];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3972
+#define DUK_BUILTINS_DATA_LENGTH 4116
#elif defined(DUK_USE_DOUBLE_ME)
#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3972];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4116];
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3972
+#define DUK_BUILTINS_DATA_LENGTH 4116
#else
#error invalid endianness defines
#endif
@@ -2535,12 +2572,13 @@ struct duk_bufwriter_ctx {
(bw_ctx)->p += duk__enc_len; \
} while (0)
/* XXX: add temporary duk__p pointer here too; sharing */
+/* XXX: avoid unsafe variants */
#define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \
const void *duk__valptr; \
duk_size_t duk__valsz; \
duk__valptr = (const void *) (valptr); \
duk__valsz = (duk_size_t) (valsz); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
+ duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
(bw_ctx)->p += duk__valsz; \
} while (0)
#define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \
@@ -2548,31 +2586,31 @@ struct duk_bufwriter_ctx {
duk_size_t duk__val_len; \
duk__val = (const duk_uint8_t *) (val); \
duk__val_len = DUK_STRLEN((const char *) duk__val); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
+ duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
+ duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
+ duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
+ duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
+ duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
@@ -2636,13 +2674,14 @@ struct duk_bufwriter_ctx {
DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \
} while (0)
/* XXX: add temporary duk__p pointer here too; sharing */
+/* XXX: avoid unsafe */
#define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \
const void *duk__valptr; \
duk_size_t duk__valsz; \
duk__valptr = (const void *) (valptr); \
duk__valsz = (duk_size_t) (valsz); \
DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
+ duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
(bw_ctx)->p += duk__valsz; \
} while (0)
#define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \
@@ -2651,35 +2690,35 @@ struct duk_bufwriter_ctx {
duk__val = (const duk_uint8_t *) (val); \
duk__val_len = DUK_STRLEN((const char *) duk__val); \
DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
+ duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
+ duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
+ duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
+ duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
#define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
duk_size_t duk__val_len; \
duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
+ duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
(bw_ctx)->p += duk__val_len; \
} while (0)
@@ -2708,10 +2747,6 @@ DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256];
DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256];
DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256];
#endif
-#if defined(DUK_USE_BASE64_FASTPATH)
-DUK_INTERNAL_DECL const duk_uint8_t duk_base64_enctab[64];
-DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256];
-#endif
#endif /* !DUK_SINGLE_FILE */
/* Note: assumes that duk_util_probe_steps size is 32 */
@@ -2766,6 +2801,127 @@ DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk_d
DUK_INTERNAL_DECL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
#endif
+/* memcpy(), memmove() etc wrappers. The plain variants like duk_memcpy()
+ * assume C99+ and 'src' and 'dst' pointers must be non-NULL even when the
+ * operation size is zero. The unsafe variants like duk_memcpy_safe() deal
+ * with the zero size case explicitly, and allow NULL pointers in that case
+ * (which is undefined behavior in C99+). For the majority of actual targets
+ * a NULL pointer with a zero length is fine in practice. These wrappers are
+ * macros to force inlining; because there are hundreds of call sites, even a
+ * few extra bytes per call site adds up to ~1kB footprint.
+ */
+#if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
+#define duk_memcpy(dst,src,len) do { \
+ void *duk__dst = (dst); \
+ const void *duk__src = (src); \
+ duk_size_t duk__len = (len); \
+ DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
+ DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
+ (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \
+ } while (0)
+#define duk_memcpy_unsafe(dst,src,len) duk_memcpy((dst), (src), (len))
+#define duk_memmove(dst,src,len) do { \
+ void *duk__dst = (dst); \
+ const void *duk__src = (src); \
+ duk_size_t duk__len = (len); \
+ DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
+ DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
+ (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \
+ } while (0)
+#define duk_memmove_unsafe(dst,src,len) duk_memmove((dst), (src), (len))
+#define duk_memset(dst,val,len) do { \
+ void *duk__dst = (dst); \
+ duk_small_int_t duk__val = (val); \
+ duk_size_t duk__len = (len); \
+ DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
+ (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \
+ } while (0)
+#define duk_memset_unsafe(dst,val,len) duk_memset((dst), (val), (len))
+#define duk_memzero(dst,len) do { \
+ void *duk__dst = (dst); \
+ duk_size_t duk__len = (len); \
+ DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
+ (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \
+ } while (0)
+#define duk_memzero_unsafe(dst,len) duk_memzero((dst), (len))
+#else /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */
+#define duk_memcpy(dst,src,len) do { \
+ void *duk__dst = (dst); \
+ const void *duk__src = (src); \
+ duk_size_t duk__len = (len); \
+ DUK_ASSERT(duk__dst != NULL); \
+ DUK_ASSERT(duk__src != NULL); \
+ (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \
+ } while (0)
+#define duk_memcpy_unsafe(dst,src,len) do { \
+ void *duk__dst = (dst); \
+ const void *duk__src = (src); \
+ duk_size_t duk__len = (len); \
+ DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
+ DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
+ if (DUK_LIKELY(duk__len > 0U)) { \
+ DUK_ASSERT(duk__dst != NULL); \
+ DUK_ASSERT(duk__src != NULL); \
+ (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \
+ } \
+ } while (0)
+#define duk_memmove(dst,src,len) do { \
+ void *duk__dst = (dst); \
+ const void *duk__src = (src); \
+ duk_size_t duk__len = (len); \
+ DUK_ASSERT(duk__dst != NULL); \
+ DUK_ASSERT(duk__src != NULL); \
+ (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \
+ } while (0)
+#define duk_memmove_unsafe(dst,src,len) do { \
+ void *duk__dst = (dst); \
+ const void *duk__src = (src); \
+ duk_size_t duk__len = (len); \
+ DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
+ DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
+ if (DUK_LIKELY(duk__len > 0U)) { \
+ DUK_ASSERT(duk__dst != NULL); \
+ DUK_ASSERT(duk__src != NULL); \
+ (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \
+ } \
+ } while (0)
+#define duk_memset(dst,val,len) do { \
+ void *duk__dst = (dst); \
+ duk_small_int_t duk__val = (val); \
+ duk_size_t duk__len = (len); \
+ DUK_ASSERT(duk__dst != NULL); \
+ (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \
+ } while (0)
+#define duk_memset_unsafe(dst,val,len) do { \
+ void *duk__dst = (dst); \
+ duk_small_int_t duk__val = (val); \
+ duk_size_t duk__len = (len); \
+ DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
+ if (DUK_LIKELY(duk__len > 0U)) { \
+ DUK_ASSERT(duk__dst != NULL); \
+ (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \
+ } \
+ } while (0)
+#define duk_memzero(dst,len) do { \
+ void *duk__dst = (dst); \
+ duk_size_t duk__len = (len); \
+ DUK_ASSERT(duk__dst != NULL); \
+ (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \
+ } while (0)
+#define duk_memzero_unsafe(dst,len) do { \
+ void *duk__dst = (dst); \
+ duk_size_t duk__len = (len); \
+ DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
+ if (DUK_LIKELY(duk__len > 0U)) { \
+ DUK_ASSERT(duk__dst != NULL); \
+ (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \
+ } \
+ } while (0)
+#endif /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */
+
+DUK_INTERNAL_DECL DUK_INLINE duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len);
+DUK_INTERNAL_DECL DUK_INLINE duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len);
+
DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival);
DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival);
DUK_INTERNAL_DECL duk_bool_t duk_double_is_anyinf(duk_double_t x);
@@ -2780,6 +2936,33 @@ DUK_INTERNAL_DECL duk_double_t duk_double_trunc_towards_zero(duk_double_t x);
DUK_INTERNAL_DECL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y);
DUK_INTERNAL_DECL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y);
DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_finite(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_integer(duk_double_t x);
+DUK_INTERNAL_DECL duk_bool_t duk_double_is_safe_integer(duk_double_t x);
+
+DUK_INTERNAL_DECL DUK_INLINE duk_double_t duk_double_div(duk_double_t x, duk_double_t y);
+DUK_INTERNAL_DECL duk_int_t duk_double_to_int_t(duk_double_t x);
+DUK_INTERNAL_DECL duk_uint_t duk_double_to_uint_t(duk_double_t x);
+DUK_INTERNAL_DECL duk_int32_t duk_double_to_int32_t(duk_double_t x);
+DUK_INTERNAL_DECL duk_uint32_t duk_double_to_uint32_t(duk_double_t x);
+DUK_INTERNAL_DECL duk_float_t duk_double_to_float_t(duk_double_t x);
+
+/*
+ * Miscellaneous
+ */
+
+/* Example: x = 0x10 = 0b00010000
+ * x - 1 = 0x0f = 0b00001111
+ * x & (x - 1) == 0
+ *
+ * x = 0x07 = 0b00000111
+ * x - 1 = 0x06 = 0b00000110
+ * x & (x - 1) != 0
+ *
+ * However, incorrectly true for x == 0 so check for that explicitly.
+ */
+#define DUK_IS_POWER_OF_TWO(x) \
+ ((x) != 0U && ((x) & ((x) - 1U)) == 0U)
#endif /* DUK_UTIL_H_INCLUDED */
/* #include duk_strings.h */
@@ -2952,7 +3135,7 @@ DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
#endif /* DUK_ERRMSG_H_INCLUDED */
/* #include duk_js_bytecode.h */
/*
- * Ecmascript bytecode
+ * ECMAScript bytecode
*/
#if !defined(DUK_JS_BYTECODE_H_INCLUDED)
@@ -3824,7 +4007,7 @@ struct duk_lexer_codepoint {
duk_int_t line;
};
-/* Lexer context. Same context is used for Ecmascript and Regexp parsing. */
+/* Lexer context. Same context is used for ECMAScript and Regexp parsing. */
struct duk_lexer_ctx {
#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
duk_lexer_codepoint *window; /* unicode code points, window[0] is always next, points to 'buffer' */
@@ -3874,13 +4057,13 @@ DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_
#endif /* DUK_LEXER_H_INCLUDED */
/* #include duk_js_compiler.h */
/*
- * Ecmascript compiler.
+ * ECMAScript compiler.
*/
#if !defined(DUK_JS_COMPILER_H_INCLUDED)
#define DUK_JS_COMPILER_H_INCLUDED
-/* ecmascript compiler limits */
+/* ECMAScript compiler limits */
#define DUK_COMPILER_TOKEN_LIMIT 100000000L /* 1e8: protects against deeply nested inner functions */
/* maximum loopcount for peephole optimization */
@@ -4062,6 +4245,7 @@ struct duk_compiler_func {
duk_uint8_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */
duk_uint8_t needs_shuffle; /* function needs shuffle registers */
duk_uint8_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */
+ duk_uint8_t allow_regexp_in_adv; /* allow RegExp literal on next advance() call */
};
struct duk_compiler_ctx {
@@ -4219,9 +4403,6 @@ DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hack
/* XXX: macro for shared header fields (avoids some padding issues) */
-#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
-#pragma pack(push, 8)
-#endif
struct duk_heaphdr {
duk_uint32_t h_flags;
@@ -4267,16 +4448,7 @@ struct duk_heaphdr {
#if defined(DUK_USE_HEAPPTR16)
duk_uint16_t h_extra16;
#endif
-}
-#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR)
-__attribute__ ((aligned (8)))
-#elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR)
-__attribute__ ((aligned (8)))
-#endif
-;
-#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
-#pragma pack(pop)
-#endif
+};
struct duk_heaphdr_string {
/* 16 bits would be enough for shared heaphdr flags and duk_hstring
@@ -5373,10 +5545,12 @@ DUK_INTERNAL_DECL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_double_t duk_to_number_m1(duk_hthread *thr);
DUK_INTERNAL_DECL duk_double_t duk_to_number_m2(duk_hthread *thr);
+DUK_INTERNAL_DECL duk_bool_t duk_to_boolean_top_pop(duk_hthread *thr);
+
#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx);
#endif
-DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv);
+DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects);
DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */
DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
@@ -5514,6 +5688,8 @@ DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t
DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
+DUK_INTERNAL_DECL duk_bool_t duk_get_method_stridx(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t stridx);
+
DUK_INTERNAL_DECL void duk_pack(duk_hthread *thr, duk_idx_t count);
DUK_INTERNAL_DECL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx);
#if 0
@@ -5550,6 +5726,10 @@ DUK_INTERNAL_DECL void duk_concat_2(duk_hthread *thr);
DUK_INTERNAL_DECL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags);
+#if defined(DUK_USE_SYMBOL_BUILTIN)
+DUK_INTERNAL_DECL void duk_to_primitive_ordinary(duk_hthread *thr, duk_idx_t idx, duk_int_t hint);
+#endif
+
/* Raw internal valstack access macros: access is unsafe so call site
* must have a guarantee that the index is valid. When that is the case,
* using these macro results in faster and smaller code than duk_get_tval().
@@ -5588,7 +5768,7 @@ DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr);
* strings used as internal property names and raw buffers converted to
* strings. In such cases the 'clen' field contains an inaccurate value.
*
- * Ecmascript requires support for 32-bit long strings. However, since each
+ * ECMAScript requires support for 32-bit long strings. However, since each
* 16-bit codepoint can take 3 bytes in CESU-8, this representation can only
* support about 1.4G codepoint long strings in extreme cases. This is not
* really a practical issue.
@@ -5612,12 +5792,15 @@ DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr);
#define DUK_HSTRING_MAX_BYTELEN (0x7fffffffUL)
#endif
-/* XXX: could add flags for "is valid CESU-8" (Ecmascript compatible strings),
+/* XXX: could add flags for "is valid CESU-8" (ECMAScript compatible strings),
* "is valid UTF-8", "is valid extended UTF-8" (internal strings are not,
* regexp bytecode is), and "contains non-BMP characters". These are not
* needed right now.
*/
+/* With lowmem builds the high 16 bits of duk_heaphdr are used for other
+ * purposes, so this leaves 7 duk_heaphdr flags and 9 duk_hstring flags.
+ */
#define DUK_HSTRING_FLAG_ASCII DUK_HEAPHDR_USER_FLAG(0) /* string is ASCII, clen == blen */
#define DUK_HSTRING_FLAG_ARRIDX DUK_HEAPHDR_USER_FLAG(1) /* string is a valid array index */
#define DUK_HSTRING_FLAG_SYMBOL DUK_HEAPHDR_USER_FLAG(2) /* string is a symbol (invalid utf-8) */
@@ -5626,6 +5809,7 @@ DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr);
#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(5) /* string is a reserved word (strict) */
#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(6) /* string is 'eval' or 'arguments' */
#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(7) /* string data is external (duk_hstring_external) */
+#define DUK_HSTRING_FLAG_PINNED_LITERAL DUK_HEAPHDR_USER_FLAG(8) /* string is a literal, and pinned */
#define DUK_HSTRING_HAS_ASCII(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
#define DUK_HSTRING_HAS_ARRIDX(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
@@ -5635,6 +5819,7 @@ DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr);
#define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
#define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
#define DUK_HSTRING_HAS_EXTDATA(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
+#define DUK_HSTRING_HAS_PINNED_LITERAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL)
#define DUK_HSTRING_SET_ASCII(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
#define DUK_HSTRING_SET_ARRIDX(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
@@ -5644,6 +5829,7 @@ DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr);
#define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
#define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
#define DUK_HSTRING_SET_EXTDATA(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
+#define DUK_HSTRING_SET_PINNED_LITERAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL)
#define DUK_HSTRING_CLEAR_ASCII(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
#define DUK_HSTRING_CLEAR_ARRIDX(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
@@ -5653,6 +5839,7 @@ DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr);
#define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
#define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
#define DUK_HSTRING_CLEAR_EXTDATA(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
+#define DUK_HSTRING_CLEAR_PINNED_LITERAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL)
#if 0 /* Slightly smaller code without explicit flag, but explicit flag
* is very useful when 'clen' is dropped.
@@ -5745,9 +5932,6 @@ DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr);
* Misc
*/
-#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
-#pragma pack(push, 8)
-#endif
struct duk_hstring {
/* Smaller heaphdr than for other objects, because strings are held
* in string intern table which requires no link pointers. Much of
@@ -5792,16 +5976,7 @@ struct duk_hstring {
* for strings, but fields above should guarantee alignment-by-4
* (but not alignment-by-8).
*/
-}
-#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR)
-__attribute__ ((aligned (8)))
-#elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR)
-__attribute__ ((aligned (8)))
-#endif
-;
-#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
-#pragma pack(pop)
-#endif
+};
/* The external string struct is defined even when the feature is inactive. */
struct duk_hstring_external {
@@ -5832,12 +6007,12 @@ DUK_INTERNAL_DECL void duk_hstring_init_charlen(duk_hstring *h);
/*
* Heap object representation.
*
- * Heap objects are used for Ecmascript objects, arrays, and functions,
+ * Heap objects are used for ECMAScript objects, arrays, and functions,
* but also for internal control like declarative and object environment
* records. Compiled functions, native functions, and threads are also
* objects but with an extended C struct.
*
- * Objects provide the required Ecmascript semantics and exotic behaviors
+ * Objects provide the required ECMAScript semantics and exotic behaviors
* especially for property access.
*
* Properties are stored in three conceptual parts:
@@ -6466,7 +6641,7 @@ DUK_INTERNAL_DECL void duk_hstring_init_charlen(duk_hstring *h);
#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L
/*
- * Ecmascript [[Class]]
+ * ECMAScript [[Class]]
*/
/* range check not necessary because all 4-bit values are mapped */
@@ -6829,9 +7004,9 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_hthread *thr);
#endif /* DUK_HOBJECT_H_INCLUDED */
/* #include duk_hcompfunc.h */
/*
- * Heap compiled function (Ecmascript function) representation.
+ * Heap compiled function (ECMAScript function) representation.
*
- * There is a single data buffer containing the Ecmascript function's
+ * There is a single data buffer containing the ECMAScript function's
* bytecode, constants, and inner functions.
*/
@@ -7222,7 +7397,8 @@ struct duk_hboundfunc {
} while (0)
/* Get the current data pointer (caller must ensure buf != NULL) as a
- * duk_uint8_t ptr.
+ * duk_uint8_t ptr. Note that the result may be NULL if the underlying
+ * buffer has zero size and is not a fixed buffer.
*/
#define DUK_HBUFOBJ_GET_SLICE_BASE(heap,h) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
@@ -7540,14 +7716,14 @@ struct duk_activation {
duk_instr_t *curr_pc; /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */
/* bottom_byteoff and retval_byteoff are only used for book-keeping
- * of Ecmascript-initiated calls, to allow returning to an Ecmascript
+ * of ECMAScript-initiated calls, to allow returning to an ECMAScript
* function properly.
*/
/* Bottom of valstack for this activation, used to reset
* valstack_bottom on return; offset is absolute. There's
* no need to track 'top' because native call handling deals
- * with that using locals, and for Ecmascript returns 'nregs'
+ * with that using locals, and for ECMAScript returns 'nregs'
* indicates the necessary top.
*/
duk_size_t bottom_byteoff;
@@ -7931,7 +8107,7 @@ struct duk_hobjenv {
#define DUK_HBUFFER_EXTERNAL_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
#define DUK_HBUFFER_EXTERNAL_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
-#define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x) ((duk_uint8_t *) (((duk_hbuffer_fixed *) (x)) + 1))
+#define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x) ((duk_uint8_t *) (((duk_hbuffer_fixed *) (void *) (x)) + 1))
#if defined(DUK_USE_HEAPPTR16)
#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) \
@@ -7986,7 +8162,7 @@ struct duk_hobjenv {
DUK_HBUFFER_EXTERNAL_GET_DATA_PTR((heap), (duk_hbuffer_external *) (x)) : \
DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) \
) : \
- DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \
+ DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (void *) (x)) \
)
#else
/* Without heap pointer compression duk_hbuffer_dynamic and duk_hbuffer_external
@@ -7995,7 +8171,7 @@ struct duk_hobjenv {
#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \
DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) : \
- DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \
+ DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (void *) (x)) \
)
#endif
@@ -8069,7 +8245,10 @@ struct duk_hbuffer_fixed {
#if (DUK_USE_ALIGN_BY == 4)
duk_uint32_t dummy_for_align4;
#elif (DUK_USE_ALIGN_BY == 8)
- duk_double_t dummy_for_align8;
+ duk_double_t dummy_for_align8_1;
+#if defined(DUK_USE_64BIT_OPS)
+ duk_uint64_t dummy_for_align8_2;
+#endif
#elif (DUK_USE_ALIGN_BY == 1)
/* no extra padding */
#else
@@ -8484,7 +8663,7 @@ struct duk_breakpoint {
* Thus, string caches are now at the heap level now.
*/
-struct duk_strcache {
+struct duk_strcache_entry {
duk_hstring *h;
duk_uint32_t bidx;
duk_uint32_t cidx;
@@ -8516,6 +8695,15 @@ struct duk_ljstate {
} while (0)
/*
+ * Literal intern cache
+ */
+
+struct duk_litcache_entry {
+ const duk_uint8_t *addr;
+ duk_hstring *h;
+};
+
+/*
* Main heap structure
*/
@@ -8741,7 +8929,15 @@ struct duk_heap {
/* String access cache (codepoint offset -> byte offset) for fast string
* character looping; 'weak' reference which needs special handling in GC.
*/
- duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE];
+ duk_strcache_entry strcache[DUK_HEAP_STRCACHE_SIZE];
+
+#if defined(DUK_USE_LITCACHE_SIZE)
+ /* Literal intern cache. When enabled, strings interned as literals
+ * (e.g. duk_push_literal()) will be pinned and cached for the lifetime
+ * of the heap.
+ */
+ duk_litcache_entry litcache[DUK_USE_LITCACHE_SIZE];
+#endif
/* Built-in strings. */
#if defined(DUK_USE_ROM_STRINGS)
@@ -8773,6 +8969,9 @@ struct duk_heap {
duk_int_t stats_strtab_resize_check;
duk_int_t stats_strtab_resize_grow;
duk_int_t stats_strtab_resize_shrink;
+ duk_int_t stats_strtab_litcache_hit;
+ duk_int_t stats_strtab_litcache_miss;
+ duk_int_t stats_strtab_litcache_pin;
duk_int_t stats_object_realloc_props;
duk_int_t stats_object_abandon_array;
duk_int_t stats_getownpropdesc_count;
@@ -8833,6 +9032,9 @@ DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_t
DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len);
+#if defined(DUK_USE_LITCACHE_SIZE)
+DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_literal_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen);
+#endif
DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val);
DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val);
#if defined(DUK_USE_REFERENCE_COUNTING)
@@ -9234,8 +9436,8 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
* Error codes: defined in duktape.h
*
* Error codes are used as a shorthand to throw exceptions from inside
- * the implementation. The appropriate Ecmascript object is constructed
- * based on the code. Ecmascript code throws objects directly. The error
+ * the implementation. The appropriate ECMAScript object is constructed
+ * based on the code. ECMAScript code throws objects directly. The error
* codes are defined in the public API header because they are also used
* by calling code.
*/
@@ -9637,7 +9839,7 @@ DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#if defined(DUK_USE_ASSERTIONS)
#define DUK_ASSERT_SET_GARBAGE(ptr,size) do { \
- DUK_MEMSET((void *) (ptr), 0x5a, size); \
+ duk_memset_unsafe((void *) (ptr), 0x5a, size); \
} while (0)
#else
#define DUK_ASSERT_SET_GARBAGE(ptr,size) do {} while (0)
@@ -9915,13 +10117,13 @@ DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, d
* Automatically generated by extract_chars.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_ids_noa[1036];
+extern const duk_uint8_t duk_unicode_ids_noa[1063];
#else
/*
* Automatically generated by extract_chars.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_ids_noabmp[625];
+extern const duk_uint8_t duk_unicode_ids_noabmp[626];
#endif
#if defined(DUK_USE_SOURCE_NONBMP)
@@ -9943,13 +10145,13 @@ extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24];
* Automatically generated by extract_chars.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_idp_m_ids_noa[530];
+extern const duk_uint8_t duk_unicode_idp_m_ids_noa[549];
#else
/*
* Automatically generated by extract_chars.py, do not edit!
*/
-extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[357];
+extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[358];
#endif
/*
@@ -10090,7 +10292,7 @@ typedef struct {
#endif /* DUK_JSON_H_INCLUDED */
/* #include duk_js.h */
/*
- * Ecmascript execution, support primitives.
+ * ECMAScript execution, support primitives.
*/
#if !defined(DUK_JS_H_INCLUDED)
@@ -10134,6 +10336,9 @@ DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuf
#endif
DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
+#if defined(DUK_USE_SYMBOL_BUILTIN)
+DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof_ordinary(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
+#endif
DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
DUK_INTERNAL_DECL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x);
@@ -10202,7 +10407,7 @@ DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
/* #include duk_numconv.h */
/*
* Number-to-string conversion. The semantics of these is very tightly
- * bound with the Ecmascript semantics required for call sites.
+ * bound with the ECMAScript semantics required for call sites.
*/
#if !defined(DUK_NUMCONV_H_INCLUDED)
@@ -10235,9 +10440,13 @@ DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
/* Maximum exponent value when parsing numbers. This is not strictly
* compliant as there should be no upper limit, but as we parse the
- * exponent without a bigint, impose some limit.
+ * exponent without a bigint, impose some limit. The limit should be
+ * small enough that multiplying it (or limit-1 to be precise) won't
+ * overflow signed 32-bit integer range. Exponent is only parsed with
+ * radix 10, but with maximum radix (36) a safe limit is:
+ * (10000000*36).toString(16) -> '15752a00'
*/
-#define DUK_S2N_MAX_EXPONENT 1000000000
+#define DUK_S2N_MAX_EXPONENT 10000000L
/* Trim white space (= allow leading and trailing whitespace) */
#define DUK_S2N_FLAG_TRIM_WHITE (1U << 0)
@@ -10508,7 +10717,7 @@ DUK_INTERNAL void duk_debug_log(duk_int_t level, const char *file, duk_int_t lin
va_start(ap, fmt);
- DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
+ duk_memzero((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
arg_level = (long) level;
@@ -10539,7 +10748,7 @@ DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
va_start(ap, fmt);
- DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
+ duk_memzero((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
arg_level = (long) duk_debug_level_stash;
@@ -10579,7 +10788,7 @@ DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
#if defined(DUK_USE_ROM_STRINGS)
#error ROM support not enabled, rerun configure.py with --rom-support
#else /* DUK_USE_ROM_STRINGS */
-DUK_INTERNAL const duk_uint8_t duk_strings_data[892] = {
+DUK_INTERNAL const duk_uint8_t duk_strings_data[967] = {
79,40,209,144,168,105,6,78,54,139,89,185,44,48,46,90,120,8,154,140,35,103,
35,113,193,73,5,52,112,180,104,166,135,52,188,4,98,12,27,146,156,80,211,31,
129,115,150,64,52,220,109,24,18,68,156,24,38,67,114,36,55,9,119,151,132,
@@ -10601,36 +10810,40 @@ DUK_INTERNAL const duk_uint8_t duk_strings_data[892] = {
249,110,128,126,88,95,133,109,237,237,237,151,235,127,46,249,119,203,190,
186,206,33,181,2,208,61,190,12,19,34,65,19,81,132,108,228,97,1,107,33,12,
32,45,100,137,64,247,175,9,19,155,41,198,130,155,134,69,146,100,227,226,
-231,146,51,192,204,73,140,224,145,221,102,241,68,196,157,34,79,143,139,166,
-233,225,228,227,138,157,173,167,197,211,118,214,210,38,238,74,113,67,76,
-105,187,169,147,154,73,225,228,32,193,48,25,100,105,166,113,200,147,44,166,
-1,40,79,18,150,134,147,141,163,2,72,171,115,147,136,4,65,130,96,35,64,194,
-32,168,89,56,208,48,135,123,144,217,146,39,220,228,193,19,18,101,220,227,
-73,121,167,115,129,196,200,39,12,136,220,225,93,22,1,114,62,231,42,8,176,
-15,62,231,36,234,68,68,70,231,30,45,37,161,164,38,231,24,7,159,115,149,4,
-72,218,171,115,133,67,64,180,100,145,54,231,42,5,208,135,19,152,244,44,133,
-67,95,73,164,145,143,5,18,2,100,65,35,30,76,241,117,134,70,212,103,37,204,
-16,72,154,218,130,77,196,145,63,127,123,106,141,25,11,189,243,169,198,132,
-251,235,119,247,182,154,6,239,124,234,113,161,62,250,221,253,237,164,52,
-187,223,58,156,104,79,190,187,127,123,105,168,105,119,190,117,56,208,159,
-125,118,254,246,209,104,209,111,124,234,113,161,62,250,205,253,162,209,162,
-249,212,227,66,125,244,161,137,0,162,8,18,33,68,9,136,232,19,155,52,54,132,
-64,200,26,24,196,137,198,66,130,139,153,134,69,146,100,16,220,66,46,68,57,
-80,208,45,120,25,93,20,22,141,20,208,230,137,5,18,26,164,54,83,3,68,71,20,
-109,37,141,18,78,145,105,165,100,76,71,36,206,137,22,103,139,172,57,199,6,
-158,30,71,20,117,4,74,39,54,83,37,92,129,150,199,66,200,75,34,103,40,150,9,
-72,132,109,24,98,93,238,140,206,75,204,141,28,140,134,61,209,153,101,71,
-146,36,109,22,178,78,52,33,74,5,200,138,67,30,178,48,141,156,146,134,204,
-145,40,4,65,172,147,59,192,37,0,196,59,226,138,130,100,75,226,233,144,83,
-32,204,250,5,104,17,165,48,77,2,46,16,69,140,
+231,146,51,192,204,73,140,224,145,221,102,241,68,196,169,248,30,75,12,11,
+151,242,233,187,143,138,24,137,162,164,255,253,63,3,201,97,129,114,254,92,
+112,75,136,108,166,6,136,159,255,167,224,121,44,48,46,95,203,166,238,74,
+113,67,77,201,128,223,255,223,224,121,44,48,46,95,203,145,46,9,205,16,39,
+201,62,36,0,192,21,147,255,238,145,39,199,197,211,116,240,242,113,197,78,
+214,211,226,233,187,107,105,19,119,37,56,161,166,52,221,212,201,205,36,240,
+242,16,96,152,12,178,52,211,56,228,73,150,83,0,148,39,137,75,67,73,198,209,
+129,36,85,185,201,196,2,32,193,48,17,160,97,16,84,44,156,104,24,67,189,200,
+108,201,19,238,114,96,137,137,50,238,113,164,188,211,185,192,226,100,19,
+134,68,110,112,174,139,0,185,31,115,149,4,88,7,159,115,146,117,34,34,35,
+115,143,22,146,208,210,19,115,140,3,207,185,202,130,36,109,85,185,194,161,
+160,90,50,72,155,115,149,2,232,67,137,204,122,22,66,161,175,164,210,72,199,
+130,137,1,50,32,145,143,38,120,186,195,35,106,51,146,230,8,36,77,109,65,38,
+226,72,159,191,189,181,70,140,133,222,249,212,227,66,125,245,187,251,219,
+77,3,119,190,117,56,208,159,125,110,254,246,210,26,93,239,157,78,52,39,223,
+93,191,189,180,212,52,187,223,58,156,104,79,190,187,127,123,104,180,104,
+183,190,117,56,208,159,125,102,254,209,104,209,124,234,113,161,62,250,80,
+196,128,81,4,9,16,162,4,196,116,9,205,154,27,66,32,100,13,12,98,68,227,33,
+65,69,204,195,34,201,50,8,110,33,23,34,28,168,104,22,188,12,174,138,11,70,
+138,104,115,68,130,137,13,82,27,41,129,162,35,138,54,146,198,137,39,72,180,
+210,178,38,35,146,103,68,139,51,197,214,28,227,131,79,15,35,138,58,130,37,
+19,155,41,146,174,64,203,99,161,100,37,145,51,148,75,4,164,66,54,140,49,46,
+247,70,103,37,230,70,142,70,67,30,232,204,178,163,201,18,54,139,89,39,26,
+16,165,2,228,69,33,143,89,24,70,206,73,67,102,72,148,2,32,214,73,157,224,
+18,128,98,29,241,69,65,50,37,241,116,200,41,144,102,125,2,180,8,210,152,38,
+129,23,8,34,198,
};
#endif /* DUK_USE_ROM_STRINGS */
#if defined(DUK_USE_ROM_OBJECTS)
#error ROM support not enabled, rerun configure.py with --rom-support
#else /* DUK_USE_ROM_OBJECTS */
-/* native functions: 176 */
-DUK_INTERNAL const duk_c_function duk_bi_native_functions[176] = {
+/* native functions: 177 */
+DUK_INTERNAL const duk_c_function duk_bi_native_functions[177] = {
NULL,
duk_bi_array_constructor,
duk_bi_array_constructor_is_array,
@@ -10723,6 +10936,7 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[176] = {
duk_bi_nodejs_buffer_tojson,
duk_bi_nodejs_buffer_tostring,
duk_bi_nodejs_buffer_write,
+ duk_bi_number_check_shared,
duk_bi_number_constructor,
duk_bi_number_prototype_to_exponential,
duk_bi_number_prototype_to_fixed,
@@ -10809,556 +11023,577 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[176] = {
duk_bi_uint8array_plainof,
};
#if defined(DUK_USE_DOUBLE_LE)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = {
-144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242,
-252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33,
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[4116] = {
+144,148,105,224,32,68,52,228,62,12,104,200,165,132,52,167,194,138,105,243,
+124,57,28,211,57,18,64,52,238,126,44,138,111,171,241,164,19,87,129,30,33,
167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
-1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
-33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17,
-13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192,
-0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188,
-0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85,
-217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225,
-146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,0,0,0,0,
-0,0,3,225,255,51,0,0,0,0,0,0,3,193,255,47,18,1,172,19,120,71,10,25,196,136,
-113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,2,
-185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,130,
-249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,138,
-9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,190,15,
-38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,53,64,
-243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,124,
-35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,116,
-88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,240,70,
-68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,51,132,
-9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,105,27,
-60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,117,204,
-123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,65,112,
-152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,39,199,
-89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,58,205,
-227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,133,18,
-2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,39,31,23,
-60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,18,84,141,
-159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,194,197,
-217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,32,130,
-166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,151,21,0,
-100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,214,111,
-31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,10,62,
-46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,52,
-156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142,
-214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173,
-165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6,
-143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62,
-180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129,
-54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,
-178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,
-129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,
-201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,
-132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,
-46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35,
-193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194,
-133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56,
-9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14,
-134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184,
-64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6,
-145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67,
-77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113,
-110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113,
-110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2,
-127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4,
-33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207,
-4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,255,255,255,255,255,255,
-239,127,19,214,33,187,85,2,232,72,0,32,0,0,0,0,0,0,25,136,0,0,0,0,0,0,31,
-15,228,122,247,73,19,69,73,180,134,149,13,68,241,0,0,0,0,0,0,3,193,252,143,
-90,67,2,104,169,54,144,210,161,168,158,32,0,0,0,0,0,0,120,127,142,73,78,20,
-0,0,0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,68,
-13,155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,
-222,17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,
-112,164,0,0,0,0,0,0,124,63,226,117,119,128,25,55,112,96,153,57,41,197,13,
-53,224,65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,
-22,78,12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,
-113,67,77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,
-97,47,128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,
-190,96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,
-206,185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,
-76,150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,
-39,195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,
-39,198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,
-163,18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,
-100,40,15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,
-11,90,36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,
-157,160,3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,
-178,166,74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,
-9,205,28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,
-49,13,164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,
-34,79,135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,
-137,62,12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,
-199,54,103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,
-147,225,104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,
-54,223,224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,
-7,38,193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,
-89,252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,
-131,64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,
-231,197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,
-228,74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,
-235,1,64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,
-64,174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,
-168,167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,
-19,177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,0,0,0,0,0,93,105,160,91,
-60,149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168,
-110,20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115,
-36,14,100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145,
-139,163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166,
-28,1,204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145,
-92,203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41,
-100,73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177,
-69,49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99,
-68,152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9,
-49,39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,
-98,79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,
-249,68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,
-136,108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,
-16,217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,
-194,173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,
-89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,104,71,161,196,201,45,167,146,59,
-68,89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,136,71,161,196,201,45,167,146,
-59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,153,51,168,71,161,196,201,45,167,
-146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,153,51,200,71,161,196,201,45,167,
-146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,153,51,232,71,161,196,201,45,167,
-146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,8,71,161,196,201,45,167,
-146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,40,71,161,196,201,45,167,
-146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,153,52,72,71,161,196,201,45,167,
-146,59,68,89,24,70,206,0,0,0,0,0,0,1,2,1,135,52,102,32,76,72,1,246,136,235,
-103,177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,
-171,37,20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,
-158,142,183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,
-246,136,235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,
-37,20,138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,
-75,161,37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,
-39,208,146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,
-129,89,58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,
-17,214,207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,
-207,161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,
-207,98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,
-78,209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,
-146,155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,
-104,142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,
-146,155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,
-217,233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,
-162,137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,
-77,156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,
-117,179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,
-162,100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,
-102,53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,
-72,16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,
-52,171,138,69,133,95,130,160,4,234,219,163,161,0,89,86,214,238,197,172,9,0,
-31,86,221,40,29,231,63,95,200,69,220,199,225,122,183,27,72,144,63,160,138,
-217,81,197,125,207,195,117,110,54,142,129,32,7,114,147,10,189,229,237,159,
-130,235,209,0,96,181,17,83,236,132,37,0,63,101,8,207,71,107,74,6,105,219,
-251,52,245,7,49,248,94,202,17,158,148,12,211,183,246,105,234,15,99,242,159,
-129,228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,
-192,25,106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,
-27,165,171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,
-32,24,157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,
-188,8,134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,
-13,65,74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,
-72,1,98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,
-81,129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,
-153,78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,
-128,0,10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,
-164,237,35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,
-120,96,196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,
-16,113,137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,
-100,108,144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,
-108,185,36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,
-10,4,28,200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,
-138,89,18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,
-80,17,42,4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,
-48,141,156,0,0,0,0,0,0,15,3,243,49,135,16,143,67,137,146,91,79,36,118,136,
-178,48,141,156,0,0,0,0,0,0,15,3,245,20,5,173,194,227,214,4,55,0,0,21,196,7,
-122,192,134,241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,
-69,145,132,108,224,0,0,0,0,0,0,120,31,153,140,72,132,122,28,76,146,218,121,
-35,180,69,145,132,108,224,0,0,0,0,0,0,0,32,25,140,80,132,122,28,76,146,218,
-121,35,180,69,145,132,108,224,0,0,0,0,0,0,0,32,25,140,88,132,122,28,76,146,
-218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,96,132,122,28,76,
-146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,104,132,122,
-28,76,146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,8,32,25,140,112,
-132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,16,32,16,
-113,225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,18,224,
-104,82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,70,131,
-165,1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,7,78,3,
-154,102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,232,
-147,161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0,
+1,82,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
+33,8,66,26,179,233,97,167,60,150,34,33,154,112,0,1,75,247,35,79,95,237,198,
+174,200,47,31,23,95,17,13,51,19,35,93,68,216,209,128,0,10,208,174,79,15,32,
+248,8,196,24,8,107,192,0,5,106,118,27,94,0,0,43,83,227,94,0,0,43,84,46,215,
+128,0,10,213,28,198,188,0,0,86,169,100,53,224,0,2,181,79,85,175,0,0,21,170,
+154,45,120,0,0,173,85,217,107,192,0,5,106,182,243,86,193,106,52,127,130,
+249,50,94,124,35,68,225,146,49,13,31,186,23,201,146,243,224,200,39,12,145,
+136,67,134,19,49,0,0,0,0,0,0,3,225,255,51,0,0,0,0,0,0,3,193,255,47,18,1,
+172,19,120,71,10,25,196,136,113,162,156,136,199,42,57,204,144,115,132,240,
+149,2,248,72,197,209,58,2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,
+141,17,56,72,197,209,58,130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,
+132,140,93,19,176,35,180,138,9,216,197,209,59,82,79,35,40,242,65,248,58,42,
+96,121,14,232,94,62,46,190,15,42,31,145,33,86,65,76,242,214,143,73,48,242,
+243,79,49,56,243,115,207,57,64,243,180,79,61,72,243,244,207,65,80,244,53,
+79,69,88,244,98,30,8,200,156,67,102,120,241,79,4,100,78,21,110,4,207,32,47,
+147,37,231,194,52,78,25,34,122,81,124,153,47,62,12,130,112,201,19,211,139,
+121,34,87,69,128,104,137,239,83,18,238,108,165,2,162,92,104,56,220,233,1,8,
+151,10,134,162,100,206,16,18,50,9,195,39,105,20,101,136,18,25,4,225,147,
+180,138,5,215,49,238,105,27,60,185,1,36,104,156,50,118,145,70,96,129,34,52,
+78,25,59,72,160,93,115,30,230,145,179,204,144,12,73,8,15,38,104,128,138,52,
+146,16,30,77,1,0,2,11,132,193,198,36,248,248,186,110,158,30,78,56,188,194,
+70,183,170,136,48,98,79,142,179,120,248,185,228,140,241,193,146,66,138,31,
+55,71,138,128,153,137,62,58,205,227,226,231,146,51,199,26,6,18,92,146,64,
+96,74,72,51,120,43,192,97,68,128,153,56,72,7,12,133,67,73,199,197,207,36,
+103,142,35,2,3,33,80,210,113,241,115,201,25,160,146,225,160,9,34,1,124,178,
+1,139,18,19,36,229,146,8,190,36,169,27,62,18,243,35,100,135,54,92,162,2,17,
+46,72,128,89,7,200,32,33,18,225,98,236,145,188,130,64,196,75,132,188,200,
+217,32,43,39,28,128,69,19,18,228,144,42,98,79,142,179,120,248,185,228,140,
+241,201,97,129,114,229,201,37,2,68,184,200,1,147,93,159,153,213,34,235,250,
+96,48,157,32,24,94,160,1,199,4,184,235,55,143,139,158,72,207,28,226,3,81,
+46,62,46,155,167,135,147,142,47,60,129,71,197,207,36,103,142,34,92,35,104,
+194,68,1,89,58,36,8,109,109,12,133,67,73,195,18,115,36,118,182,185,168,8,
+109,109,12,133,67,73,201,18,115,36,118,182,185,168,130,27,91,75,115,149,71,
+240,196,156,201,29,173,174,129,2,27,91,75,115,149,71,242,68,156,201,29,173,
+174,129,34,12,16,28,128,62,191,42,3,71,146,68,4,16,22,188,161,240,16,40,
+104,242,103,196,16,93,158,125,96,110,115,235,64,131,16,16,58,37,192,70,32,
+194,144,114,25,67,95,40,6,18,8,32,48,156,209,2,108,124,96,224,144,6,247,62,
+16,0,143,164,143,12,248,15,18,84,145,145,34,128,11,35,160,179,140,0,44,150,
+129,18,58,0,146,116,103,32,128,105,61,104,17,36,175,1,232,217,29,5,156,179,
+224,58,26,50,95,142,43,159,64,181,130,83,226,26,50,95,142,43,159,192,7,255,
+248,41,42,72,226,1,160,18,78,97,32,26,64,114,186,60,32,4,120,6,148,13,128,
+124,3,76,12,84,46,100,140,3,78,13,18,14,130,36,67,232,23,18,14,130,39,34,
+131,30,113,15,224,3,255,253,6,48,40,194,197,204,224,142,8,240,78,25,60,231,
+192,210,197,204,224,156,50,113,238,67,103,232,62,28,138,156,104,82,170,107,
+255,32,48,191,144,1,132,112,71,128,159,168,128,161,28,17,224,156,50,112,19,
+245,144,22,39,12,156,123,144,217,240,19,245,146,3,9,205,16,39,236,62,3,161,
+163,37,248,226,251,141,1,107,4,167,196,52,100,191,28,95,113,164,13,91,132,
+5,147,130,115,30,8,147,222,64,43,1,49,31,224,64,60,72,245,128,68,249,32,13,
+34,2,34,63,204,128,89,45,2,39,209,0,89,61,104,159,213,0,153,80,50,156,80,
+211,126,16,11,155,184,183,88,145,224,129,34,122,64,17,155,184,183,8,11,39,
+22,235,18,60,16,36,79,72,1,115,119,40,247,146,60,16,36,79,72,32,140,221,
+197,184,64,89,57,71,188,145,224,129,34,122,65,1,39,20,51,244,0,52,72,242,2,
+127,18,2,165,48,70,114,229,145,51,253,141,1,4,104,229,203,34,103,251,26,64,
+132,52,75,160,201,47,105,160,26,84,12,167,31,186,8,50,0,114,58,113,163,46,
+190,120,35,11,60,4,25,68,81,61,96,47,181,80,46,132,129,255,255,255,255,255,
+255,222,254,39,172,67,118,170,5,208,144,0,64,0,0,0,0,0,0,51,16,0,0,0,0,0,0,
+62,31,200,245,238,146,38,138,147,105,13,42,26,137,226,0,0,0,0,0,0,7,131,
+249,30,180,134,4,209,82,109,33,165,67,81,60,64,0,0,0,0,0,0,240,255,15,210,
+62,72,91,155,0,0,0,0,0,0,2,192,240,135,88,11,237,72,5,38,210,27,50,24,145,
+129,255,255,255,255,255,254,126,134,67,172,67,118,164,2,147,105,13,153,12,
+72,192,255,255,255,255,255,255,63,195,16,240,70,68,226,27,51,199,138,120,
+35,34,112,171,112,38,121,7,16,137,112,168,106,38,77,193,1,40,151,16,217,
+144,196,142,224,144,21,18,227,65,198,238,9,67,81,46,72,5,39,16,217,144,196,
+142,224,152,228,148,227,64,0,0,0,0,0,0,0,0,131,175,223,16,194,111,8,97,119,
+224,3,205,220,42,46,65,238,200,13,155,184,75,189,205,35,102,128,47,116,64,
+92,221,199,196,130,68,144,230,239,72,65,152,12,21,224,140,137,92,128,62,
+210,98,177,252,3,107,173,88,3,146,211,141,32,0,0,0,0,0,3,225,255,19,175,
+188,0,100,221,193,130,100,228,167,20,52,215,129,3,38,238,77,12,39,37,56,
+161,166,188,10,194,94,6,18,155,184,183,8,11,39,6,9,147,146,156,80,211,94,7,
+18,155,184,183,8,11,39,38,134,19,146,156,80,211,94,8,12,53,224,130,195,222,
+8,77,133,210,24,91,224,3,152,147,228,208,194,95,0,44,196,159,11,69,175,152,
+32,35,100,33,135,24,147,237,38,34,246,139,95,48,64,70,200,68,8,49,39,198,
+57,179,61,144,138,22,98,79,180,152,153,215,54,103,178,17,129,204,73,240,96,
+153,44,132,112,163,18,125,164,196,62,130,100,178,18,1,140,73,240,96,197,
+144,146,18,98,79,180,152,135,208,98,200,74,8,49,39,195,186,145,149,144,150,
+22,98,79,180,152,143,215,82,50,178,19,2,140,73,241,136,109,38,73,89,9,161,
+166,36,251,73,137,157,67,105,50,74,200,78,10,49,39,201,16,78,104,229,100,
+39,134,152,147,237,38,41,116,130,115,71,43,33,64,60,196,159,24,133,173,18,
+32,156,209,202,200,81,18,49,39,218,76,76,234,22,180,72,130,115,71,43,33,72,
+68,196,159,38,134,19,46,105,56,226,150,68,157,160,1,228,73,242,104,97,46,
+16,31,34,79,140,66,214,137,16,78,104,229,108,169,137,72,147,237,38,38,117,
+11,90,36,65,57,163,149,178,168,21,34,79,146,32,156,209,202,218,250,161,178,
+36,251,73,138,93,32,156,209,202,218,250,193,82,36,248,196,54,147,36,173,
+191,174,27,34,79,180,152,153,212,54,147,36,173,191,176,17,34,79,135,117,35,
+43,115,236,133,200,147,237,38,35,245,212,140,173,207,180,15,34,79,131,4,
+201,108,173,133,72,147,237,38,33,244,19,37,178,184,17,34,79,140,115,102,
+123,107,238,133,200,147,237,38,38,117,205,153,237,175,188,23,34,79,133,162,
+215,204,16,17,182,254,248,116,137,62,210,98,47,104,181,243,4,4,109,191,192,
+131,152,147,230,8,8,217,12,16,60,137,62,96,128,141,178,193,160,206,1,201,
+176,113,146,0,0,0,0,0,0,0,0,49,185,252,65,137,207,227,37,215,207,227,12,86,
+127,24,152,188,254,49,88,33,46,65,120,72,4,153,37,63,33,13,127,148,4,26,0,
+57,62,6,228,163,228,74,86,215,62,55,28,110,179,226,113,70,223,62,47,24,38,
+191,30,2,125,32,40,20,87,114,41,225,42,5,240,145,139,163,145,41,68,250,128,
+80,41,174,228,85,200,129,166,39,9,24,186,57,18,148,79,172,5,2,170,238,69,
+220,137,10,72,145,162,39,9,24,186,57,18,148,79,176,5,2,186,238,69,124,150,
+27,48,95,132,140,93,28,137,74,39,218,2,129,101,119,34,158,79,15,39,9,24,
+186,57,18,148,79,184,5,2,218,238,69,29,164,80,78,198,46,142,68,165,16,64,
+28,24,61,73,25,33,205,128,0,0,0,0,1,167,166,129,108,242,151,15,39,8,34,26,
+87,97,200,3,0,167,129,32,8,194,195,16,6,84,55,10,60,3,35,69,132,30,1,140,
+130,193,143,1,196,230,60,2,158,8,131,153,64,115,42,46,191,176,8,194,246,0,
+80,5,220,193,95,6,234,5,100,225,35,23,71,35,6,228,140,93,29,180,55,108,145,
+139,163,182,112,52,107,67,76,56,3,153,132,20,28,76,156,89,26,105,158,62,0,
+0,42,193,2,201,104,17,41,34,156,204,176,160,226,100,226,200,211,76,241,240,
+0,1,86,2,131,137,147,142,41,100,73,199,192,0,5,96,6,13,10,82,70,62,0,0,42,
+130,88,115,18,124,67,103,177,69,49,129,6,36,249,68,54,123,20,82,216,65,137,
+62,33,179,209,214,162,152,208,147,18,124,162,27,61,29,106,41,112,32,196,
+159,16,217,233,233,81,76,112,73,137,62,81,13,158,158,149,20,186,20,98,79,
+133,91,129,61,61,42,41,120,40,196,159,10,183,2,122,218,148,82,248,60,137,
+62,33,179,216,166,216,192,137,18,124,162,27,61,138,109,108,34,68,159,16,
+217,232,235,83,108,104,76,137,62,81,13,158,142,181,54,184,17,34,79,136,108,
+244,244,169,182,56,38,68,159,40,134,207,79,74,155,93,10,145,39,194,173,192,
+158,158,149,54,188,21,34,79,133,91,129,61,109,74,109,125,155,51,136,71,161,
+196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,155,51,168,71,
+161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,155,51,200,
+71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,155,51,
+232,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,155,52,
+8,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,155,52,40,
+71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,155,52,72,
+71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,155,52,
+104,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,155,
+52,136,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,1,2,1,135,
+52,166,32,76,72,1,246,136,235,103,177,69,0,136,144,3,226,27,61,138,41,44,
+50,36,0,251,68,117,179,209,214,234,201,69,16,50,36,0,251,68,117,179,209,
+214,232,73,69,34,5,196,128,31,16,217,232,235,117,100,162,147,2,226,64,15,
+136,108,244,117,186,18,81,74,129,145,32,7,218,35,173,158,158,151,86,74,40,
+161,145,32,7,218,35,173,158,158,151,66,74,41,20,46,36,0,248,134,207,79,75,
+171,37,20,154,23,18,0,124,67,103,167,165,208,146,138,85,11,137,0,62,21,110,
+4,250,178,81,70,11,137,0,62,21,110,4,250,18,81,72,193,145,32,7,193,186,129,
+89,58,178,81,71,12,137,0,62,13,212,10,201,208,146,138,71,10,137,0,62,209,
+29,108,250,178,81,104,1,81,32,7,218,35,173,159,66,74,45,32,38,36,0,248,134,
+207,171,37,22,160,19,18,0,124,67,103,208,146,139,88,10,180,81,50,118,136,
+235,103,177,77,128,155,69,19,39,16,217,236,83,105,97,182,138,38,78,209,29,
+108,244,117,186,178,83,100,13,180,81,50,118,136,235,103,163,173,208,146,
+155,68,12,180,81,50,113,13,158,142,183,86,74,109,48,50,209,68,201,196,54,
+122,58,221,9,41,181,64,219,69,19,39,104,142,182,122,122,93,89,41,178,134,
+218,40,153,59,68,117,179,211,210,232,73,77,162,134,90,40,153,56,134,207,79,
+75,171,37,54,154,25,104,162,100,226,27,61,61,46,132,148,218,168,101,162,
+137,147,133,91,129,62,172,148,217,131,45,20,76,156,42,220,9,244,36,166,209,
+131,109,20,76,156,27,168,21,147,171,37,54,112,219,69,19,39,6,234,5,100,232,
+73,77,163,133,218,40,153,59,68,117,179,234,201,78,32,5,218,40,153,59,68,
+117,179,232,73,78,36,5,90,40,153,56,134,207,171,37,56,160,21,104,162,100,
+226,27,62,132,148,226,195,95,182,97,176,218,128,8,84,45,123,38,1,137,10,1,
+114,160,64,56,156,199,130,36,160,72,8,39,63,27,24,1,100,180,8,148,146,0,45,
+162,137,147,111,2,8,4,16,7,8,96,120,72,13,42,226,145,97,87,224,168,1,58,
+182,232,232,64,22,85,181,187,177,107,2,64,7,213,183,74,7,121,207,215,242,
+17,119,49,248,94,173,198,210,36,15,232,34,182,84,113,95,115,240,221,91,141,
+163,160,72,1,220,164,194,175,121,123,103,224,186,244,64,24,45,68,84,251,33,
+9,64,15,217,66,51,209,218,210,129,154,118,254,205,61,65,204,126,23,178,132,
+103,165,3,52,237,253,154,122,131,216,254,168,48,6,90,130,1,0,39,75,80,72,8,
+9,33,186,130,80,64,76,13,212,19,2,130,96,110,150,173,0,65,6,51,212,20,128,
+65,17,11,212,19,130,137,121,211,210,209,144,6,39,75,80,80,0,201,119,234,10,
+8,41,86,231,71,80,80,129,79,135,186,122,69,224,34,25,69,233,80,3,91,141,
+168,40,96,139,113,180,181,5,36,21,110,54,142,134,160,165,1,176,23,211,47,0,
+216,134,233,215,128,111,117,181,104,128,209,3,70,230,106,64,5,139,168,209,
+234,10,32,36,144,102,234,136,3,146,27,168,40,160,146,132,103,168,40,192,
+115,3,117,5,28,22,113,163,69,168,41,103,1,66,188,17,145,52,40,4,202,113,67,
+76,130,227,68,194,13,240,108,0,0,83,96,0,2,161,0,104,146,84,97,48,0,1,78,
+192,56,169,24,145,179,192,0,5,48,8,56,16,32,128,56,18,52,125,166,86,147,
+182,140,28,50,21,13,39,31,23,60,145,158,56,140,141,47,113,6,155,186,188,24,
+49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,197,68,14,49,
+39,199,197,211,116,240,242,113,197,230,18,180,253,228,3,17,46,18,243,35,
+100,128,172,156,114,70,163,146,76,34,248,146,164,108,248,75,204,141,146,28,
+217,114,137,27,78,251,241,173,234,162,160,225,1,3,34,92,170,9,105,164,32,
+225,64,131,155,1,193,133,7,19,39,22,70,154,103,143,128,0,10,176,20,28,76,
+156,113,75,34,78,62,0,0,43,0,48,104,82,146,49,240,0,1,84,11,180,192,0,5,
+114,1,18,160,65,24,131,20,145,25,172,48,132,122,28,76,146,218,121,35,180,
+69,145,132,108,224,0,0,0,0,0,0,120,31,153,172,56,132,122,28,76,146,218,121,
+35,180,69,145,132,108,224,0,0,0,0,0,0,120,31,168,160,45,110,23,30,176,33,
+184,0,0,175,32,29,235,2,27,199,23,0,0,22,4,51,88,129,8,244,56,153,37,180,
+242,71,104,139,35,8,217,192,0,0,0,0,0,0,240,63,51,88,145,8,244,56,153,37,
+180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,0,64,51,88,161,8,244,56,153,37,
+180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,0,64,51,88,177,8,244,56,153,37,
+180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,88,193,8,244,56,153,
+37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,88,209,8,244,56,
+153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,88,225,8,244,
+56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,32,64,32,227,194,0,
+97,57,162,4,245,232,5,34,92,35,68,225,161,166,218,16,16,137,112,52,41,73,
+29,153,1,65,196,201,197,145,166,153,245,200,3,137,204,120,34,74,8,200,58,
+112,28,211,32,130,52,78,26,26,110,248,0,0,164,4,12,70,137,195,39,252,73,
+240,117,32,57,168,97,4,104,156,52,52,221,255,160,20,160,152,23,223,250,32,
+148,25,174,137,58,23,51,191,244,84,12,50,9,195,39,240,81,238,2,3,107,173,
+214,3,192,
};
#elif defined(DUK_USE_DOUBLE_BE)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = {
-144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242,
-252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33,
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[4116] = {
+144,148,105,224,32,68,52,228,62,12,104,200,165,132,52,167,194,138,105,243,
+124,57,28,211,57,18,64,52,238,126,44,138,111,171,241,164,19,87,129,30,33,
167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
-1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
-33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17,
-13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192,
-0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188,
-0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85,
-217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225,
-146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,1,255,
-224,0,0,0,0,0,3,51,1,255,192,0,0,0,0,0,3,47,18,1,172,19,120,71,10,25,196,
-136,113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,
-2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,
-130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,
-138,9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,
-190,15,38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,
-53,64,243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,
-124,35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,
-116,88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,
-240,70,68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,
-51,132,9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,
-105,27,60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,
-117,204,123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,
-65,112,152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,
-39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,
-58,205,227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,
-133,18,2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,
-39,31,23,60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,
-18,84,141,159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,
-194,197,217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,
-32,130,166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,
-151,21,0,100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,
-214,111,31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,
-10,62,46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,
-52,156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142,
-214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173,
-165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6,
-143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62,
-180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129,
-54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,
-178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,
-129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,
-201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,
-132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,
-46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35,
-193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194,
-133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56,
-9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14,
-134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184,
-64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6,
-145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67,
-77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113,
-110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113,
-110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2,
-127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4,
-33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207,
-4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,127,239,255,255,255,255,
-255,255,19,214,33,187,85,2,232,72,0,0,0,0,0,0,0,0,57,136,15,255,0,0,0,0,0,
-0,4,122,247,73,19,69,73,180,134,149,13,68,241,1,255,192,0,0,0,0,0,0,143,90,
-67,2,104,169,54,144,210,161,168,158,32,127,248,0,0,0,0,0,0,14,73,78,20,0,0,
-0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,68,13,
-155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,222,
-17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,112,
-164,63,252,0,0,0,0,0,0,98,117,119,128,25,55,112,96,153,57,41,197,13,53,224,
-65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,22,78,
-12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,113,67,
-77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,97,47,
-128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,190,
-96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,206,
-185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,76,
-150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,39,
-195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,39,
-198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,163,
-18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,100,40,
-15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,11,90,
-36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,157,160,
-3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,178,166,
-74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,9,205,
-28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,49,13,
-164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,34,79,
-135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,137,62,
-12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,199,54,
-103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,147,225,
-104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,54,223,
-224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,7,38,
-193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,89,
-252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,131,
-64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,231,
-197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,228,
-74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,235,1,
-64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,64,
-174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,168,
-167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,19,
-177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,32,105,221,0,0,0,0,0,91,60,
-149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168,110,
-20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115,36,14,
-100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145,139,
-163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166,28,1,
-204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145,92,
-203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41,100,
-73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177,69,
-49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99,68,
-152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9,49,
-39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,98,
-79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,249,
-68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,136,
-108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,16,
-217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,194,
-173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,89,24,
-70,206,1,255,128,0,0,0,0,0,1,153,51,104,71,161,196,201,45,167,146,59,68,89,
-24,70,206,1,255,128,0,0,0,0,0,1,153,51,136,71,161,196,201,45,167,146,59,68,
-89,24,70,206,1,255,128,0,0,0,0,0,1,153,51,168,71,161,196,201,45,167,146,59,
-68,89,24,70,206,2,0,0,0,0,0,0,0,1,153,51,200,71,161,196,201,45,167,146,59,
-68,89,24,70,206,2,0,0,0,0,0,0,0,1,153,51,232,71,161,196,201,45,167,146,59,
-68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,8,71,161,196,201,45,167,146,59,
-68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,40,71,161,196,201,45,167,146,59,
-68,89,24,70,206,2,0,128,0,0,0,0,0,1,153,52,72,71,161,196,201,45,167,146,59,
-68,89,24,70,206,2,1,0,0,0,0,0,0,1,135,52,102,32,76,72,1,246,136,235,103,
-177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,
-20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,
-183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,
-235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,
-138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,
-37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,
-146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,
-58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,
-207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,
-161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207,
-98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,
-209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146,
-155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104,
-142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146,
-155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,
-233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162,
-137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77,
-156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117,
-179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162,
-100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,102,
-53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,72,
-16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,32,2,
-223,133,69,138,43,180,132,234,219,163,161,1,0,9,174,198,238,213,84,88,31,
-86,221,40,7,252,197,200,95,223,71,61,225,122,183,27,72,144,15,253,197,81,
-217,74,224,191,131,117,110,54,142,129,32,31,237,229,189,138,147,114,135,2,
-235,209,1,0,36,135,237,81,16,180,96,63,101,8,207,71,107,74,1,255,53,4,243,
-51,249,222,104,94,202,17,158,148,3,255,106,9,230,103,243,188,210,159,129,
-228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,192,25,
-106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,27,165,
-171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,32,24,
-157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,188,8,
-134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,13,65,
-74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,72,1,
-98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,81,
-129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,153,
-78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,128,0,
-10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,164,237,
-35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,120,96,
-196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,16,113,
-137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,100,108,
-144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,108,185,
-36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,10,4,28,
-200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,138,89,
-18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,80,17,42,
-4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,48,141,156,
-3,255,0,0,0,0,0,0,3,49,135,16,143,67,137,146,91,79,36,118,136,178,48,141,
-156,3,255,0,0,0,0,0,0,5,20,5,173,194,227,214,4,55,0,0,21,196,7,122,192,134,
-241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,69,145,132,
-108,224,31,248,0,0,0,0,0,0,25,140,72,132,122,28,76,146,218,121,35,180,69,
-145,132,108,224,32,0,0,0,0,0,0,0,25,140,80,132,122,28,76,146,218,121,35,
-180,69,145,132,108,224,32,0,0,0,0,0,0,0,25,140,88,132,122,28,76,146,218,
-121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,96,132,122,28,76,146,
-218,121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,104,132,122,28,
-76,146,218,121,35,180,69,145,132,108,224,32,8,0,0,0,0,0,0,25,140,112,132,
-122,28,76,146,218,121,35,180,69,145,132,108,224,32,16,0,0,0,0,0,0,16,113,
-225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,18,224,104,
-82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,70,131,165,
-1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,7,78,3,154,
-102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,232,147,
-161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0,
+1,82,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
+33,8,66,26,179,233,97,167,60,150,34,33,154,112,0,1,75,247,35,79,95,237,198,
+174,200,47,31,23,95,17,13,51,19,35,93,68,216,209,128,0,10,208,174,79,15,32,
+248,8,196,24,8,107,192,0,5,106,118,27,94,0,0,43,83,227,94,0,0,43,84,46,215,
+128,0,10,213,28,198,188,0,0,86,169,100,53,224,0,2,181,79,85,175,0,0,21,170,
+154,45,120,0,0,173,85,217,107,192,0,5,106,182,243,86,193,106,52,127,130,
+249,50,94,124,35,68,225,146,49,13,31,186,23,201,146,243,224,200,39,12,145,
+136,67,134,19,49,1,255,224,0,0,0,0,0,3,51,1,255,192,0,0,0,0,0,3,47,18,1,
+172,19,120,71,10,25,196,136,113,162,156,136,199,42,57,204,144,115,132,240,
+149,2,248,72,197,209,58,2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,
+141,17,56,72,197,209,58,130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,
+132,140,93,19,176,35,180,138,9,216,197,209,59,82,79,35,40,242,65,248,58,42,
+96,121,14,232,94,62,46,190,15,42,31,145,33,86,65,76,242,214,143,73,48,242,
+243,79,49,56,243,115,207,57,64,243,180,79,61,72,243,244,207,65,80,244,53,
+79,69,88,244,98,30,8,200,156,67,102,120,241,79,4,100,78,21,110,4,207,32,47,
+147,37,231,194,52,78,25,34,122,81,124,153,47,62,12,130,112,201,19,211,139,
+121,34,87,69,128,104,137,239,83,18,238,108,165,2,162,92,104,56,220,233,1,8,
+151,10,134,162,100,206,16,18,50,9,195,39,105,20,101,136,18,25,4,225,147,
+180,138,5,215,49,238,105,27,60,185,1,36,104,156,50,118,145,70,96,129,34,52,
+78,25,59,72,160,93,115,30,230,145,179,204,144,12,73,8,15,38,104,128,138,52,
+146,16,30,77,1,0,2,11,132,193,198,36,248,248,186,110,158,30,78,56,188,194,
+70,183,170,136,48,98,79,142,179,120,248,185,228,140,241,193,146,66,138,31,
+55,71,138,128,153,137,62,58,205,227,226,231,146,51,199,26,6,18,92,146,64,
+96,74,72,51,120,43,192,97,68,128,153,56,72,7,12,133,67,73,199,197,207,36,
+103,142,35,2,3,33,80,210,113,241,115,201,25,160,146,225,160,9,34,1,124,178,
+1,139,18,19,36,229,146,8,190,36,169,27,62,18,243,35,100,135,54,92,162,2,17,
+46,72,128,89,7,200,32,33,18,225,98,236,145,188,130,64,196,75,132,188,200,
+217,32,43,39,28,128,69,19,18,228,144,42,98,79,142,179,120,248,185,228,140,
+241,201,97,129,114,229,201,37,2,68,184,200,1,147,93,159,153,213,34,235,250,
+96,48,157,32,24,94,160,1,199,4,184,235,55,143,139,158,72,207,28,226,3,81,
+46,62,46,155,167,135,147,142,47,60,129,71,197,207,36,103,142,34,92,35,104,
+194,68,1,89,58,36,8,109,109,12,133,67,73,195,18,115,36,118,182,185,168,8,
+109,109,12,133,67,73,201,18,115,36,118,182,185,168,130,27,91,75,115,149,71,
+240,196,156,201,29,173,174,129,2,27,91,75,115,149,71,242,68,156,201,29,173,
+174,129,34,12,16,28,128,62,191,42,3,71,146,68,4,16,22,188,161,240,16,40,
+104,242,103,196,16,93,158,125,96,110,115,235,64,131,16,16,58,37,192,70,32,
+194,144,114,25,67,95,40,6,18,8,32,48,156,209,2,108,124,96,224,144,6,247,62,
+16,0,143,164,143,12,248,15,18,84,145,145,34,128,11,35,160,179,140,0,44,150,
+129,18,58,0,146,116,103,32,128,105,61,104,17,36,175,1,232,217,29,5,156,179,
+224,58,26,50,95,142,43,159,64,181,130,83,226,26,50,95,142,43,159,192,7,255,
+248,41,42,72,226,1,160,18,78,97,32,26,64,114,186,60,32,4,120,6,148,13,128,
+124,3,76,12,84,46,100,140,3,78,13,18,14,130,36,67,232,23,18,14,130,39,34,
+131,30,113,15,224,3,255,253,6,48,40,194,197,204,224,142,8,240,78,25,60,231,
+192,210,197,204,224,156,50,113,238,67,103,232,62,28,138,156,104,82,170,107,
+255,32,48,191,144,1,132,112,71,128,159,168,128,161,28,17,224,156,50,112,19,
+245,144,22,39,12,156,123,144,217,240,19,245,146,3,9,205,16,39,236,62,3,161,
+163,37,248,226,251,141,1,107,4,167,196,52,100,191,28,95,113,164,13,91,132,
+5,147,130,115,30,8,147,222,64,43,1,49,31,224,64,60,72,245,128,68,249,32,13,
+34,2,34,63,204,128,89,45,2,39,209,0,89,61,104,159,213,0,153,80,50,156,80,
+211,126,16,11,155,184,183,88,145,224,129,34,122,64,17,155,184,183,8,11,39,
+22,235,18,60,16,36,79,72,1,115,119,40,247,146,60,16,36,79,72,32,140,221,
+197,184,64,89,57,71,188,145,224,129,34,122,65,1,39,20,51,244,0,52,72,242,2,
+127,18,2,165,48,70,114,229,145,51,253,141,1,4,104,229,203,34,103,251,26,64,
+132,52,75,160,201,47,105,160,26,84,12,167,31,186,8,50,0,114,58,113,163,46,
+190,120,35,11,60,4,25,68,81,61,96,47,181,80,46,132,128,255,223,255,255,255,
+255,255,254,39,172,67,118,170,5,208,144,0,0,0,0,0,0,0,0,115,16,31,254,0,0,
+0,0,0,0,8,245,238,146,38,138,147,105,13,42,26,137,226,3,255,128,0,0,0,0,0,
+1,30,180,134,4,209,82,109,33,165,67,81,60,64,255,240,0,0,0,0,0,0,15,210,62,
+72,91,155,0,242,192,0,0,0,0,0,0,135,88,11,237,72,5,38,210,27,50,24,145,128,
+134,127,255,255,255,255,255,254,67,172,67,118,164,2,147,105,13,153,12,72,
+192,195,63,255,255,255,255,255,255,16,240,70,68,226,27,51,199,138,120,35,
+34,112,171,112,38,121,7,16,137,112,168,106,38,77,193,1,40,151,16,217,144,
+196,142,224,144,21,18,227,65,198,238,9,67,81,46,72,5,39,16,217,144,196,142,
+224,152,228,148,227,64,0,0,0,0,0,0,0,0,131,175,223,16,194,111,8,97,119,224,
+3,205,220,42,46,65,238,200,13,155,184,75,189,205,35,102,128,47,116,64,92,
+221,199,196,130,68,144,230,239,72,65,152,12,21,224,140,137,92,128,62,210,
+98,177,252,3,107,173,88,3,146,211,141,33,255,224,0,0,0,0,0,3,19,175,188,0,
+100,221,193,130,100,228,167,20,52,215,129,3,38,238,77,12,39,37,56,161,166,
+188,10,194,94,6,18,155,184,183,8,11,39,6,9,147,146,156,80,211,94,7,18,155,
+184,183,8,11,39,38,134,19,146,156,80,211,94,8,12,53,224,130,195,222,8,77,
+133,210,24,91,224,3,152,147,228,208,194,95,0,44,196,159,11,69,175,152,32,
+35,100,33,135,24,147,237,38,34,246,139,95,48,64,70,200,68,8,49,39,198,57,
+179,61,144,138,22,98,79,180,152,153,215,54,103,178,17,129,204,73,240,96,
+153,44,132,112,163,18,125,164,196,62,130,100,178,18,1,140,73,240,96,197,
+144,146,18,98,79,180,152,135,208,98,200,74,8,49,39,195,186,145,149,144,150,
+22,98,79,180,152,143,215,82,50,178,19,2,140,73,241,136,109,38,73,89,9,161,
+166,36,251,73,137,157,67,105,50,74,200,78,10,49,39,201,16,78,104,229,100,
+39,134,152,147,237,38,41,116,130,115,71,43,33,64,60,196,159,24,133,173,18,
+32,156,209,202,200,81,18,49,39,218,76,76,234,22,180,72,130,115,71,43,33,72,
+68,196,159,38,134,19,46,105,56,226,150,68,157,160,1,228,73,242,104,97,46,
+16,31,34,79,140,66,214,137,16,78,104,229,108,169,137,72,147,237,38,38,117,
+11,90,36,65,57,163,149,178,168,21,34,79,146,32,156,209,202,218,250,161,178,
+36,251,73,138,93,32,156,209,202,218,250,193,82,36,248,196,54,147,36,173,
+191,174,27,34,79,180,152,153,212,54,147,36,173,191,176,17,34,79,135,117,35,
+43,115,236,133,200,147,237,38,35,245,212,140,173,207,180,15,34,79,131,4,
+201,108,173,133,72,147,237,38,33,244,19,37,178,184,17,34,79,140,115,102,
+123,107,238,133,200,147,237,38,38,117,205,153,237,175,188,23,34,79,133,162,
+215,204,16,17,182,254,248,116,137,62,210,98,47,104,181,243,4,4,109,191,192,
+131,152,147,230,8,8,217,12,16,60,137,62,96,128,141,178,193,160,206,1,201,
+176,113,146,0,0,0,0,0,0,0,0,49,185,252,65,137,207,227,37,215,207,227,12,86,
+127,24,152,188,254,49,88,33,46,65,120,72,4,153,37,63,33,13,127,148,4,26,0,
+57,62,6,228,163,228,74,86,215,62,55,28,110,179,226,113,70,223,62,47,24,38,
+191,30,2,125,32,40,20,87,114,41,225,42,5,240,145,139,163,145,41,68,250,128,
+80,41,174,228,85,200,129,166,39,9,24,186,57,18,148,79,172,5,2,170,238,69,
+220,137,10,72,145,162,39,9,24,186,57,18,148,79,176,5,2,186,238,69,124,150,
+27,48,95,132,140,93,28,137,74,39,218,2,129,101,119,34,158,79,15,39,9,24,
+186,57,18,148,79,184,5,2,218,238,69,29,164,80,78,198,46,142,68,165,16,64,
+28,24,61,73,25,33,205,128,129,167,166,0,0,0,0,1,108,242,151,15,39,8,34,26,
+87,97,200,3,0,167,129,32,8,194,195,16,6,84,55,10,60,3,35,69,132,30,1,140,
+130,193,143,1,196,230,60,2,158,8,131,153,64,115,42,46,191,176,8,194,246,0,
+80,5,220,193,95,6,234,5,100,225,35,23,71,35,6,228,140,93,29,180,55,108,145,
+139,163,182,112,52,107,67,76,56,3,153,132,20,28,76,156,89,26,105,158,62,0,
+0,42,193,2,201,104,17,41,34,156,204,176,160,226,100,226,200,211,76,241,240,
+0,1,86,2,131,137,147,142,41,100,73,199,192,0,5,96,6,13,10,82,70,62,0,0,42,
+130,88,115,18,124,67,103,177,69,49,129,6,36,249,68,54,123,20,82,216,65,137,
+62,33,179,209,214,162,152,208,147,18,124,162,27,61,29,106,41,112,32,196,
+159,16,217,233,233,81,76,112,73,137,62,81,13,158,158,149,20,186,20,98,79,
+133,91,129,61,61,42,41,120,40,196,159,10,183,2,122,218,148,82,248,60,137,
+62,33,179,216,166,216,192,137,18,124,162,27,61,138,109,108,34,68,159,16,
+217,232,235,83,108,104,76,137,62,81,13,158,142,181,54,184,17,34,79,136,108,
+244,244,169,182,56,38,68,159,40,134,207,79,74,155,93,10,145,39,194,173,192,
+158,158,149,54,188,21,34,79,133,91,129,61,109,74,109,125,155,51,136,71,161,
+196,201,45,167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,155,51,168,71,
+161,196,201,45,167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,155,51,200,
+71,161,196,201,45,167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,155,51,
+232,71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,0,0,0,0,0,0,1,155,52,
+8,71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,0,0,0,0,0,0,1,155,52,40,
+71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,128,0,0,0,0,0,1,155,52,72,
+71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,128,0,0,0,0,0,1,155,52,
+104,71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,128,0,0,0,0,0,1,155,
+52,136,71,161,196,201,45,167,146,59,68,89,24,70,206,2,1,0,0,0,0,0,0,1,135,
+52,166,32,76,72,1,246,136,235,103,177,69,0,136,144,3,226,27,61,138,41,44,
+50,36,0,251,68,117,179,209,214,234,201,69,16,50,36,0,251,68,117,179,209,
+214,232,73,69,34,5,196,128,31,16,217,232,235,117,100,162,147,2,226,64,15,
+136,108,244,117,186,18,81,74,129,145,32,7,218,35,173,158,158,151,86,74,40,
+161,145,32,7,218,35,173,158,158,151,66,74,41,20,46,36,0,248,134,207,79,75,
+171,37,20,154,23,18,0,124,67,103,167,165,208,146,138,85,11,137,0,62,21,110,
+4,250,178,81,70,11,137,0,62,21,110,4,250,18,81,72,193,145,32,7,193,186,129,
+89,58,178,81,71,12,137,0,62,13,212,10,201,208,146,138,71,10,137,0,62,209,
+29,108,250,178,81,104,1,81,32,7,218,35,173,159,66,74,45,32,38,36,0,248,134,
+207,171,37,22,160,19,18,0,124,67,103,208,146,139,88,10,180,81,50,118,136,
+235,103,177,77,128,155,69,19,39,16,217,236,83,105,97,182,138,38,78,209,29,
+108,244,117,186,178,83,100,13,180,81,50,118,136,235,103,163,173,208,146,
+155,68,12,180,81,50,113,13,158,142,183,86,74,109,48,50,209,68,201,196,54,
+122,58,221,9,41,181,64,219,69,19,39,104,142,182,122,122,93,89,41,178,134,
+218,40,153,59,68,117,179,211,210,232,73,77,162,134,90,40,153,56,134,207,79,
+75,171,37,54,154,25,104,162,100,226,27,61,61,46,132,148,218,168,101,162,
+137,147,133,91,129,62,172,148,217,131,45,20,76,156,42,220,9,244,36,166,209,
+131,109,20,76,156,27,168,21,147,171,37,54,112,219,69,19,39,6,234,5,100,232,
+73,77,163,133,218,40,153,59,68,117,179,234,201,78,32,5,218,40,153,59,68,
+117,179,232,73,78,36,5,90,40,153,56,134,207,171,37,56,160,21,104,162,100,
+226,27,62,132,148,226,195,95,182,97,176,218,128,8,84,45,123,38,1,137,10,1,
+114,160,64,56,156,199,130,36,160,72,8,39,63,27,24,1,100,180,8,148,146,0,45,
+162,137,147,111,2,8,4,16,7,8,96,120,72,8,0,183,225,81,98,138,237,33,58,182,
+232,232,64,64,2,107,177,187,181,85,22,7,213,183,74,1,255,49,114,23,247,209,
+207,120,94,173,198,210,36,3,255,113,84,118,82,184,47,224,221,91,141,163,
+160,72,7,251,121,111,98,164,220,161,192,186,244,64,64,9,33,251,84,68,45,24,
+15,217,66,51,209,218,210,128,127,205,65,60,204,254,119,154,23,178,132,103,
+165,0,255,218,130,121,153,252,239,54,168,48,6,90,130,1,0,39,75,80,72,8,9,
+33,186,130,80,64,76,13,212,19,2,130,96,110,150,173,0,65,6,51,212,20,128,65,
+17,11,212,19,130,137,121,211,210,209,144,6,39,75,80,80,0,201,119,234,10,8,
+41,86,231,71,80,80,129,79,135,186,122,69,224,34,25,69,233,80,3,91,141,168,
+40,96,139,113,180,181,5,36,21,110,54,142,134,160,165,1,176,23,211,47,0,216,
+134,233,215,128,111,117,181,104,128,209,3,70,230,106,64,5,139,168,209,234,
+10,32,36,144,102,234,136,3,146,27,168,40,160,146,132,103,168,40,192,115,3,
+117,5,28,22,113,163,69,168,41,103,1,66,188,17,145,52,40,4,202,113,67,76,
+130,227,68,194,13,240,108,0,0,83,96,0,2,161,0,104,146,84,97,48,0,1,78,192,
+56,169,24,145,179,192,0,5,48,8,56,16,32,128,56,18,52,125,166,86,147,182,
+140,28,50,21,13,39,31,23,60,145,158,56,140,141,47,113,6,155,186,188,24,49,
+39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,197,68,14,49,39,
+199,197,211,116,240,242,113,197,230,18,180,253,228,3,17,46,18,243,35,100,
+128,172,156,114,70,163,146,76,34,248,146,164,108,248,75,204,141,146,28,217,
+114,137,27,78,251,241,173,234,162,160,225,1,3,34,92,170,9,105,164,32,225,
+64,131,155,1,193,133,7,19,39,22,70,154,103,143,128,0,10,176,20,28,76,156,
+113,75,34,78,62,0,0,43,0,48,104,82,146,49,240,0,1,84,11,180,192,0,5,114,1,
+18,160,65,24,131,20,145,25,172,48,132,122,28,76,146,218,121,35,180,69,145,
+132,108,224,31,248,0,0,0,0,0,0,25,172,56,132,122,28,76,146,218,121,35,180,
+69,145,132,108,224,31,248,0,0,0,0,0,0,40,160,45,110,23,30,176,33,184,0,0,
+175,32,29,235,2,27,199,23,0,0,22,4,51,88,129,8,244,56,153,37,180,242,71,
+104,139,35,8,217,192,63,240,0,0,0,0,0,0,51,88,145,8,244,56,153,37,180,242,
+71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,51,88,161,8,244,56,153,37,180,242,
+71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,51,88,177,8,244,56,153,37,180,242,
+71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,88,193,8,244,56,153,37,180,
+242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,88,209,8,244,56,153,37,
+180,242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,88,225,8,244,56,153,
+37,180,242,71,104,139,35,8,217,192,64,32,0,0,0,0,0,0,32,227,194,0,97,57,
+162,4,245,232,5,34,92,35,68,225,161,166,218,16,16,137,112,52,41,73,29,153,
+1,65,196,201,197,145,166,153,245,200,3,137,204,120,34,74,8,200,58,112,28,
+211,32,130,52,78,26,26,110,248,0,0,164,4,12,70,137,195,39,252,73,240,117,
+32,57,168,97,4,104,156,52,52,221,255,160,20,160,152,23,223,250,32,148,25,
+174,137,58,23,51,191,244,84,12,50,9,195,39,240,81,238,2,3,107,173,214,3,
+192,
};
#elif defined(DUK_USE_DOUBLE_ME)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3972] = {
-144,148,105,223,160,68,52,228,62,12,104,200,165,132,52,167,194,138,105,242,
-252,57,28,211,57,18,64,52,238,62,44,138,111,171,241,164,19,87,125,30,33,
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[4116] = {
+144,148,105,224,32,68,52,228,62,12,104,200,165,132,52,167,194,138,105,243,
+124,57,28,211,57,18,64,52,238,126,44,138,111,171,241,164,19,87,129,30,33,
167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
-1,80,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
-33,8,66,34,33,154,112,0,1,73,247,35,79,91,237,198,174,192,47,31,23,95,17,
-13,51,19,35,93,68,216,209,128,0,10,192,174,79,15,32,248,8,196,24,8,107,192,
-0,5,98,118,27,94,0,0,43,19,227,94,0,0,43,20,46,215,128,0,10,197,28,198,188,
-0,0,86,41,100,53,224,0,2,177,79,85,175,0,0,21,138,154,45,120,0,0,172,85,
-217,107,192,0,5,98,182,243,86,193,106,52,127,66,249,50,94,124,35,68,225,
-146,49,13,31,170,23,201,146,243,224,200,39,12,145,136,67,134,11,49,0,0,3,
-225,252,0,0,0,3,51,0,0,3,193,252,0,0,0,3,47,18,1,172,19,120,71,10,25,196,
-136,113,162,156,136,199,42,57,204,144,115,132,240,149,2,248,72,197,209,58,
-2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,141,17,56,72,197,209,58,
-130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,132,140,93,19,176,35,180,
-138,9,216,197,209,59,82,79,31,40,242,1,248,58,42,96,121,14,232,94,62,46,
-190,15,38,31,145,33,86,65,76,242,150,143,69,48,242,179,79,45,56,243,51,207,
-53,64,243,116,79,57,72,243,180,207,61,80,243,245,79,65,88,244,34,249,50,94,
-124,35,68,225,146,39,163,23,201,146,243,224,200,39,12,145,61,40,183,146,37,
-116,88,6,136,158,244,241,174,230,202,80,135,130,50,39,16,217,231,208,20,
-240,70,68,225,86,224,79,60,64,84,75,141,7,27,157,32,66,37,194,161,168,153,
-51,132,9,25,4,225,147,180,138,50,196,18,25,4,225,147,180,138,5,215,49,238,
-105,27,60,185,2,72,209,56,100,237,34,140,193,4,136,209,56,100,237,34,129,
-117,204,123,154,70,207,50,64,98,72,64,121,51,68,8,163,73,33,1,228,208,16,0,
-65,112,152,56,196,159,31,23,77,211,195,201,199,23,150,73,169,234,34,24,49,
-39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,196,64,153,137,62,
-58,205,227,226,231,146,51,199,26,6,18,92,130,64,192,148,144,102,240,23,129,
-133,18,2,100,224,160,56,100,42,26,78,62,46,121,35,60,112,216,32,50,21,13,
-39,31,23,60,145,154,9,46,18,1,36,64,47,148,64,98,196,132,201,57,68,132,95,
-18,84,141,159,9,121,145,178,67,155,46,73,2,17,46,72,128,89,7,199,32,66,37,
-194,197,217,35,120,228,131,17,46,18,243,35,100,128,172,156,98,2,40,152,151,
-32,130,166,36,248,235,55,143,139,158,72,207,28,150,24,23,46,92,130,80,72,
-151,21,0,100,213,103,229,245,8,186,190,144,24,78,136,24,94,152,3,142,9,113,
-214,111,31,23,60,145,158,57,164,13,68,184,248,186,110,158,30,78,56,188,226,
-10,62,46,121,35,60,113,18,225,27,70,18,32,10,201,208,32,134,214,208,200,84,
-52,156,49,39,50,71,107,107,152,129,13,173,161,144,168,105,57,34,78,100,142,
-214,215,49,16,134,214,210,220,229,81,252,49,39,50,71,107,107,158,65,13,173,
-165,185,202,163,249,34,78,100,142,214,215,60,146,12,16,28,128,62,175,42,6,
-143,36,136,16,64,90,242,135,192,129,67,71,147,62,65,5,215,231,214,6,215,62,
-180,8,49,1,3,162,92,4,98,12,41,14,67,40,106,229,1,132,130,8,24,78,104,129,
-54,62,96,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,
-178,58,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,
-129,232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,
-201,126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,
-132,0,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,
-46,36,29,4,78,69,6,60,226,31,192,7,255,252,24,192,163,11,23,51,130,56,35,
-193,56,100,243,31,6,150,46,103,4,225,147,143,114,27,63,57,241,200,169,194,
-133,42,166,175,240,6,23,240,0,97,28,17,224,39,233,32,80,142,8,240,78,25,56,
-9,250,136,22,39,12,156,123,144,217,240,19,245,18,6,19,154,32,79,214,124,14,
-134,140,151,227,139,237,52,11,88,37,62,33,163,37,248,226,251,77,32,213,184,
-64,89,56,39,49,224,137,61,196,5,96,38,35,251,200,15,18,61,96,17,62,40,6,
-145,1,17,31,228,64,89,45,2,39,205,0,178,122,209,63,162,2,101,64,202,113,67,
-77,247,64,92,221,197,186,196,143,4,9,19,208,1,25,187,139,112,128,178,113,
-110,177,35,193,2,68,244,0,46,110,229,30,242,71,130,4,137,232,4,35,55,113,
-110,16,22,78,81,239,36,120,32,72,158,128,64,147,138,25,249,0,52,72,242,2,
-127,2,5,74,96,140,229,203,34,103,250,154,4,17,163,151,44,137,159,234,105,4,
-33,162,93,6,73,123,13,1,165,64,202,113,251,33,6,64,14,71,78,20,101,213,207,
-4,194,207,2,12,162,0,158,176,23,218,168,23,66,64,255,255,239,127,255,255,
-255,255,19,214,33,187,85,2,232,72,0,0,0,0,0,32,0,0,25,136,0,0,31,15,224,0,
-0,0,4,122,247,73,19,69,73,180,134,149,13,68,241,0,0,3,193,252,0,0,0,0,143,
-90,67,2,104,169,54,144,210,161,168,158,32,0,0,120,127,128,0,0,0,14,73,78,
-20,0,0,0,0,0,0,0,0,8,58,189,233,24,77,217,24,93,240,1,230,238,21,23,32,247,
-68,13,155,184,75,189,205,35,102,128,47,114,64,185,187,143,137,4,137,33,205,
-222,17,6,96,48,87,130,50,37,114,1,246,147,21,143,224,54,186,213,128,114,90,
-112,164,0,0,124,63,128,0,0,0,98,117,119,128,25,55,112,96,153,57,41,197,13,
-53,224,65,147,119,38,134,19,146,156,80,211,94,5,194,94,6,37,55,113,110,16,
-22,78,12,19,39,37,56,161,166,188,14,74,110,226,220,32,44,156,154,24,78,74,
-113,67,77,120,32,97,175,4,28,61,224,133,172,186,70,22,248,1,204,73,242,104,
-97,47,128,44,196,159,11,69,175,152,32,35,100,33,142,49,39,218,76,69,237,22,
-190,96,128,141,144,136,32,196,159,24,230,204,246,66,40,179,18,125,164,196,
-206,185,179,61,144,140,28,196,159,6,9,146,200,71,20,98,79,180,152,135,208,
-76,150,66,64,99,18,124,24,49,100,36,137,49,39,218,76,67,232,49,100,37,8,49,
-39,195,186,145,149,144,150,44,196,159,105,49,31,174,164,101,100,38,10,49,
-39,198,33,180,153,37,100,38,141,49,39,218,76,76,234,27,73,146,86,66,112,
-163,18,124,145,4,230,142,86,66,120,211,18,125,164,197,46,144,78,104,229,
-100,40,15,49,39,198,33,107,68,136,39,52,114,178,20,73,24,147,237,38,38,117,
-11,90,36,65,57,163,149,144,164,68,196,159,38,134,19,46,105,56,226,150,68,
-157,160,3,200,147,228,208,194,92,32,124,137,62,49,11,90,36,65,57,163,149,
-178,166,74,68,159,105,49,51,168,90,209,34,9,205,28,173,149,65,82,36,249,34,
-9,205,28,173,175,170,54,68,159,105,49,75,164,19,154,57,91,95,88,84,137,62,
-49,13,164,201,43,111,235,141,145,39,218,76,76,234,27,73,146,86,223,216,17,
-34,79,135,117,35,43,115,236,139,145,39,218,76,71,235,169,25,91,159,104,60,
-137,62,12,19,37,178,182,42,68,159,105,49,15,160,153,45,149,193,18,36,248,
-199,54,103,182,190,232,185,18,125,164,196,206,185,179,61,181,247,133,200,
-147,225,104,181,243,4,4,109,191,190,58,68,159,105,49,23,180,90,249,130,2,
-54,223,224,67,152,147,230,8,8,217,12,16,121,18,124,193,1,27,101,131,131,56,
-7,38,193,198,72,0,0,0,0,0,0,0,0,198,231,240,134,39,63,136,151,95,63,136,49,
-89,252,66,98,243,248,133,96,132,185,5,224,32,36,201,41,248,200,213,249,0,
-131,64,7,39,192,218,148,124,137,74,216,231,198,227,141,182,124,78,40,217,
-231,197,227,4,213,227,192,159,72,10,5,21,218,138,120,74,129,124,36,98,232,
-228,74,81,62,160,20,10,107,181,21,114,32,105,137,194,70,46,142,68,165,19,
-235,1,64,170,187,81,119,34,66,146,36,104,137,194,70,46,142,68,165,19,236,1,
-64,174,187,81,95,37,134,204,23,225,35,23,71,34,82,137,246,128,160,89,93,
-168,167,147,195,201,194,70,46,142,68,165,19,238,1,64,182,187,81,71,105,20,
-19,177,139,163,145,41,68,16,7,6,15,82,70,72,115,96,0,93,105,160,0,0,0,0,91,
-60,149,195,200,194,8,134,149,216,114,1,128,83,192,144,8,194,195,16,12,168,
-110,20,120,12,141,22,16,120,12,100,22,12,120,28,78,99,192,41,224,136,115,
-36,14,100,197,213,245,193,48,189,112,40,2,237,96,175,131,117,2,178,112,145,
-139,163,145,131,114,70,46,142,218,27,182,72,197,209,219,56,26,53,161,166,
-28,1,204,178,10,14,38,78,44,141,52,207,31,0,0,21,64,129,100,180,8,148,145,
-92,203,176,160,226,100,226,200,211,76,241,240,0,1,84,2,131,137,147,142,41,
-100,73,199,192,0,5,88,6,13,10,82,70,62,0,0,42,66,88,115,18,124,67,103,177,
-69,49,130,12,73,242,136,108,246,40,165,177,6,36,248,134,207,71,90,138,99,
-68,152,147,229,16,217,232,235,81,75,130,12,73,241,13,158,158,149,20,199,9,
-49,39,202,33,179,211,210,162,151,69,24,147,225,86,224,79,79,74,138,94,20,
-98,79,133,91,129,61,109,74,41,124,60,137,62,33,179,216,166,216,193,18,36,
-249,68,54,123,20,218,216,137,18,124,67,103,163,173,77,177,162,100,73,242,
-136,108,244,117,169,181,193,18,36,248,134,207,79,74,155,99,132,200,147,229,
-16,217,233,233,83,107,162,164,73,240,171,112,39,167,165,77,175,10,145,39,
-194,173,192,158,182,165,54,191,153,51,72,71,161,196,201,45,167,146,59,68,
-89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,104,71,161,196,201,45,167,146,59,
-68,89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,136,71,161,196,201,45,167,146,
-59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,153,51,168,71,161,196,201,45,167,
-146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,153,51,200,71,161,196,201,45,167,
-146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,153,51,232,71,161,196,201,45,167,
-146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,8,71,161,196,201,45,167,
-146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,40,71,161,196,201,45,167,
-146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,153,52,72,71,161,196,201,45,167,
-146,59,68,89,24,70,206,0,0,1,2,0,0,0,0,1,135,52,102,32,76,72,1,246,136,235,
-103,177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,
-171,37,20,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,
-158,142,183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,
-246,136,235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,
-37,20,138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,
-75,161,37,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,
-39,208,146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,
-129,89,58,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,
-17,214,207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,
-207,161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,
-207,98,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,
-78,209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,
-146,155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,
-104,142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,
-146,155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,
-217,233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,
-162,137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,
-77,156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,
-117,179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,
-162,100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,123,
-102,53,155,80,2,21,11,94,201,128,196,133,0,185,80,32,56,156,199,130,36,160,
-72,16,78,126,54,48,5,146,208,34,82,72,1,109,20,76,155,120,28,34,1,225,32,5,
-95,130,160,52,171,138,69,132,234,219,163,161,2,197,172,9,0,89,86,214,236,
-31,86,221,40,8,69,220,199,253,231,63,95,193,122,183,27,72,144,17,197,125,
-207,255,160,138,217,67,117,110,54,142,129,32,61,229,237,159,135,114,147,10,
-130,235,209,3,236,132,37,0,96,181,17,80,63,101,8,207,71,107,74,4,245,7,49,
-254,105,219,251,48,94,202,17,158,148,9,234,15,99,252,211,183,246,98,159,
-129,228,176,192,185,127,46,155,185,41,197,13,55,38,3,127,255,20,138,160,
-192,25,106,8,8,1,58,90,130,64,128,146,27,168,37,8,9,129,186,130,96,160,152,
-27,165,171,64,32,131,25,234,10,64,65,17,11,212,19,133,18,243,167,165,163,
-32,24,157,45,65,64,6,75,191,80,80,66,149,110,116,117,5,8,41,240,247,79,72,
-188,8,134,81,122,84,1,173,198,212,20,48,139,113,180,181,5,36,42,220,109,29,
-13,65,74,6,192,95,76,188,6,196,55,78,188,6,247,91,86,136,26,32,104,220,205,
-72,1,98,234,52,122,130,136,18,72,51,117,68,3,146,27,168,40,161,37,8,207,80,
-81,129,204,13,212,20,112,179,141,26,45,65,75,112,20,43,193,25,19,66,128,
-153,78,40,105,144,92,104,152,131,124,27,253,128,0,10,116,3,68,146,163,9,
-128,0,10,102,3,138,145,137,27,60,0,0,82,129,7,2,4,16,7,2,70,143,178,203,
-164,237,35,14,25,10,134,147,143,139,158,72,207,28,54,77,47,109,13,55,113,
-120,96,196,159,29,102,241,241,115,201,25,227,131,36,133,20,62,110,143,17,
-16,113,137,62,62,46,155,167,135,147,142,47,44,151,79,221,64,98,37,194,94,
-100,108,144,21,147,140,73,168,228,19,17,124,73,82,54,124,37,230,70,201,14,
-108,185,36,155,14,243,243,83,212,69,131,132,4,12,137,114,168,37,166,145,7,
-10,4,28,200,14,12,40,56,153,56,178,52,211,60,124,0,0,85,0,160,226,100,227,
-138,89,18,113,240,0,1,86,1,131,66,148,145,143,128,0,10,144,93,134,0,0,43,
-80,17,42,4,17,136,49,73,19,49,134,16,143,67,137,146,91,79,36,118,136,178,
-48,141,156,0,0,15,3,240,0,0,0,3,49,135,16,143,67,137,146,91,79,36,118,136,
-178,48,141,156,0,0,15,3,240,0,0,0,5,20,5,173,194,227,214,4,55,0,0,21,196,7,
-122,192,134,241,197,192,0,5,121,25,140,64,132,122,28,76,146,218,121,35,180,
-69,145,132,108,224,0,0,120,31,128,0,0,0,25,140,72,132,122,28,76,146,218,
-121,35,180,69,145,132,108,224,0,0,0,32,0,0,0,0,25,140,80,132,122,28,76,146,
-218,121,35,180,69,145,132,108,224,0,0,0,32,0,0,0,0,25,140,88,132,122,28,76,
-146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,140,96,132,122,
-28,76,146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,140,104,
-132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,8,32,0,0,0,0,25,
-140,112,132,122,28,76,146,218,121,35,180,69,145,132,108,224,0,0,16,32,0,0,
-0,0,16,113,225,0,48,156,209,2,122,244,5,34,92,35,68,225,161,166,218,16,33,
-18,224,104,82,146,59,50,5,7,19,39,22,70,154,103,215,32,28,78,99,193,18,80,
-70,131,165,1,205,34,8,35,68,225,161,166,239,255,4,12,70,137,195,39,248,73,
-7,78,3,154,102,16,70,137,195,67,77,223,248,1,74,9,129,125,255,130,9,65,154,
-232,147,161,115,59,255,5,64,195,32,156,50,126,197,14,2,3,107,173,213,0,
+1,82,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
+33,8,66,26,179,233,97,167,60,150,34,33,154,112,0,1,75,247,35,79,95,237,198,
+174,200,47,31,23,95,17,13,51,19,35,93,68,216,209,128,0,10,208,174,79,15,32,
+248,8,196,24,8,107,192,0,5,106,118,27,94,0,0,43,83,227,94,0,0,43,84,46,215,
+128,0,10,213,28,198,188,0,0,86,169,100,53,224,0,2,181,79,85,175,0,0,21,170,
+154,45,120,0,0,173,85,217,107,192,0,5,106,182,243,86,193,106,52,127,130,
+249,50,94,124,35,68,225,146,49,13,31,186,23,201,146,243,224,200,39,12,145,
+136,67,134,19,49,0,0,3,225,252,0,0,0,3,51,0,0,3,193,252,0,0,0,3,47,18,1,
+172,19,120,71,10,25,196,136,113,162,156,136,199,42,57,204,144,115,132,240,
+149,2,248,72,197,209,58,2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,
+141,17,56,72,197,209,58,130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,
+132,140,93,19,176,35,180,138,9,216,197,209,59,82,79,35,40,242,65,248,58,42,
+96,121,14,232,94,62,46,190,15,42,31,145,33,86,65,76,242,214,143,73,48,242,
+243,79,49,56,243,115,207,57,64,243,180,79,61,72,243,244,207,65,80,244,53,
+79,69,88,244,98,30,8,200,156,67,102,120,241,79,4,100,78,21,110,4,207,32,47,
+147,37,231,194,52,78,25,34,122,81,124,153,47,62,12,130,112,201,19,211,139,
+121,34,87,69,128,104,137,239,83,18,238,108,165,2,162,92,104,56,220,233,1,8,
+151,10,134,162,100,206,16,18,50,9,195,39,105,20,101,136,18,25,4,225,147,
+180,138,5,215,49,238,105,27,60,185,1,36,104,156,50,118,145,70,96,129,34,52,
+78,25,59,72,160,93,115,30,230,145,179,204,144,12,73,8,15,38,104,128,138,52,
+146,16,30,77,1,0,2,11,132,193,198,36,248,248,186,110,158,30,78,56,188,194,
+70,183,170,136,48,98,79,142,179,120,248,185,228,140,241,193,146,66,138,31,
+55,71,138,128,153,137,62,58,205,227,226,231,146,51,199,26,6,18,92,146,64,
+96,74,72,51,120,43,192,97,68,128,153,56,72,7,12,133,67,73,199,197,207,36,
+103,142,35,2,3,33,80,210,113,241,115,201,25,160,146,225,160,9,34,1,124,178,
+1,139,18,19,36,229,146,8,190,36,169,27,62,18,243,35,100,135,54,92,162,2,17,
+46,72,128,89,7,200,32,33,18,225,98,236,145,188,130,64,196,75,132,188,200,
+217,32,43,39,28,128,69,19,18,228,144,42,98,79,142,179,120,248,185,228,140,
+241,201,97,129,114,229,201,37,2,68,184,200,1,147,93,159,153,213,34,235,250,
+96,48,157,32,24,94,160,1,199,4,184,235,55,143,139,158,72,207,28,226,3,81,
+46,62,46,155,167,135,147,142,47,60,129,71,197,207,36,103,142,34,92,35,104,
+194,68,1,89,58,36,8,109,109,12,133,67,73,195,18,115,36,118,182,185,168,8,
+109,109,12,133,67,73,201,18,115,36,118,182,185,168,130,27,91,75,115,149,71,
+240,196,156,201,29,173,174,129,2,27,91,75,115,149,71,242,68,156,201,29,173,
+174,129,34,12,16,28,128,62,191,42,3,71,146,68,4,16,22,188,161,240,16,40,
+104,242,103,196,16,93,158,125,96,110,115,235,64,131,16,16,58,37,192,70,32,
+194,144,114,25,67,95,40,6,18,8,32,48,156,209,2,108,124,96,224,144,6,247,62,
+16,0,143,164,143,12,248,15,18,84,145,145,34,128,11,35,160,179,140,0,44,150,
+129,18,58,0,146,116,103,32,128,105,61,104,17,36,175,1,232,217,29,5,156,179,
+224,58,26,50,95,142,43,159,64,181,130,83,226,26,50,95,142,43,159,192,7,255,
+248,41,42,72,226,1,160,18,78,97,32,26,64,114,186,60,32,4,120,6,148,13,128,
+124,3,76,12,84,46,100,140,3,78,13,18,14,130,36,67,232,23,18,14,130,39,34,
+131,30,113,15,224,3,255,253,6,48,40,194,197,204,224,142,8,240,78,25,60,231,
+192,210,197,204,224,156,50,113,238,67,103,232,62,28,138,156,104,82,170,107,
+255,32,48,191,144,1,132,112,71,128,159,168,128,161,28,17,224,156,50,112,19,
+245,144,22,39,12,156,123,144,217,240,19,245,146,3,9,205,16,39,236,62,3,161,
+163,37,248,226,251,141,1,107,4,167,196,52,100,191,28,95,113,164,13,91,132,
+5,147,130,115,30,8,147,222,64,43,1,49,31,224,64,60,72,245,128,68,249,32,13,
+34,2,34,63,204,128,89,45,2,39,209,0,89,61,104,159,213,0,153,80,50,156,80,
+211,126,16,11,155,184,183,88,145,224,129,34,122,64,17,155,184,183,8,11,39,
+22,235,18,60,16,36,79,72,1,115,119,40,247,146,60,16,36,79,72,32,140,221,
+197,184,64,89,57,71,188,145,224,129,34,122,65,1,39,20,51,244,0,52,72,242,2,
+127,18,2,165,48,70,114,229,145,51,253,141,1,4,104,229,203,34,103,251,26,64,
+132,52,75,160,201,47,105,160,26,84,12,167,31,186,8,50,0,114,58,113,163,46,
+190,120,35,11,60,4,25,68,81,61,96,47,181,80,46,132,129,255,255,222,255,255,
+255,255,254,39,172,67,118,170,5,208,144,0,0,0,0,0,64,0,0,51,16,0,0,62,31,
+192,0,0,0,8,245,238,146,38,138,147,105,13,42,26,137,226,0,0,7,131,248,0,0,
+0,1,30,180,134,4,209,82,109,33,165,67,81,60,64,0,0,240,255,0,0,0,0,15,210,
+62,72,91,155,0,0,2,192,240,0,0,0,0,135,88,11,237,72,5,38,210,27,50,24,145,
+129,255,254,126,135,255,255,255,254,67,172,67,118,164,2,147,105,13,153,12,
+72,192,255,255,63,195,255,255,255,255,16,240,70,68,226,27,51,199,138,120,
+35,34,112,171,112,38,121,7,16,137,112,168,106,38,77,193,1,40,151,16,217,
+144,196,142,224,144,21,18,227,65,198,238,9,67,81,46,72,5,39,16,217,144,196,
+142,224,152,228,148,227,64,0,0,0,0,0,0,0,0,131,175,223,16,194,111,8,97,119,
+224,3,205,220,42,46,65,238,200,13,155,184,75,189,205,35,102,128,47,116,64,
+92,221,199,196,130,68,144,230,239,72,65,152,12,21,224,140,137,92,128,62,
+210,98,177,252,3,107,173,88,3,146,211,141,32,0,3,225,252,0,0,0,3,19,175,
+188,0,100,221,193,130,100,228,167,20,52,215,129,3,38,238,77,12,39,37,56,
+161,166,188,10,194,94,6,18,155,184,183,8,11,39,6,9,147,146,156,80,211,94,7,
+18,155,184,183,8,11,39,38,134,19,146,156,80,211,94,8,12,53,224,130,195,222,
+8,77,133,210,24,91,224,3,152,147,228,208,194,95,0,44,196,159,11,69,175,152,
+32,35,100,33,135,24,147,237,38,34,246,139,95,48,64,70,200,68,8,49,39,198,
+57,179,61,144,138,22,98,79,180,152,153,215,54,103,178,17,129,204,73,240,96,
+153,44,132,112,163,18,125,164,196,62,130,100,178,18,1,140,73,240,96,197,
+144,146,18,98,79,180,152,135,208,98,200,74,8,49,39,195,186,145,149,144,150,
+22,98,79,180,152,143,215,82,50,178,19,2,140,73,241,136,109,38,73,89,9,161,
+166,36,251,73,137,157,67,105,50,74,200,78,10,49,39,201,16,78,104,229,100,
+39,134,152,147,237,38,41,116,130,115,71,43,33,64,60,196,159,24,133,173,18,
+32,156,209,202,200,81,18,49,39,218,76,76,234,22,180,72,130,115,71,43,33,72,
+68,196,159,38,134,19,46,105,56,226,150,68,157,160,1,228,73,242,104,97,46,
+16,31,34,79,140,66,214,137,16,78,104,229,108,169,137,72,147,237,38,38,117,
+11,90,36,65,57,163,149,178,168,21,34,79,146,32,156,209,202,218,250,161,178,
+36,251,73,138,93,32,156,209,202,218,250,193,82,36,248,196,54,147,36,173,
+191,174,27,34,79,180,152,153,212,54,147,36,173,191,176,17,34,79,135,117,35,
+43,115,236,133,200,147,237,38,35,245,212,140,173,207,180,15,34,79,131,4,
+201,108,173,133,72,147,237,38,33,244,19,37,178,184,17,34,79,140,115,102,
+123,107,238,133,200,147,237,38,38,117,205,153,237,175,188,23,34,79,133,162,
+215,204,16,17,182,254,248,116,137,62,210,98,47,104,181,243,4,4,109,191,192,
+131,152,147,230,8,8,217,12,16,60,137,62,96,128,141,178,193,160,206,1,201,
+176,113,146,0,0,0,0,0,0,0,0,49,185,252,65,137,207,227,37,215,207,227,12,86,
+127,24,152,188,254,49,88,33,46,65,120,72,4,153,37,63,33,13,127,148,4,26,0,
+57,62,6,228,163,228,74,86,215,62,55,28,110,179,226,113,70,223,62,47,24,38,
+191,30,2,125,32,40,20,87,114,41,225,42,5,240,145,139,163,145,41,68,250,128,
+80,41,174,228,85,200,129,166,39,9,24,186,57,18,148,79,172,5,2,170,238,69,
+220,137,10,72,145,162,39,9,24,186,57,18,148,79,176,5,2,186,238,69,124,150,
+27,48,95,132,140,93,28,137,74,39,218,2,129,101,119,34,158,79,15,39,9,24,
+186,57,18,148,79,184,5,2,218,238,69,29,164,80,78,198,46,142,68,165,16,64,
+28,24,61,73,25,33,205,128,1,167,166,128,0,0,0,1,108,242,151,15,39,8,34,26,
+87,97,200,3,0,167,129,32,8,194,195,16,6,84,55,10,60,3,35,69,132,30,1,140,
+130,193,143,1,196,230,60,2,158,8,131,153,64,115,42,46,191,176,8,194,246,0,
+80,5,220,193,95,6,234,5,100,225,35,23,71,35,6,228,140,93,29,180,55,108,145,
+139,163,182,112,52,107,67,76,56,3,153,132,20,28,76,156,89,26,105,158,62,0,
+0,42,193,2,201,104,17,41,34,156,204,176,160,226,100,226,200,211,76,241,240,
+0,1,86,2,131,137,147,142,41,100,73,199,192,0,5,96,6,13,10,82,70,62,0,0,42,
+130,88,115,18,124,67,103,177,69,49,129,6,36,249,68,54,123,20,82,216,65,137,
+62,33,179,209,214,162,152,208,147,18,124,162,27,61,29,106,41,112,32,196,
+159,16,217,233,233,81,76,112,73,137,62,81,13,158,158,149,20,186,20,98,79,
+133,91,129,61,61,42,41,120,40,196,159,10,183,2,122,218,148,82,248,60,137,
+62,33,179,216,166,216,192,137,18,124,162,27,61,138,109,108,34,68,159,16,
+217,232,235,83,108,104,76,137,62,81,13,158,142,181,54,184,17,34,79,136,108,
+244,244,169,182,56,38,68,159,40,134,207,79,74,155,93,10,145,39,194,173,192,
+158,158,149,54,188,21,34,79,133,91,129,61,109,74,109,125,155,51,136,71,161,
+196,201,45,167,146,59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,155,51,168,71,
+161,196,201,45,167,146,59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,155,51,200,
+71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,155,51,
+232,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,155,52,
+8,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,155,52,40,
+71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,155,52,72,
+71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,155,52,
+104,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,155,
+52,136,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,1,2,0,0,0,0,1,135,
+52,166,32,76,72,1,246,136,235,103,177,69,0,136,144,3,226,27,61,138,41,44,
+50,36,0,251,68,117,179,209,214,234,201,69,16,50,36,0,251,68,117,179,209,
+214,232,73,69,34,5,196,128,31,16,217,232,235,117,100,162,147,2,226,64,15,
+136,108,244,117,186,18,81,74,129,145,32,7,218,35,173,158,158,151,86,74,40,
+161,145,32,7,218,35,173,158,158,151,66,74,41,20,46,36,0,248,134,207,79,75,
+171,37,20,154,23,18,0,124,67,103,167,165,208,146,138,85,11,137,0,62,21,110,
+4,250,178,81,70,11,137,0,62,21,110,4,250,18,81,72,193,145,32,7,193,186,129,
+89,58,178,81,71,12,137,0,62,13,212,10,201,208,146,138,71,10,137,0,62,209,
+29,108,250,178,81,104,1,81,32,7,218,35,173,159,66,74,45,32,38,36,0,248,134,
+207,171,37,22,160,19,18,0,124,67,103,208,146,139,88,10,180,81,50,118,136,
+235,103,177,77,128,155,69,19,39,16,217,236,83,105,97,182,138,38,78,209,29,
+108,244,117,186,178,83,100,13,180,81,50,118,136,235,103,163,173,208,146,
+155,68,12,180,81,50,113,13,158,142,183,86,74,109,48,50,209,68,201,196,54,
+122,58,221,9,41,181,64,219,69,19,39,104,142,182,122,122,93,89,41,178,134,
+218,40,153,59,68,117,179,211,210,232,73,77,162,134,90,40,153,56,134,207,79,
+75,171,37,54,154,25,104,162,100,226,27,61,61,46,132,148,218,168,101,162,
+137,147,133,91,129,62,172,148,217,131,45,20,76,156,42,220,9,244,36,166,209,
+131,109,20,76,156,27,168,21,147,171,37,54,112,219,69,19,39,6,234,5,100,232,
+73,77,163,133,218,40,153,59,68,117,179,234,201,78,32,5,218,40,153,59,68,
+117,179,232,73,78,36,5,90,40,153,56,134,207,171,37,56,160,21,104,162,100,
+226,27,62,132,148,226,195,95,182,97,176,218,128,8,84,45,123,38,1,137,10,1,
+114,160,64,56,156,199,130,36,160,72,8,39,63,27,24,1,100,180,8,148,146,0,45,
+162,137,147,111,2,8,4,16,7,8,96,120,72,1,87,224,168,13,42,226,145,97,58,
+182,232,232,64,177,107,2,64,22,85,181,187,7,213,183,74,2,17,119,49,255,121,
+207,215,240,94,173,198,210,36,4,113,95,115,255,232,34,182,80,221,91,141,
+163,160,72,15,121,123,103,225,220,164,194,160,186,244,64,251,33,9,64,24,45,
+68,84,15,217,66,51,209,218,210,129,61,65,204,127,154,118,254,204,23,178,
+132,103,165,2,122,131,216,255,52,237,253,154,168,48,6,90,130,1,0,39,75,80,
+72,8,9,33,186,130,80,64,76,13,212,19,2,130,96,110,150,173,0,65,6,51,212,20,
+128,65,17,11,212,19,130,137,121,211,210,209,144,6,39,75,80,80,0,201,119,
+234,10,8,41,86,231,71,80,80,129,79,135,186,122,69,224,34,25,69,233,80,3,91,
+141,168,40,96,139,113,180,181,5,36,21,110,54,142,134,160,165,1,176,23,211,
+47,0,216,134,233,215,128,111,117,181,104,128,209,3,70,230,106,64,5,139,168,
+209,234,10,32,36,144,102,234,136,3,146,27,168,40,160,146,132,103,168,40,
+192,115,3,117,5,28,22,113,163,69,168,41,103,1,66,188,17,145,52,40,4,202,
+113,67,76,130,227,68,194,13,240,108,0,0,83,96,0,2,161,0,104,146,84,97,48,0,
+1,78,192,56,169,24,145,179,192,0,5,48,8,56,16,32,128,56,18,52,125,166,86,
+147,182,140,28,50,21,13,39,31,23,60,145,158,56,140,141,47,113,6,155,186,
+188,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,197,68,
+14,49,39,199,197,211,116,240,242,113,197,230,18,180,253,228,3,17,46,18,243,
+35,100,128,172,156,114,70,163,146,76,34,248,146,164,108,248,75,204,141,146,
+28,217,114,137,27,78,251,241,173,234,162,160,225,1,3,34,92,170,9,105,164,
+32,225,64,131,155,1,193,133,7,19,39,22,70,154,103,143,128,0,10,176,20,28,
+76,156,113,75,34,78,62,0,0,43,0,48,104,82,146,49,240,0,1,84,11,180,192,0,5,
+114,1,18,160,65,24,131,20,145,25,172,48,132,122,28,76,146,218,121,35,180,
+69,145,132,108,224,0,0,120,31,128,0,0,0,25,172,56,132,122,28,76,146,218,
+121,35,180,69,145,132,108,224,0,0,120,31,128,0,0,0,40,160,45,110,23,30,176,
+33,184,0,0,175,32,29,235,2,27,199,23,0,0,22,4,51,88,129,8,244,56,153,37,
+180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0,0,51,88,145,8,244,56,153,
+37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,0,0,51,88,161,8,244,56,153,
+37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,0,0,51,88,177,8,244,56,153,
+37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,88,193,8,244,56,
+153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,88,209,8,244,
+56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,88,225,8,
+244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,32,64,0,0,0,0,32,227,194,
+0,97,57,162,4,245,232,5,34,92,35,68,225,161,166,218,16,16,137,112,52,41,73,
+29,153,1,65,196,201,197,145,166,153,245,200,3,137,204,120,34,74,8,200,58,
+112,28,211,32,130,52,78,26,26,110,248,0,0,164,4,12,70,137,195,39,252,73,
+240,117,32,57,168,97,4,104,156,52,52,221,255,160,20,160,152,23,223,250,32,
+148,25,174,137,58,23,51,191,244,84,12,50,9,195,39,240,81,238,2,3,107,173,
+214,3,192,
};
#else
#error invalid endianness defines
@@ -11482,10 +11717,18 @@ DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *ms
DUK_UNREF(udata);
DUK_UNREF(msg);
+ msg = msg ? msg : "NULL";
+
#if defined(DUK_USE_FATAL_HANDLER)
/* duk_config.h provided a custom default fatal handler. */
- DUK_D(DUK_DPRINT("custom default fatal error handler called: %s", msg ? msg : "NULL"));
+ DUK_D(DUK_DPRINT("custom default fatal error handler called: %s", msg));
DUK_USE_FATAL_HANDLER(udata, msg);
+#elif defined(DUK_USE_CPP_EXCEPTIONS)
+ /* With C++ use a duk_fatal_exception which user code can catch in
+ * a natural way.
+ */
+ DUK_D(DUK_DPRINT("built-in default C++ fatal error handler called: %s", msg));
+ throw duk_fatal_exception(msg);
#else
/* Default behavior is to abort() on error. There's no printout
* which makes this awkward, so it's always recommended to use an
@@ -11502,7 +11745,7 @@ DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *ms
* - http://duktape.org/api.html#taglist-protected
* ====================================================================
*/
- DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s", msg ? msg : "NULL"));
+ DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s", msg));
DUK_ABORT();
#endif
@@ -11657,7 +11900,7 @@ DUK_INTERNAL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_u
/*
* Unicode codepoints above U+FFFF are encoded as surrogate
* pairs here. This ensures that all CESU-8 codepoints are
- * 16-bit values as expected in Ecmascript. The surrogate
+ * 16-bit values as expected in ECMAScript. The surrogate
* pairs always get a 3-byte encoding (each) in CESU-8.
* See: http://en.wikipedia.org/wiki/Surrogate_pair
*
@@ -11796,8 +12039,7 @@ DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr,
return cp;
}
DUK_ERROR_INTERNAL(thr);
- DUK_UNREACHABLE();
- return 0;
+ DUK_WO_NORETURN(return 0;);
}
/* Compute (extended) utf-8 length without codepoint encoding validation,
@@ -11946,7 +12188,7 @@ DUK_LOCAL duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_si
duk_bitdecoder_ctx bd_ctx;
duk_codepoint_t prev_re;
- DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
+ duk_memzero(&bd_ctx, sizeof(bd_ctx));
bd_ctx.data = (const duk_uint8_t *) unitab;
bd_ctx.length = (duk_size_t) unilen;
@@ -12498,7 +12740,7 @@ duk_codepoint_t duk__case_transform_helper(duk_hthread *thr,
}
/* 1:1 or special conversions, but not locale/context specific: script generated rules */
- DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
+ duk_memzero(&bd_ctx, sizeof(bd_ctx));
if (uppercase) {
bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_uc;
bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc);
@@ -12697,7 +12939,7 @@ DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = {
#endif /* DUK_USE_REGEXP_SUPPORT */
/*
- * Misc util stuff
+ * Misc util stuff.
*/
/* #include duk_internal.h -> already included */
@@ -12860,45 +13102,6 @@ DUK_INTERNAL const duk_uint16_t duk_hex_enctab[256] = {
#endif /* DUK_USE_HEX_FASTPATH */
/*
- * Table for base-64 encoding
- */
-
-#if defined(DUK_USE_BASE64_FASTPATH)
-DUK_INTERNAL const duk_uint8_t duk_base64_enctab[64] = {
- 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* A...P */
- 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, /* Q...f */
- 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, /* g...v */
- 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f /* w.../ */
-};
-#endif /* DUK_USE_BASE64_FASTPATH */
-
-/*
- * Table for base-64 decoding
- */
-
-#if defined(DUK_USE_BASE64_FASTPATH)
-DUK_INTERNAL const duk_int8_t duk_base64_dectab[256] = {
- /* -1 = error, -2 = allowed whitespace, -3 = padding ('='), 0...63 decoded bytes */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, /* 0x00...0x0f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10...0x1f */
- -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20...0x2f */
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1, /* 0x30...0x3f */
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50...0x5f */
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70...0x7f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80...0x8f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90...0x9f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0...0xaf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0...0xbf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0...0xcf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0...0xdf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0...0xef */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0...0xff */
-};
-#endif /* DUK_USE_BASE64_FASTPATH */
-
-/*
* Arbitrary byteswap for potentially unaligned values
*
* Used to byteswap pointers e.g. in debugger code.
@@ -12918,191 +13121,8 @@ DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) {
}
}
#endif
-
-/*
- * Miscellaneous coercion / clamping helpers.
- */
-
-/* Check whether a duk_double_t is a whole number in the 32-bit range (reject
- * negative zero), and if so, return a duk_int32_t.
- * For compiler use: don't allow negative zero as it will cause trouble with
- * LDINT+LDINTX, positive zero is OK.
- */
-DUK_INTERNAL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival) {
- duk_int32_t t;
-
- t = (duk_int32_t) x;
- if (!((duk_double_t) t == x)) {
- return 0;
- }
- if (t == 0) {
- duk_double_union du;
- du.d = x;
- if (DUK_DBLUNION_HAS_SIGNBIT(&du)) {
- return 0;
- }
- }
- *ival = t;
- return 1;
-}
-
-/* Check whether a duk_double_t is a whole number in the 32-bit range, and if
- * so, return a duk_int32_t.
- */
-DUK_INTERNAL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival) {
- duk_int32_t t;
-
- t = (duk_int32_t) x;
- if (!((duk_double_t) t == x)) {
- return 0;
- }
- *ival = t;
- return 1;
-}
-
-/*
- * IEEE double checks
- */
-
-DUK_INTERNAL duk_bool_t duk_double_is_anyinf(duk_double_t x) {
- duk_double_union du;
- du.d = x;
- return DUK_DBLUNION_IS_ANYINF(&du);
-}
-
-DUK_INTERNAL duk_bool_t duk_double_is_posinf(duk_double_t x) {
- duk_double_union du;
- du.d = x;
- return DUK_DBLUNION_IS_POSINF(&du);
-}
-
-DUK_INTERNAL duk_bool_t duk_double_is_neginf(duk_double_t x) {
- duk_double_union du;
- du.d = x;
- return DUK_DBLUNION_IS_NEGINF(&du);
-}
-
-DUK_INTERNAL duk_bool_t duk_double_is_nan(duk_double_t x) {
- duk_double_union du;
- du.d = x;
- /* Assumes we're dealing with a Duktape internal NaN which is
- * NaN normalized if duk_tval requires it.
- */
- DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
- return DUK_DBLUNION_IS_NAN(&du);
-}
-
-DUK_INTERNAL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x) {
- duk_double_union du;
- du.d = x;
- /* Assumes we're dealing with a Duktape internal NaN which is
- * NaN normalized if duk_tval requires it.
- */
- DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
- return DUK_DBLUNION_IS_NAN(&du) || DUK_DBLUNION_IS_ANYZERO(&du);
-}
-
-DUK_INTERNAL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x) {
- duk_double_union du;
- du.d = x;
- /* If exponent is 0x7FF the argument is either a NaN or an
- * infinity. We don't need to check any other fields.
- */
-#if defined(DUK_USE_64BIT_OPS)
-#if defined(DUK_USE_DOUBLE_ME)
- return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000);
-#else
- return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000);
-#endif
-#else
- return (du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL;
-#endif
-}
-
-DUK_INTERNAL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x) {
- duk_double_union du;
-#if defined(DUK_USE_64BIT_OPS)
- duk_uint64_t t;
-#else
- duk_uint32_t t;
-#endif
- du.d = x;
-#if defined(DUK_USE_64BIT_OPS)
-#if defined(DUK_USE_DOUBLE_ME)
- t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000);
- if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
- t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x0000000080000000);
- return t == 0;
- }
- if (t == DUK_U64_CONSTANT(0x000000007ff00000)) {
- return 1;
- }
-#else
- t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000);
- if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
- t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000);
- return t == 0;
- }
- if (t == DUK_U64_CONSTANT(0x7ff0000000000000)) {
- return 1;
- }
-#endif
-#else
- t = du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL;
- if (t == 0x00000000UL) {
- return DUK_DBLUNION_IS_ANYZERO(&du);
- }
- if (t == 0x7ff00000UL) {
- return 1;
- }
-#endif
- return 0;
-}
-
-DUK_INTERNAL duk_small_uint_t duk_double_signbit(duk_double_t x) {
- duk_double_union du;
- du.d = x;
- return (duk_small_uint_t) DUK_DBLUNION_GET_SIGNBIT(&du);
-}
-
-DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) {
- /* XXX: optimize */
- duk_small_uint_t s = duk_double_signbit(x);
- x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */
- if (s) {
- x = -x;
- }
- return x;
-}
-
-DUK_INTERNAL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y) {
- duk_double_union du1;
- duk_double_union du2;
- du1.d = x;
- du2.d = y;
-
- return (((du1.ui[DUK_DBL_IDX_UI0] ^ du2.ui[DUK_DBL_IDX_UI0]) & 0x80000000UL) == 0);
-}
-
-DUK_INTERNAL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y) {
- /* Doesn't replicate fmin() behavior exactly: for fmin() if one
- * argument is a NaN, the other argument should be returned.
- * Duktape doesn't rely on this behavior so the replacement can
- * be simplified.
- */
- return (x < y ? x : y);
-}
-
-DUK_INTERNAL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y) {
- /* Doesn't replicate fmax() behavior exactly: for fmax() if one
- * argument is a NaN, the other argument should be returned.
- * Duktape doesn't rely on this behavior so the replacement can
- * be simplified.
- */
- return (x > y ? x : y);
-}
/*
- * Hobject Ecmascript [[Class]].
+ * Hobject ECMAScript [[Class]].
*/
/* #include duk_internal.h -> already included */
@@ -13280,9 +13300,10 @@ DUK_EXTERNAL void *duk_resize_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t
if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
+ DUK_WO_NORETURN(return NULL;);
}
- /* maximum size check is handled by callee */
+ /* Maximum size check is handled by callee. */
duk_hbuffer_resize(thr, h, new_size);
return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
@@ -13300,6 +13321,7 @@ DUK_EXTERNAL void *duk_steal_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t
if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
+ DUK_WO_NORETURN(return NULL;);
}
/* Forget the previous allocation, setting size to 0 and alloc to
@@ -13328,6 +13350,7 @@ DUK_EXTERNAL void duk_config_buffer(duk_hthread *thr, duk_idx_t idx, void *ptr,
if (!DUK_HBUFFER_HAS_EXTERNAL(h)) {
DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
+ DUK_WO_NORETURN(return;);
}
DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h));
@@ -13376,7 +13399,7 @@ DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_hthread *thr, duk_uint8_t *p) {
len = DUK_RAW_READ_U32_BE(p);
buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len);
DUK_ASSERT(buf != NULL);
- DUK_MEMCPY((void *) buf, (const void *) p, (size_t) len);
+ duk_memcpy((void *) buf, (const void *) p, (size_t) len);
p += len;
return p;
}
@@ -13391,7 +13414,7 @@ DUK_LOCAL duk_uint8_t *duk__dump_hstring_raw(duk_uint8_t *p, duk_hstring *h) {
DUK_ASSERT(len <= 0xffffffffUL); /* string limits */
tmp32 = (duk_uint32_t) len;
DUK_RAW_WRITE_U32_BE(p, tmp32);
- DUK_MEMCPY((void *) p,
+ duk_memcpy((void *) p,
(const void *) DUK_HSTRING_GET_DATA(h),
len);
p += len;
@@ -13410,9 +13433,10 @@ DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, d
DUK_ASSERT(len <= 0xffffffffUL); /* buffer limits */
tmp32 = (duk_uint32_t) len;
DUK_RAW_WRITE_U32_BE(p, tmp32);
- DUK_MEMCPY((void *) p,
- (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
- len);
+ /* When len == 0, buffer data pointer may be NULL. */
+ duk_memcpy_unsafe((void *) p,
+ (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
+ len);
p += len;
return p;
}
@@ -13624,7 +13648,7 @@ static duk_uint8_t *duk__dump_func(duk_hthread *thr, duk_hcompfunc *func, duk_bu
ins_end = DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func);
DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr);
#if defined(DUK_USE_INTEGER_BE)
- DUK_MEMCPY((void *) p, (const void *) ins, (size_t) (ins_end - ins));
+ duk_memcpy_unsafe((void *) p, (const void *) ins, (size_t) (ins_end - ins));
p += (size_t) (ins_end - ins);
#else
while (ins != ins_end) {
@@ -13646,7 +13670,7 @@ static duk_uint8_t *duk__dump_func(duk_hthread *thr, duk_hcompfunc *func, duk_bu
h_str = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h_str != NULL);
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 4U + DUK_HSTRING_GET_BYTELEN(h_str), p),
+ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 4U + DUK_HSTRING_GET_BYTELEN(h_str), p);
*p++ = DUK__SER_STRING;
p = duk__dump_hstring_raw(p, h_str);
} else {
@@ -13810,7 +13834,7 @@ static duk_uint8_t *duk__load_func(duk_hthread *thr, duk_uint8_t *p, duk_uint8_t
DUK__ASSERT_LEFT(count_instr * sizeof(duk_instr_t));
#if defined(DUK_USE_INTEGER_BE)
q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
- DUK_MEMCPY((void *) q,
+ duk_memcpy((void *) q,
(const void *) p,
sizeof(duk_instr_t) * count_instr);
p += sizeof(duk_instr_t) * count_instr;
@@ -13875,15 +13899,12 @@ static duk_uint8_t *duk__load_func(duk_hthread *thr, duk_uint8_t *p, duk_uint8_t
DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL);
q = fun_data;
- if (count_const > 0) {
- /* Explicit zero size check to avoid NULL 'tv1'. */
- DUK_MEMCPY((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const);
- for (n = count_const; n > 0; n--) {
- DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */
- q += sizeof(duk_tval);
- }
- tv1 += count_const;
+ duk_memcpy_unsafe((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const);
+ for (n = count_const; n > 0; n--) {
+ DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */
+ q += sizeof(duk_tval);
}
+ tv1 += count_const;
DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q);
for (n = count_funcs; n > 0; n--) {
@@ -14084,6 +14105,7 @@ DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
format_error:
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BYTECODE);
+ DUK_WO_NORETURN(return;);
}
#else /* DUK_USE_BYTECODE_DUMP_SUPPORT */
@@ -14091,11 +14113,13 @@ DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) {
DUK_ASSERT_API_ENTRY(thr);
DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return;);
}
DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
DUK_ASSERT_API_ENTRY(thr);
DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return;);
}
#endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */
@@ -14162,7 +14186,7 @@ DUK_LOCAL duk_idx_t duk__call_get_idx_func(duk_hthread *thr, duk_idx_t nargs, du
idx_func = duk_get_top(thr) - nargs - other;
if (DUK_UNLIKELY((idx_func | nargs) < 0)) { /* idx_func < 0 || nargs < 0; OR sign bits */
DUK_ERROR_TYPE_INVALID_ARGS(thr);
- /* unreachable */
+ DUK_WO_NORETURN(return 0;);
}
DUK_ASSERT(duk_is_valid_index(thr, idx_func));
return idx_func;
@@ -14274,6 +14298,7 @@ DUK_EXTERNAL void duk_call_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t n
obj_idx = duk_require_normalize_index(thr, obj_idx); /* make absolute */
if (DUK_UNLIKELY(nargs < 0)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ DUK_WO_NORETURN(return;);
}
duk__call_prop_prep_stack(thr, obj_idx, nargs);
@@ -14310,7 +14335,7 @@ DUK_EXTERNAL duk_int_t duk_pcall(duk_hthread *thr, duk_idx_t nargs) {
args.nargs = nargs;
if (DUK_UNLIKELY(nargs < 0)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
- return DUK_EXEC_ERROR; /* unreachable */
+ DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
}
args.call_flags = 0;
@@ -14345,7 +14370,7 @@ DUK_INTERNAL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs,
args.nargs = nargs;
if (DUK_UNLIKELY(nargs < 0)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
- return DUK_EXEC_ERROR; /* unreachable */
+ DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
}
args.call_flags = call_flags;
@@ -14386,7 +14411,7 @@ DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_i
args.nargs = nargs;
if (DUK_UNLIKELY(nargs < 0)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
- return DUK_EXEC_ERROR; /* unreachable */
+ DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
}
args.call_flags = 0;
@@ -14422,7 +14447,7 @@ DUK_EXTERNAL duk_int_t duk_safe_call(duk_hthread *thr, duk_safe_call_function fu
(long) (thr->valstack_top - thr->valstack),
(long) nrets));
DUK_ERROR_TYPE_INVALID_ARGS(thr);
- return DUK_EXEC_ERROR; /* unreachable */
+ DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
}
rc = duk_handle_safe_call(thr, /* thread */
@@ -14470,7 +14495,7 @@ DUK_EXTERNAL duk_int_t duk_pnew(duk_hthread *thr, duk_idx_t nargs) {
if (DUK_UNLIKELY(nargs < 0)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
- return DUK_EXEC_ERROR; /* unreachable */
+ DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
}
rc = duk_safe_call(thr, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
@@ -14497,6 +14522,7 @@ DUK_INTERNAL void duk_require_constructor_call(duk_hthread *thr) {
if (!duk_is_constructor_call(thr)) {
DUK_ERROR_TYPE(thr, DUK_STR_CONSTRUCT_ONLY);
+ DUK_WO_NORETURN(return;);
}
}
@@ -14507,7 +14533,7 @@ DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_hthread *thr) {
* because all Duktape/C functions are considered strict,
* and strict is also the default when nothing is running.
* However, Duktape may call this function internally when
- * the current activation is an Ecmascript function, so
+ * the current activation is an ECMAScript function, so
* this cannot be replaced by a 'return 1' without fixing
* the internal call sites.
*/
@@ -14574,7 +14600,7 @@ DUK_EXTERNAL duk_int_t duk_get_magic(duk_hthread *thr, duk_idx_t idx) {
/* fall through */
type_error:
DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
- return 0;
+ DUK_WO_NORETURN(return 0;);
}
DUK_EXTERNAL void duk_set_magic(duk_hthread *thr, duk_idx_t idx, duk_int_t magic) {
@@ -14606,7 +14632,7 @@ DUK_INTERNAL void duk_resolve_nonbound_function(duk_hthread *thr) {
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) {
- duk_push_tval(thr, &((duk_hboundfunc *) h)->target);
+ duk_push_tval(thr, &((duk_hboundfunc *) (void *) h)->target);
duk_replace(thr, -2);
#if 0
DUK_TVAL_SET_TVAL(tv, &((duk_hboundfunc *) h)->target);
@@ -14636,6 +14662,10 @@ DUK_INTERNAL void duk_resolve_nonbound_function(duk_hthread *thr) {
/* #include duk_internal.h -> already included */
+/*
+ * Misc helpers
+ */
+
/* Shared handling for encode/decode argument. Fast path handling for
* buffer and string values because they're the most common. In particular,
* avoid creating a temporary string or buffer when possible.
@@ -14657,250 +14687,425 @@ DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_hthread *thr, duk_idx_t idx
return (const duk_uint8_t *) duk_to_lstring(thr, idx, out_len);
}
+/*
+ * Base64
+ */
+
+#if defined(DUK_USE_BASE64_SUPPORT)
+/* Bytes emitted for number of padding characters in range [0,4]. */
+DUK_LOCAL const duk_int8_t duk__base64_decode_nequal_step[5] = {
+ 3, /* #### -> 24 bits, emit 3 bytes */
+ 2, /* ###= -> 18 bits, emit 2 bytes */
+ 1, /* ##== -> 12 bits, emit 1 byte */
+ -1, /* #=== -> 6 bits, error */
+ 0, /* ==== -> 0 bits, emit 0 bytes */
+};
+
#if defined(DUK_USE_BASE64_FASTPATH)
-DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
+DUK_LOCAL const duk_uint8_t duk__base64_enctab_fast[64] = {
+ 0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, 0x48U, 0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU, 0x50U, /* A...P */
+ 0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U, 0x58U, 0x59U, 0x5aU, 0x61U, 0x62U, 0x63U, 0x64U, 0x65U, 0x66U, /* Q...f */
+ 0x67U, 0x68U, 0x69U, 0x6aU, 0x6bU, 0x6cU, 0x6dU, 0x6eU, 0x6fU, 0x70U, 0x71U, 0x72U, 0x73U, 0x74U, 0x75U, 0x76U, /* g...v */
+ 0x77U, 0x78U, 0x79U, 0x7aU, 0x30U, 0x31U, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U, 0x38U, 0x39U, 0x2bU, 0x2fU /* w.../ */
+};
+#endif /* DUK_USE_BASE64_FASTPATH */
+
+#if defined(DUK_USE_BASE64_FASTPATH)
+/* Decode table for one byte of input:
+ * -1 = allowed whitespace
+ * -2 = padding
+ * -3 = error
+ * 0...63 decoded bytes
+ */
+DUK_LOCAL const duk_int8_t duk__base64_dectab_fast[256] = {
+ -3, -3, -3, -3, -3, -3, -3, -3, -3, -1, -1, -3, -3, -1, -3, -3, /* 0x00...0x0f */
+ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x10...0x1f */
+ -1, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 62, -3, -3, -3, 63, /* 0x20...0x2f */
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -3, -3, -3, -2, -3, -3, /* 0x30...0x3f */
+ -3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -3, -3, -3, -3, -3, /* 0x50...0x5f */
+ -3, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -3, -3, -3, -3, -3, /* 0x70...0x7f */
+ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x80...0x8f */
+ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x90...0x9f */
+ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xa0...0xaf */
+ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xb0...0xbf */
+ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xc0...0xcf */
+ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xd0...0xdf */
+ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xe0...0xef */
+ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3 /* 0xf0...0xff */
+};
+#endif /* DUK_USE_BASE64_FASTPATH */
+
+#if defined(DUK_USE_BASE64_FASTPATH)
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_3(const duk_uint8_t *src, duk_uint8_t *dst) {
duk_uint_t t;
- duk_size_t n_full, n_full3, n_final;
- const duk_uint8_t *src_end_fast;
-
- n_full = srclen / 3; /* full 3-byte -> 4-char conversions */
- n_full3 = n_full * 3;
- n_final = srclen - n_full3;
- DUK_ASSERT_DISABLE(n_final >= 0);
- DUK_ASSERT(n_final <= 2);
-
- src_end_fast = src + n_full3;
- while (DUK_UNLIKELY(src != src_end_fast)) {
- t = (duk_uint_t) (*src++);
- t = (t << 8) + (duk_uint_t) (*src++);
- t = (t << 8) + (duk_uint_t) (*src++);
-
- *dst++ = duk_base64_enctab[t >> 18];
- *dst++ = duk_base64_enctab[(t >> 12) & 0x3f];
- *dst++ = duk_base64_enctab[(t >> 6) & 0x3f];
- *dst++ = duk_base64_enctab[t & 0x3f];
-
-#if 0 /* Tested: not faster on x64 */
- /* aaaaaabb bbbbcccc ccdddddd */
- dst[0] = duk_base64_enctab[(src[0] >> 2) & 0x3f];
- dst[1] = duk_base64_enctab[((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0f)];
- dst[2] = duk_base64_enctab[((src[1] << 2) & 0x3f) | ((src[2] >> 6) & 0x03)];
- dst[3] = duk_base64_enctab[src[2] & 0x3f];
- src += 3; dst += 4;
-#endif
- }
-
- switch (n_final) {
- /* case 0: nop */
- case 1: {
- /* XX== */
- t = (duk_uint_t) (*src++);
- *dst++ = duk_base64_enctab[t >> 2]; /* XXXXXX-- */
- *dst++ = duk_base64_enctab[(t << 4) & 0x3f]; /* ------XX */
- *dst++ = DUK_ASC_EQUALS;
- *dst++ = DUK_ASC_EQUALS;
- break;
- }
- case 2: {
- /* XXX= */
- t = (duk_uint_t) (*src++);
- t = (t << 8) + (duk_uint_t) (*src++);
- *dst++ = duk_base64_enctab[t >> 10]; /* XXXXXX-- -------- */
- *dst++ = duk_base64_enctab[(t >> 4) & 0x3f]; /* ------XX XXXX---- */
- *dst++ = duk_base64_enctab[(t << 2) & 0x3f]; /* -------- ----XXXX */
- *dst++ = DUK_ASC_EQUALS;
- break;
- }
+
+ t = (duk_uint_t) src[0];
+ t = (t << 8) + (duk_uint_t) src[1];
+ t = (t << 8) + (duk_uint_t) src[2];
+
+ dst[0] = duk__base64_enctab_fast[t >> 18];
+ dst[1] = duk__base64_enctab_fast[(t >> 12) & 0x3fU];
+ dst[2] = duk__base64_enctab_fast[(t >> 6) & 0x3fU];
+ dst[3] = duk__base64_enctab_fast[t & 0x3fU];
+
+#if 0
+ /* Tested: not faster on x64, most likely due to aliasing between
+ * output and input index computation.
+ */
+ /* aaaaaabb bbbbcccc ccdddddd */
+ dst[0] = duk__base64_enctab_fast[(src[0] >> 2) & 0x3fU];
+ dst[1] = duk__base64_enctab_fast[((src[0] << 4) & 0x30U) | ((src[1] >> 4) & 0x0fU)];
+ dst[2] = duk__base64_enctab_fast[((src[1] << 2) & 0x3fU) | ((src[2] >> 6) & 0x03U)];
+ dst[3] = duk__base64_enctab_fast[src[2] & 0x3fU];
+#endif
+}
+
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_2(const duk_uint8_t *src, duk_uint8_t *dst) {
+ duk_uint_t t;
+
+ t = (duk_uint_t) src[0];
+ t = (t << 8) + (duk_uint_t) src[1];
+ dst[0] = duk__base64_enctab_fast[t >> 10]; /* XXXXXX-- -------- */
+ dst[1] = duk__base64_enctab_fast[(t >> 4) & 0x3fU]; /* ------XX XXXX---- */
+ dst[2] = duk__base64_enctab_fast[(t << 2) & 0x3fU]; /* -------- ----XXXX */
+ dst[3] = DUK_ASC_EQUALS;
+}
+
+DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_1(const duk_uint8_t *src, duk_uint8_t *dst) {
+ duk_uint_t t;
+
+ t = (duk_uint_t) src[0];
+ dst[0] = duk__base64_enctab_fast[t >> 2]; /* XXXXXX-- */
+ dst[1] = duk__base64_enctab_fast[(t << 4) & 0x3fU]; /* ------XX */
+ dst[2] = DUK_ASC_EQUALS;
+ dst[3] = DUK_ASC_EQUALS;
+}
+
+DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
+ duk_size_t n;
+ const duk_uint8_t *p;
+ duk_uint8_t *q;
+
+ n = srclen;
+ p = src;
+ q = dst;
+
+ if (n >= 16U) {
+ /* Fast path, unrolled by 4, allows interleaving. Process
+ * 12-byte input chunks which encode to 16-char output chunks.
+ * Only enter when at least one block is emitted (avoids div+mul
+ * for short inputs too).
+ */
+ const duk_uint8_t *p_end_fast;
+
+ p_end_fast = p + ((n / 12U) * 12U);
+ DUK_ASSERT(p_end_fast >= p + 12);
+ do {
+ duk__base64_encode_fast_3(p, q);
+ duk__base64_encode_fast_3(p + 3, q + 4);
+ duk__base64_encode_fast_3(p + 6, q + 8);
+ duk__base64_encode_fast_3(p + 9, q + 12);
+ p += 12;
+ q += 16;
+ } while (DUK_LIKELY(p != p_end_fast));
+
+ DUK_ASSERT(src + srclen >= p);
+ n = (duk_size_t) (src + srclen - p);
+ DUK_ASSERT(n < 12U);
+ }
+
+ /* Remainder. */
+ while (n >= 3U) {
+ duk__base64_encode_fast_3(p, q);
+ p += 3;
+ q += 4;
+ n -= 3U;
+ }
+ DUK_ASSERT(n == 0U || n == 1U || n == 2U);
+ if (n == 1U) {
+ duk__base64_encode_fast_1(p, q);
+#if 0 /* Unnecessary. */
+ p += 1;
+ q += 4;
+ n -= 1U;
+#endif
+ } else if (n == 2U) {
+ duk__base64_encode_fast_2(p, q);
+#if 0 /* Unnecessary. */
+ p += 2;
+ q += 4;
+ n -= 2U;
+#endif
+ } else {
+ DUK_ASSERT(n == 0U); /* nothing to do */
+ ;
}
}
#else /* DUK_USE_BASE64_FASTPATH */
DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
- duk_small_uint_t i, snip;
- duk_uint_t t;
- duk_uint_fast8_t x, y;
- const duk_uint8_t *src_end;
+ duk_small_uint_t i, npad;
+ duk_uint_t t, x, y;
+ const duk_uint8_t *p;
+ const duk_uint8_t *p_end;
+ duk_uint8_t *q;
- src_end = src + srclen;
+ p = src;
+ p_end = src + srclen;
+ q = dst;
+ npad = 0U;
- while (src < src_end) {
- /* read 3 bytes into 't', padded by zero */
- snip = 4;
+ while (p < p_end) {
+ /* Read 3 bytes into 't', padded by zero. */
t = 0;
for (i = 0; i < 3; i++) {
t = t << 8;
- if (src >= src_end) {
- snip--;
+ if (p < p_end) {
+ t += (duk_uint_t) (*p++);
} else {
- t += (duk_uint_t) (*src++);
+ /* This only happens on the last loop and we're
+ * guaranteed to exit on the next loop.
+ */
+ npad++;
}
}
+ DUK_ASSERT(npad <= 2U);
- /*
- * Missing bytes snip base64 example
- * 0 4 XXXX
- * 1 3 XXX=
- * 2 2 XX==
+ /* Emit 4 encoded characters. If npad > 0, some of the
+ * chars will be incorrect (zero bits) but we fix up the
+ * padding after the loop. A straightforward 64-byte
+ * lookup would be faster and cleaner, but this is shorter.
*/
-
- DUK_ASSERT(snip >= 2 && snip <= 4);
-
for (i = 0; i < 4; i++) {
- x = (duk_uint_fast8_t) ((t >> 18) & 0x3f);
+ x = ((t >> 18) & 0x3fU);
t = t << 6;
- /* A straightforward 64-byte lookup would be faster
- * and cleaner, but this is shorter.
- */
- if (i >= snip) {
- y = '=';
- } else if (x <= 25) {
- y = x + 'A';
- } else if (x <= 51) {
- y = x - 26 + 'a';
- } else if (x <= 61) {
- y = x - 52 + '0';
- } else if (x == 62) {
- y = '+';
+ if (x <= 51U) {
+ if (x <= 25) {
+ y = x + DUK_ASC_UC_A;
+ } else {
+ y = x - 26 + DUK_ASC_LC_A;
+ }
} else {
- y = '/';
+ if (x <= 61U) {
+ y = x - 52 + DUK_ASC_0;
+ } else if (x == 62) {
+ y = DUK_ASC_PLUS;
+ } else {
+ DUK_ASSERT(x == 63);
+ y = DUK_ASC_SLASH;
+ }
}
- *dst++ = (duk_uint8_t) y;
+ *q++ = (duk_uint8_t) y;
}
}
+
+ /* Handle padding by rewriting 0-2 bogus characters at the end.
+ *
+ * Missing bytes npad base64 example
+ * 0 0 ####
+ * 1 1 ###=
+ * 2 2 ##==
+ */
+ DUK_ASSERT(npad <= 2U);
+ while (npad > 0U) {
+ *(q - npad) = DUK_ASC_EQUALS;
+ npad--;
+ }
}
#endif /* DUK_USE_BASE64_FASTPATH */
#if defined(DUK_USE_BASE64_FASTPATH)
DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) {
duk_int_t x;
- duk_int_t t;
+ duk_uint_t t;
duk_small_uint_t n_equal;
- duk_small_uint_t n_chars;
- const duk_uint8_t *src_end;
- const duk_uint8_t *src_end_safe;
+ duk_int8_t step;
+ const duk_uint8_t *p;
+ const duk_uint8_t *p_end;
+ const duk_uint8_t *p_end_safe;
+ duk_uint8_t *q;
- src_end = src + srclen;
- src_end_safe = src_end - 4; /* if 'src < src_end_safe', safe to read 4 bytes */
+ p = src;
+ p_end = src + srclen;
+ p_end_safe = p_end - 8; /* If 'src <= src_end_safe', safe to read 8 bytes. */
+ q = dst;
- /* Innermost fast path processes 4 valid base-64 characters at a time
- * but bails out on whitespace, padding chars ('=') and invalid chars.
- * Once the slow path segment has been processed, we return to the
- * inner fast path again. This handles e.g. base64 with newlines
- * reasonably well because the majority of a line is in the fast path.
+ /* Alternate between a fast path which processes clean groups with no
+ * padding or whitespace, and a slow path which processes one arbitrary
+ * group and then re-enters the fast path. This handles e.g. base64
+ * with newlines reasonably well because the majority of a line is in
+ * the fast path.
*/
for (;;) {
- /* Fast path, handle units with just actual encoding characters. */
-
- while (src <= src_end_safe) {
- /* The lookup byte is intentionally sign extended to (at least)
- * 32 bits and then ORed. This ensures that is at least 1 byte
- * is negative, the highest bit of 't' will be set at the end
- * and we don't need to check every byte.
+ /* Fast path, on each loop handle two 4-char input groups.
+ * If both are clean, emit 6 bytes and continue. If first
+ * is clean, emit 3 bytes and drop out; otherwise emit
+ * nothing and drop out. This approach could be extended to
+ * more groups per loop, but for inputs with e.g. periodic
+ * newlines (which are common) it might not be an improvement.
+ */
+ while (DUK_LIKELY(p <= p_end_safe)) {
+ duk_int_t t1, t2;
+
+ /* The lookup byte is intentionally sign extended to
+ * (at least) 32 bits and then ORed. This ensures
+ * that is at least 1 byte is negative, the highest
+ * bit of the accumulator will be set at the end and
+ * we don't need to check every byte.
+ *
+ * Read all input bytes first before writing output
+ * bytes to minimize aliasing.
*/
- DUK_DDD(DUK_DDDPRINT("fast loop: src=%p, src_end_safe=%p, src_end=%p",
- (const void *) src, (const void *) src_end_safe, (const void *) src_end));
-
- t = (duk_int_t) duk_base64_dectab[*src++];
- t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
- t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
- t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
-
- if (DUK_UNLIKELY(t < 0)) {
- DUK_DDD(DUK_DDDPRINT("fast loop unit was not clean, process one slow path unit"));
- src -= 4;
+ DUK_DDD(DUK_DDDPRINT("fast loop: p=%p, p_end_safe=%p, p_end=%p",
+ (const void *) p, (const void *) p_end_safe, (const void *) p_end));
+
+ t1 = (duk_int_t) duk__base64_dectab_fast[p[0]];
+ t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[1]];
+ t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[2]];
+ t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[3]];
+
+ t2 = (duk_int_t) duk__base64_dectab_fast[p[4]];
+ t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[5]];
+ t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[6]];
+ t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[7]];
+
+ q[0] = (duk_uint8_t) (((duk_uint_t) t1 >> 16) & 0xffU);
+ q[1] = (duk_uint8_t) (((duk_uint_t) t1 >> 8) & 0xffU);
+ q[2] = (duk_uint8_t) ((duk_uint_t) t1 & 0xffU);
+
+ q[3] = (duk_uint8_t) (((duk_uint_t) t2 >> 16) & 0xffU);
+ q[4] = (duk_uint8_t) (((duk_uint_t) t2 >> 8) & 0xffU);
+ q[5] = (duk_uint8_t) ((duk_uint_t) t2 & 0xffU);
+
+ /* Optimistic check using one branch. */
+ if (DUK_LIKELY((t1 | t2) >= 0)) {
+ p += 8;
+ q += 6;
+ } else if (t1 >= 0) {
+ DUK_DDD(DUK_DDDPRINT("fast loop first group was clean, second was not, process one slow path group"));
+ DUK_ASSERT(t2 < 0);
+ p += 4;
+ q += 3;
+ break;
+ } else {
+ DUK_DDD(DUK_DDDPRINT("fast loop first group was not clean, second does not matter, process one slow path group"));
+ DUK_ASSERT(t1 < 0);
break;
}
+ } /* fast path */
- DUK_ASSERT(t <= 0xffffffL);
- DUK_ASSERT((t >> 24) == 0);
- *dst++ = (duk_uint8_t) (t >> 16);
- *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
- *dst++ = (duk_uint8_t) (t & 0xff);
- }
-
- /* Handle one slow path unit (or finish if we're done). */
-
- n_equal = 0;
- n_chars = 0;
- t = 0;
+ /* Slow path step 1: try to scan a 4-character encoded group,
+ * end-of-input, or start-of-padding. We exit with:
+ * 1. n_chars == 4: full group, no padding, no end-of-input.
+ * 2. n_chars < 4: partial group (may also be 0), encountered
+ * padding or end of input.
+ *
+ * The accumulator is initialized to 1; this allows us to detect
+ * a full group by comparing >= 0x1000000 without an extra
+ * counter variable.
+ */
+ t = 1UL;
for (;;) {
- DUK_DDD(DUK_DDDPRINT("slow loop: src=%p, src_end=%p, n_chars=%ld, n_equal=%ld, t=%ld",
- (const void *) src, (const void *) src_end, (long) n_chars, (long) n_equal, (long) t));
-
- if (DUK_UNLIKELY(src >= src_end)) {
- goto done; /* two level break */
- }
-
- x = duk_base64_dectab[*src++];
- if (DUK_UNLIKELY(x < 0)) {
- if (x == -2) {
+ DUK_DDD(DUK_DDDPRINT("slow loop: p=%p, p_end=%p, t=%lu",
+ (const void *) p, (const void *) p_end, (unsigned long) t));
+
+ if (DUK_LIKELY(p < p_end)) {
+ x = duk__base64_dectab_fast[*p++];
+ if (DUK_LIKELY(x >= 0)) {
+ DUK_ASSERT(x >= 0 && x <= 63);
+ t = (t << 6) + (duk_uint_t) x;
+ if (t >= 0x1000000UL) {
+ break;
+ }
+ } else if (x == -1) {
continue; /* allowed ascii whitespace */
- } else if (x == -3) {
- n_equal++;
- t <<= 6;
+ } else if (x == -2) {
+ p--;
+ break; /* start of padding */
} else {
- DUK_ASSERT(x == -1);
+ DUK_ASSERT(x == -3);
goto decode_error;
}
} else {
- DUK_ASSERT(x >= 0 && x <= 63);
- if (n_equal > 0) {
- /* Don't allow actual chars after equal sign. */
- goto decode_error;
- }
- t = (t << 6) + x;
+ break; /* end of input */
}
+ } /* slow path step 1 */
- if (DUK_UNLIKELY(n_chars == 3)) {
- /* Emit 3 bytes and backtrack if there was padding. There's
- * always space for the whole 3 bytes so no check needed.
- */
- DUK_ASSERT(t <= 0xffffffL);
- DUK_ASSERT((t >> 24) == 0);
- *dst++ = (duk_uint8_t) (t >> 16);
- *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
- *dst++ = (duk_uint8_t) (t & 0xff);
-
- if (DUK_UNLIKELY(n_equal > 0)) {
- DUK_ASSERT(n_equal <= 4);
-
- /* There may be whitespace between the equal signs. */
- if (n_equal == 1) {
- /* XXX= */
- dst -= 1;
- } else if (n_equal == 2) {
- /* XX== */
- dst -= 2;
- } else {
- goto decode_error; /* invalid padding */
- }
+ /* Complete the padding by simulating pad characters,
+ * regardless of actual input padding chars.
+ */
+ n_equal = 0;
+ while (t < 0x1000000UL) {
+ t = (t << 6) + 0U;
+ n_equal++;
+ }
- /* Continue parsing after padding, allows concatenated,
- * padded base64.
- */
- }
- break; /* back to fast loop */
+ /* Slow path step 2: deal with full/partial group, padding,
+ * etc. Note that for num chars in [0,3] we intentionally emit
+ * 3 bytes but don't step forward that much, buffer space is
+ * guaranteed in setup.
+ *
+ * num chars:
+ * 0 #### no output (= step 0)
+ * 1 #=== reject, 6 bits of data
+ * 2 ##== 12 bits of data, output 1 byte (= step 1)
+ * 3 ###= 18 bits of data, output 2 bytes (= step 2)
+ * 4 #### 24 bits of data, output 3 bytes (= step 3)
+ */
+ q[0] = (duk_uint8_t) ((t >> 16) & 0xffU);
+ q[1] = (duk_uint8_t) ((t >> 8) & 0xffU);
+ q[2] = (duk_uint8_t) (t & 0xffU);
+
+ DUK_ASSERT(n_equal <= 4);
+ step = duk__base64_decode_nequal_step[n_equal];
+ if (DUK_UNLIKELY(step < 0)) {
+ goto decode_error;
+ }
+ q += step;
+
+ /* Slow path step 3: read and ignore padding and whitespace
+ * until (a) next non-padding and non-whitespace character
+ * after which we resume the fast path, or (b) end of input.
+ * This allows us to accept missing, partial, full, and extra
+ * padding cases uniformly. We also support concatenated
+ * base-64 documents because we resume scanning afterwards.
+ *
+ * Note that to support concatenated documents well, the '='
+ * padding found inside the input must also allow for 'extra'
+ * padding. For example, 'Zm===' decodes to 'f' and has one
+ * extra padding char. So, 'Zm===Zm' should decode 'ff', even
+ * though the standard break-up would be 'Zm==' + '=Zm' which
+ * doesn't make sense.
+ *
+ * We also accept prepended padding like '==Zm9', because it
+ * is equivalent to an empty document with extra padding ('==')
+ * followed by a valid document.
+ */
+
+ for (;;) {
+ if (DUK_UNLIKELY(p >= p_end)) {
+ goto done;
+ }
+ x = duk__base64_dectab_fast[*p++];
+ if (x == -1 || x == -2) {
+ ; /* padding or whitespace, keep eating */
} else {
- n_chars++;
+ p--;
+ break; /* backtrack and go back to fast path, even for -1 */
}
- }
- }
- done:
- DUK_DDD(DUK_DDDPRINT("done; src=%p, src_end=%p, n_chars=%ld",
- (const void *) src, (const void *) src_end, (long) n_chars));
+ } /* slow path step 3 */
+ } /* outer fast+slow path loop */
- DUK_ASSERT(src == src_end);
+ done:
+ DUK_DDD(DUK_DDDPRINT("done; p=%p, p_end=%p",
+ (const void *) p, (const void *) p_end));
- if (n_chars != 0) {
- /* Here we'd have the option of decoding unpadded base64
- * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
- * accepted.
- */
- goto decode_error;
- }
+ DUK_ASSERT(p == p_end);
- *out_dst_final = dst;
+ *out_dst_final = q;
return 1;
decode_error:
@@ -14908,94 +15113,138 @@ DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_
}
#else /* DUK_USE_BASE64_FASTPATH */
DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) {
- duk_uint_t t;
- duk_uint_fast8_t x, y;
- duk_small_uint_t group_idx;
- duk_small_uint_t n_equal;
- const duk_uint8_t *src_end;
+ duk_uint_t t, x;
+ duk_int_t y;
+ duk_int8_t step;
+ const duk_uint8_t *p;
+ const duk_uint8_t *p_end;
+ duk_uint8_t *q;
+ /* 0x09, 0x0a, or 0x0d */
+ duk_uint32_t mask_white = (1U << 9) | (1U << 10) | (1U << 13);
- src_end = src + srclen;
- t = 0;
- group_idx = 0;
- n_equal = 0;
-
- while (src < src_end) {
- x = *src++;
-
- if (x >= 'A' && x <= 'Z') {
- y = x - 'A' + 0;
- } else if (x >= 'a' && x <= 'z') {
- y = x - 'a' + 26;
- } else if (x >= '0' && x <= '9') {
- y = x - '0' + 52;
- } else if (x == '+') {
- y = 62;
- } else if (x == '/') {
- y = 63;
- } else if (x == '=') {
- /* We don't check the zero padding bytes here right now
- * (that they're actually zero). This seems to be common
- * behavior for base-64 decoders.
+ /* 't' tracks progress of the decoded group:
+ *
+ * t == 1 no valid chars yet
+ * t >= 0x40 1x6 = 6 bits shifted in
+ * t >= 0x1000 2x6 = 12 bits shifted in
+ * t >= 0x40000 3x6 = 18 bits shifted in
+ * t >= 0x1000000 4x6 = 24 bits shifted in
+ *
+ * By initializing t=1 there's no need for a separate counter for
+ * the number of characters found so far.
+ */
+ p = src;
+ p_end = src + srclen;
+ q = dst;
+ t = 1UL;
+
+ for (;;) {
+ duk_small_uint_t n_equal;
+
+ DUK_ASSERT(t >= 1U);
+ if (p >= p_end) {
+ /* End of input: if input exists, treat like
+ * start of padding, finish the block, then
+ * re-enter here to see we're done.
*/
+ if (t == 1U) {
+ break;
+ } else {
+ goto simulate_padding;
+ }
+ }
- n_equal++;
- t <<= 6; /* shift in zeroes */
- goto skip_add;
- } else if (x == 0x09 || x == 0x0a || x == 0x0d || x == 0x20) {
- /* allow basic ASCII whitespace */
- continue;
+ x = *p++;
+
+ if (x >= 0x41U) {
+ /* Valid: a-z and A-Z. */
+ DUK_ASSERT(x >= 0x41U && x <= 0xffU);
+ if (x >= 0x61U && x <= 0x7aU) {
+ y = (duk_int_t) x - 0x61 + 26;
+ } else if (x <= 0x5aU) {
+ y = (duk_int_t) x - 0x41;
+ } else {
+ goto decode_error;
+ }
+ } else if (x >= 0x30U) {
+ /* Valid: 0-9 and =. */
+ DUK_ASSERT(x >= 0x30U && x <= 0x40U);
+ if (x <= 0x39U) {
+ y = (duk_int_t) x - 0x30 + 52;
+ } else if (x == 0x3dU) {
+ /* Skip padding and whitespace unless we're in the
+ * middle of a block. Otherwise complete group by
+ * simulating shifting in the correct padding.
+ */
+ if (t == 1U) {
+ continue;
+ }
+ goto simulate_padding;
+ } else {
+ goto decode_error;
+ }
+ } else if (x >= 0x20U) {
+ /* Valid: +, /, and 0x20 whitespace. */
+ DUK_ASSERT(x >= 0x20U && x <= 0x2fU);
+ if (x == 0x2bU) {
+ y = 62;
+ } else if (x == 0x2fU) {
+ y = 63;
+ } else if (x == 0x20U) {
+ continue;
+ } else {
+ goto decode_error;
+ }
} else {
- goto decode_error;
+ /* Valid: whitespace. */
+ duk_uint32_t m;
+ DUK_ASSERT(x < 0x20U); /* 0x00 to 0x1f */
+ m = (1U << x);
+ if (mask_white & m) {
+ /* Allow basic ASCII whitespace. */
+ continue;
+ } else {
+ goto decode_error;
+ }
}
- if (n_equal > 0) {
- /* Don't allow mixed padding and actual chars. */
- goto decode_error;
+ DUK_ASSERT(y >= 0 && y <= 63);
+ t = (t << 6) + (duk_uint_t) y;
+ if (t < 0x1000000UL) {
+ continue;
}
- t = (t << 6) + y;
- skip_add:
-
- if (group_idx == 3) {
- /* output 3 bytes from 't' */
- *dst++ = (duk_uint8_t) ((t >> 16) & 0xff);
- *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
- *dst++ = (duk_uint8_t) (t & 0xff);
-
- if (DUK_UNLIKELY(n_equal > 0)) {
- /* Backtrack. */
- DUK_ASSERT(n_equal <= 4);
- if (n_equal == 1) {
- dst -= 1;
- } else if (n_equal == 2) {
- dst -= 2;
- } else {
- goto decode_error; /* invalid padding */
- }
+ /* fall through; no padding will be added */
- /* Here we can choose either to end parsing and ignore
- * whatever follows, or to continue parsing in case
- * multiple (possibly padded) base64 strings have been
- * concatenated. Currently, keep on parsing.
- */
- n_equal = 0;
- }
+ simulate_padding:
+ n_equal = 0;
+ while (t < 0x1000000UL) {
+ t = (t << 6) + 0U;
+ n_equal++;
+ }
- t = 0;
- group_idx = 0;
- } else {
- group_idx++;
+ /* Output 3 bytes from 't' and advance as needed. */
+ q[0] = (duk_uint8_t) ((t >> 16) & 0xffU);
+ q[1] = (duk_uint8_t) ((t >> 8) & 0xffU);
+ q[2] = (duk_uint8_t) (t & 0xffU);
+
+ DUK_ASSERT(n_equal <= 4U);
+ step = duk__base64_decode_nequal_step[n_equal];
+ if (step < 0) {
+ goto decode_error;
}
- }
+ q += step;
- if (group_idx != 0) {
- /* Here we'd have the option of decoding unpadded base64
- * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
- * accepted.
+ /* Re-enter loop. The actual padding characters are skipped
+ * by the main loop. This handles cases like missing, partial,
+ * full, and extra padding, and allows parsing of concatenated
+ * documents (with extra padding) like: Zm===Zm. Also extra
+ * prepended padding is accepted: ===Zm9v.
*/
- goto decode_error;
+ t = 1U;
}
+ DUK_ASSERT(t == 1UL);
- *out_dst_final = dst;
+ *out_dst_final = q;
return 1;
decode_error:
@@ -15012,15 +15261,12 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT_API_ENTRY(thr);
- /* XXX: optimize for string inputs: no need to coerce to a buffer
- * which makes a copy of the input.
- */
-
idx = duk_require_normalize_index(thr, idx);
src = duk__prep_codec_arg(thr, idx, &srclen);
/* Note: for srclen=0, src may be NULL */
- /* Computation must not wrap; this limit works for 32-bit size_t:
+ /* Compute exact output length. Computation must not wrap; this
+ * limit works for 32-bit size_t:
* >>> srclen = 3221225469
* >>> '%x' % ((srclen + 2) / 3 * 4)
* 'fffffffc'
@@ -15028,7 +15274,7 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) {
if (srclen > 3221225469UL) {
goto type_error;
}
- dstlen = (srclen + 2) / 3 * 4;
+ dstlen = (srclen + 2U) / 3U * 4U;
dst = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, dstlen);
duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst);
@@ -15039,7 +15285,7 @@ DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) {
type_error:
DUK_ERROR_TYPE(thr, DUK_STR_BASE64_ENCODE_FAILED);
- return NULL; /* never here */
+ DUK_WO_NORETURN(return NULL;);
}
DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) {
@@ -15048,31 +15294,24 @@ DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) {
duk_size_t dstlen;
duk_uint8_t *dst;
duk_uint8_t *dst_final;
- duk_bool_t retval;
DUK_ASSERT_API_ENTRY(thr);
- /* XXX: optimize for buffer inputs: no need to coerce to a string
- * which causes an unnecessary interning.
- */
-
idx = duk_require_normalize_index(thr, idx);
src = duk__prep_codec_arg(thr, idx, &srclen);
- /* Computation must not wrap, only srclen + 3 is at risk of
- * wrapping because after that the number gets smaller.
- * This limit works for 32-bit size_t:
- * 0x100000000 - 3 - 1 = 4294967292
+ /* Round up and add safety margin. Avoid addition before division to
+ * avoid possibility of wrapping. Margin includes +3 for rounding up,
+ * and +3 for one extra group: the decoder may emit and then backtrack
+ * a full group (3 bytes) from zero-sized input for technical reasons.
+ * Similarly, 'xx' may ecause 1+3 = bytes to be emitted and then
+ * backtracked.
*/
- if (srclen > 4294967292UL) {
- goto type_error;
- }
- dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */
+ dstlen = (srclen / 4) * 3 + 6; /* upper limit, assuming no whitespace etc */
dst = (duk_uint8_t *) duk_push_dynamic_buffer(thr, dstlen);
/* Note: for dstlen=0, dst may be NULL */
- retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final);
- if (!retval) {
+ if (!duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final)) {
goto type_error;
}
@@ -15083,8 +15322,27 @@ DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) {
type_error:
DUK_ERROR_TYPE(thr, DUK_STR_BASE64_DECODE_FAILED);
+ DUK_WO_NORETURN(return;);
+}
+#else /* DUK_USE_BASE64_SUPPORT */
+DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) {
+ DUK_UNREF(idx);
+ DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return;);
+}
+
+DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) {
+ DUK_UNREF(idx);
+ DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return;);
}
+#endif /* DUK_USE_BASE64_SUPPORT */
+
+/*
+ * Hex
+ */
+#if defined(DUK_USE_HEX_SUPPORT)
DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *inp;
duk_size_t len;
@@ -15195,8 +15453,12 @@ DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) {
}
}
for (; i < len; i += 2) {
- t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) |
- ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
+ /* First cast to duk_int_t to sign extend, second cast to
+ * duk_uint_t to avoid signed left shift, and final cast to
+ * duk_int_t result type.
+ */
+ t = (duk_int_t) ((((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i]]) << 4U) |
+ ((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i + 1]]));
if (DUK_UNLIKELY(t < 0)) {
goto type_error;
}
@@ -15208,8 +15470,8 @@ DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) {
* at least 16 bits. If either nybble is invalid, the
* resulting 't' will be < 0.
*/
- t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) |
- ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
+ t = (duk_int_t) ((((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i]]) << 4U) |
+ ((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i + 1]]));
if (DUK_UNLIKELY(t < 0)) {
goto type_error;
}
@@ -15222,7 +15484,24 @@ DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) {
type_error:
DUK_ERROR_TYPE(thr, DUK_STR_HEX_DECODE_FAILED);
+ DUK_WO_NORETURN(return;);
}
+#else /* DUK_USE_HEX_SUPPORT */
+DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) {
+ DUK_UNREF(idx);
+ DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return;);
+}
+DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) {
+ DUK_UNREF(idx);
+ DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return;);
+}
+#endif /* DUK_USE_HEX_SUPPORT */
+
+/*
+ * JSON
+ */
#if defined(DUK_USE_JSON_SUPPORT)
DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
@@ -15275,12 +15554,14 @@ DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(idx);
DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return NULL;);
}
DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(idx);
DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return;);
}
#endif /* DUK_USE_JSON_SUPPORT */
/*
@@ -15374,6 +15655,7 @@ DUK_LOCAL duk_ret_t duk__do_compile(duk_hthread *thr, void *udata) {
if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */
(h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */
DUK_ERROR_TYPE(thr, DUK_STR_NO_SOURCECODE);
+ DUK_WO_NORETURN(return 0;);
}
DUK_ASSERT(h_sourcecode != NULL);
comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
@@ -15498,6 +15780,7 @@ DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
DUK_ASSERT_API_ENTRY(thr);
DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return;);
}
#endif /* DUK_USE_JSON_SUPPORT */
@@ -15609,7 +15892,7 @@ DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues)
top = duk_get_top(thr);
if (top < nvalues) {
DUK_ERROR_RANGE(thr, "not enough stack values for notify");
- return ret; /* unreachable */
+ DUK_WO_NORETURN(return 0;);
}
if (duk_debug_is_attached(thr->heap)) {
duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY);
@@ -15676,11 +15959,13 @@ DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr,
DUK_UNREF(detached_cb);
DUK_UNREF(udata);
DUK_ERROR_TYPE(thr, "no debugger support");
+ DUK_WO_NORETURN(return;);
}
DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) {
DUK_ASSERT_API_ENTRY(thr);
DUK_ERROR_TYPE(thr, "no debugger support");
+ DUK_WO_NORETURN(return;);
}
DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) {
@@ -15697,7 +15982,7 @@ DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues)
top = duk_get_top(thr);
if (top < nvalues) {
DUK_ERROR_RANGE_INVALID_COUNT(thr);
- return 0; /* unreachable */
+ DUK_WO_NORETURN(return 0;);
}
/* No debugger support, just pop values. */
@@ -15819,7 +16104,7 @@ DUK_EXTERNAL void duk_suspend(duk_hthread *thr, duk_thread_state *state) {
duk_push_tval(thr, &lj->value2);
/* XXX: creating_error == 0 is asserted above, so no need to store. */
- DUK_MEMCPY((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate));
+ duk_memcpy((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate));
snapshot->creating_error = heap->creating_error;
snapshot->curr_thread = heap->curr_thread;
snapshot->call_recursion_depth = heap->call_recursion_depth;
@@ -15849,7 +16134,7 @@ DUK_EXTERNAL void duk_resume(duk_hthread *thr, const duk_thread_state *state) {
heap = thr->heap;
- DUK_MEMCPY((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate));
+ duk_memcpy((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate));
heap->creating_error = snapshot->creating_error;
heap->curr_thread = snapshot->curr_thread;
heap->call_recursion_depth = snapshot->call_recursion_depth;
@@ -15985,7 +16270,7 @@ DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT_API_ENTRY(thr);
/* Assume two's complement and set everything to -1. */
- DUK_MEMSET((void *) &vals, (int) 0xff, sizeof(vals));
+ duk_memset((void *) &vals, (int) 0xff, sizeof(vals));
DUK_ASSERT(vals[DUK__IDX_TYPE] == -1); /* spot check one */
tv = duk_get_tval_or_unused(thr, idx);
@@ -16001,12 +16286,12 @@ DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) {
goto finish;
}
duk_push_pointer(thr, (void *) h);
- duk_put_prop_string(thr, -2, "hptr");
+ duk_put_prop_literal(thr, -2, "hptr");
#if 0
/* Covers a lot of information, e.g. buffer and string variants. */
duk_push_uint(thr, (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
- duk_put_prop_string(thr, -2, "hflags");
+ duk_put_prop_literal(thr, -2, "hflags");
#endif
#if defined(DUK_USE_REFERENCE_COUNTING)
@@ -16051,7 +16336,7 @@ DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) {
}
vals[DUK__IDX_CLASS] = (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h_obj);
- vals[DUK__IDX_PBYTES] = (duk_int_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj),
+ vals[DUK__IDX_PBYTES] = (duk_int_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj);
vals[DUK__IDX_ESIZE] = (duk_int_t) DUK_HOBJECT_GET_ESIZE(h_obj);
vals[DUK__IDX_ENEXT] = (duk_int_t) DUK_HOBJECT_GET_ENEXT(h_obj);
vals[DUK__IDX_ASIZE] = (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj);
@@ -16252,7 +16537,7 @@ DUK_EXTERNAL void duk_gc(duk_hthread *thr, duk_uint_t flags) {
* Property handling
*
* The API exposes only the most common property handling functions.
- * The caller can invoke Ecmascript built-ins for full control (e.g.
+ * The caller can invoke ECMAScript built-ins for full control (e.g.
* defineProperty, getOwnPropertyDescriptor).
*/
@@ -16284,7 +16569,7 @@ DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_hthread *thr, duk_idx_t obj_idx,
DUK_ASSERT(key != NULL);
obj_idx = duk_require_normalize_index(thr, obj_idx);
- duk_push_string(thr, key);
+ (void) duk_push_string(thr, key);
return duk_get_prop(thr, obj_idx);
}
@@ -16293,9 +16578,21 @@ DUK_EXTERNAL duk_bool_t duk_get_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx
DUK_ASSERT(key != NULL);
obj_idx = duk_require_normalize_index(thr, obj_idx);
- duk_push_lstring(thr, key, key_len);
+ (void) duk_push_lstring(thr, key, key_len);
+ return duk_get_prop(thr, obj_idx);
+}
+
+#if !defined(DUK_USE_PREFER_SIZE)
+DUK_EXTERNAL duk_bool_t duk_get_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(key != NULL);
+ DUK_ASSERT(key[key_len] == (char) 0);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ (void) duk_push_literal_raw(thr, key, key_len);
return duk_get_prop(thr, obj_idx);
}
+#endif
DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
DUK_ASSERT_API_ENTRY(thr);
@@ -16309,7 +16606,7 @@ DUK_EXTERNAL duk_bool_t duk_get_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx
DUK_ASSERT_API_ENTRY(thr);
obj_idx = duk_require_normalize_index(thr, obj_idx);
- duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
return duk_get_prop(thr, obj_idx);
}
@@ -16318,7 +16615,7 @@ DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx,
DUK_ASSERT_STRIDX_VALID(stridx);
obj_idx = duk_require_normalize_index(thr, obj_idx);
- duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
+ (void) duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
return duk_get_prop(thr, obj_idx);
}
@@ -16337,10 +16634,7 @@ DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t
if (out_has_prop) {
*out_has_prop = rc;
}
- rc = duk_to_boolean(thr, -1);
- DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop(thr);
- return rc;
+ return duk_to_boolean_top_pop(thr);
}
DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t idx_key) {
@@ -16400,6 +16694,18 @@ DUK_EXTERNAL duk_bool_t duk_put_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx
return duk__put_prop_shared(thr, obj_idx, -1);
}
+#if !defined(DUK_USE_PREFER_SIZE)
+DUK_EXTERNAL duk_bool_t duk_put_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(key != NULL);
+ DUK_ASSERT(key[key_len] == (char) 0);
+
+ obj_idx = duk_normalize_index(thr, obj_idx);
+ (void) duk_push_literal_raw(thr, key, key_len);
+ return duk__put_prop_shared(thr, obj_idx, -1);
+}
+#endif
+
DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
DUK_ASSERT_API_ENTRY(thr);
@@ -16412,7 +16718,7 @@ DUK_EXTERNAL duk_bool_t duk_put_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx
DUK_ASSERT_API_ENTRY(thr);
obj_idx = duk_require_normalize_index(thr, obj_idx);
- duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
return duk__put_prop_shared(thr, obj_idx, -1);
}
@@ -16459,7 +16765,7 @@ DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_hthread *thr, duk_idx_t obj_idx,
DUK_ASSERT(key != NULL);
obj_idx = duk_require_normalize_index(thr, obj_idx);
- duk_push_string(thr, key);
+ (void) duk_push_string(thr, key);
return duk_del_prop(thr, obj_idx);
}
@@ -16468,9 +16774,21 @@ DUK_EXTERNAL duk_bool_t duk_del_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx
DUK_ASSERT(key != NULL);
obj_idx = duk_require_normalize_index(thr, obj_idx);
- duk_push_lstring(thr, key, key_len);
+ (void) duk_push_lstring(thr, key, key_len);
+ return duk_del_prop(thr, obj_idx);
+}
+
+#if !defined(DUK_USE_PREFER_SIZE)
+DUK_EXTERNAL duk_bool_t duk_del_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(key != NULL);
+ DUK_ASSERT(key[key_len] == (char) 0);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ (void) duk_push_literal_raw(thr, key, key_len);
return duk_del_prop(thr, obj_idx);
}
+#endif
DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
DUK_ASSERT_API_ENTRY(thr);
@@ -16484,7 +16802,7 @@ DUK_EXTERNAL duk_bool_t duk_del_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx
DUK_ASSERT_API_ENTRY(thr);
obj_idx = duk_require_normalize_index(thr, obj_idx);
- duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
return duk_del_prop(thr, obj_idx);
}
@@ -16530,7 +16848,7 @@ DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_hthread *thr, duk_idx_t obj_idx,
DUK_ASSERT(key != NULL);
obj_idx = duk_require_normalize_index(thr, obj_idx);
- duk_push_string(thr, key);
+ (void) duk_push_string(thr, key);
return duk_has_prop(thr, obj_idx);
}
@@ -16539,9 +16857,21 @@ DUK_EXTERNAL duk_bool_t duk_has_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx
DUK_ASSERT(key != NULL);
obj_idx = duk_require_normalize_index(thr, obj_idx);
- duk_push_lstring(thr, key, key_len);
+ (void) duk_push_lstring(thr, key, key_len);
+ return duk_has_prop(thr, obj_idx);
+}
+
+#if !defined(DUK_USE_PREFER_SIZE)
+DUK_EXTERNAL duk_bool_t duk_has_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(key != NULL);
+ DUK_ASSERT(key[key_len] == (char) 0);
+
+ obj_idx = duk_require_normalize_index(thr, obj_idx);
+ (void) duk_push_literal_raw(thr, key, key_len);
return duk_has_prop(thr, obj_idx);
}
+#endif
DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
DUK_ASSERT_API_ENTRY(thr);
@@ -16555,7 +16885,7 @@ DUK_EXTERNAL duk_bool_t duk_has_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx
DUK_ASSERT_API_ENTRY(thr);
obj_idx = duk_require_normalize_index(thr, obj_idx);
- duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
+ (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */
return duk_has_prop(thr, obj_idx);
}
@@ -16755,17 +17085,17 @@ DUK_EXTERNAL void duk_def_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t f
fail_invalid_desc:
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
- return;
+ DUK_WO_NORETURN(return;);
fail_not_callable:
DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
- return;
+ DUK_WO_NORETURN(return;);
}
/*
* Object related
*
- * Note: seal() and freeze() are accessible through Ecmascript bindings,
+ * Note: seal() and freeze() are accessible through ECMAScript bindings,
* and are not exposed through the API.
*/
@@ -16857,6 +17187,7 @@ DUK_INTERNAL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_b
fail_cannot_freeze:
DUK_ERROR_TYPE_INVALID_ARGS(thr); /* XXX: proper error message */
+ DUK_WO_NORETURN(return;);
}
DUK_EXTERNAL void duk_seal(duk_hthread *thr, duk_idx_t obj_idx) {
@@ -16940,6 +17271,38 @@ DUK_EXTERNAL duk_bool_t duk_get_global_lstring(duk_hthread *thr, const char *key
return ret;
}
+#if !defined(DUK_USE_PREFER_SIZE)
+DUK_EXTERNAL duk_bool_t duk_get_global_literal_raw(duk_hthread *thr, const char *key, duk_size_t key_len) {
+ duk_bool_t ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
+ DUK_ASSERT(key[key_len] == (char) 0);
+
+ /* XXX: direct implementation */
+
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ ret = duk_get_prop_literal_raw(thr, -1, key, key_len);
+ duk_remove_m2(thr);
+ return ret;
+}
+#endif
+
+DUK_EXTERNAL duk_bool_t duk_get_global_heapptr(duk_hthread *thr, void *ptr) {
+ duk_bool_t ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
+
+ /* XXX: direct implementation */
+
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ ret = duk_get_prop_heapptr(thr, -1, ptr);
+ duk_remove_m2(thr);
+ return ret;
+}
+
+
DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_hthread *thr, const char *key) {
duk_bool_t ret;
@@ -16970,6 +17333,56 @@ DUK_EXTERNAL duk_bool_t duk_put_global_lstring(duk_hthread *thr, const char *key
return ret;
}
+#if !defined(DUK_USE_PREFER_SIZE)
+DUK_EXTERNAL duk_bool_t duk_put_global_literal_raw(duk_hthread *thr, const char *key, duk_size_t key_len) {
+ duk_bool_t ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
+ DUK_ASSERT(key[key_len] == (char) 0);
+
+ /* XXX: direct implementation */
+
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ duk_insert(thr, -2);
+ ret = duk_put_prop_literal_raw(thr, -2, key, key_len); /* [ ... global val ] -> [ ... global ] */
+ duk_pop(thr);
+ return ret;
+}
+#endif
+
+DUK_EXTERNAL duk_bool_t duk_put_global_heapptr(duk_hthread *thr, void *ptr) {
+ duk_bool_t ret;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
+
+ /* XXX: direct implementation */
+
+ duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
+ duk_insert(thr, -2);
+ ret = duk_put_prop_heapptr(thr, -2, ptr); /* [ ... global val ] -> [ ... global ] */
+ duk_pop(thr);
+ return ret;
+}
+
+/*
+ * ES2015 GetMethod()
+ */
+
+DUK_INTERNAL duk_bool_t duk_get_method_stridx(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t stridx) {
+ (void) duk_get_prop_stridx(thr, idx, stridx);
+ if (duk_is_null_or_undefined(thr, -1)) {
+ duk_pop_nodecref_unsafe(thr);
+ return 0;
+ }
+ if (!duk_is_callable(thr, -1)) {
+ DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
+ DUK_WO_NORETURN(return 0;);
+ }
+ return 1;
+}
+
/*
* Object prototype
*/
@@ -17008,7 +17421,7 @@ DUK_EXTERNAL void duk_set_prototype(duk_hthread *thr, duk_idx_t idx) {
#if defined(DUK_USE_ROM_OBJECTS)
if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); /* XXX: "read only object"? */
- return;
+ DUK_WO_NORETURN(return;);
}
#endif
@@ -17065,15 +17478,26 @@ DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(idx);
DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return;);
}
DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(idx);
DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return;);
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
+ * Random numbers
+ */
+
+/* #include duk_internal.h -> already included */
+
+DUK_EXTERNAL duk_double_t duk_random(duk_hthread *thr) {
+ return (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE(thr);
+}
+/*
* API calls related to general value stack manipulation: resizing the value
* stack, pushing and popping values, type checking and reading values,
* coercing values, etc.
@@ -17247,7 +17671,7 @@ DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_hthread *thr, duk_idx_t idx, duk_int
if (require) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
- /* not reachable */
+ DUK_WO_NORETURN(return 0;);
}
return def_value;
@@ -17298,7 +17722,7 @@ DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_hthread *thr, duk_idx_t idx, duk_u
if (require) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
- /* not reachable */
+ DUK_WO_NORETURN(return 0;);
}
return def_value;
@@ -17373,7 +17797,7 @@ DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_hthread *thr, duk_idx_t i
return (duk_idx_t) uidx;
}
DUK_ERROR_RANGE_INDEX(thr, idx);
- return 0; /* unreachable */
+ DUK_WO_NORETURN(return 0;);
}
DUK_INTERNAL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx) {
@@ -17449,7 +17873,7 @@ DUK_INTERNAL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx) {
return thr->valstack_bottom + uidx;
}
DUK_ERROR_RANGE_INDEX(thr, idx);
- return NULL;
+ DUK_WO_NORETURN(return NULL;);
}
/* Non-critical. */
@@ -17467,7 +17891,7 @@ DUK_EXTERNAL void duk_require_valid_index(duk_hthread *thr, duk_idx_t idx) {
if (DUK_UNLIKELY(duk_normalize_index(thr, idx) < 0)) {
DUK_ERROR_RANGE_INDEX(thr, idx);
- return; /* unreachable */
+ DUK_WO_NORETURN(return;);
}
}
@@ -17492,6 +17916,7 @@ DUK_INTERNAL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_t
ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
if (DUK_UNLIKELY(ret < min_top)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ DUK_WO_NORETURN(return 0;);
}
return ret;
}
@@ -17536,7 +17961,7 @@ DUK_EXTERNAL void duk_set_top(duk_hthread *thr, duk_idx_t idx) {
#else
if (DUK_UNLIKELY(uidx > vs_limit)) {
DUK_ERROR_RANGE_INDEX(thr, idx);
- return; /* unreachable */
+ DUK_WO_NORETURN(return;);
}
#endif
DUK_ASSERT(uidx <= vs_limit);
@@ -17719,7 +18144,7 @@ DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_hthread *thr) {
ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
if (DUK_UNLIKELY(ret < 0)) {
DUK_ERROR_RANGE_INDEX(thr, -1);
- return 0; /* unreachable */
+ DUK_WO_NORETURN(return 0;);
}
return ret;
}
@@ -17920,6 +18345,7 @@ DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_grow(duk_hthread *thr,
*/
if (throw_on_error) {
DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT);
+ DUK_WO_NORETURN(return 0;);
}
return 0;
}
@@ -17927,6 +18353,7 @@ DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_grow(duk_hthread *thr,
if (duk__resize_valstack(thr, new_size) == 0) {
if (throw_on_error) {
DUK_ERROR_ALLOC_FAILED(thr);
+ DUK_WO_NORETURN(return 0;);
}
return 0;
}
@@ -18187,7 +18614,7 @@ DUK_EXTERNAL void duk_dup_top(duk_hthread *thr) {
if (DUK_UNLIKELY(thr->valstack_top - thr->valstack_bottom <= 0)) {
DUK_ERROR_RANGE_INDEX(thr, -1);
- return; /* unreachable */
+ DUK_WO_NORETURN(return;);
}
tv_from = thr->valstack_top - 1;
tv_to = thr->valstack_top++;
@@ -18249,18 +18676,12 @@ DUK_EXTERNAL void duk_insert(duk_hthread *thr, duk_idx_t to_idx) {
DUK_DDD(DUK_DDDPRINT("duk_insert: to_idx=%ld, p=%p, q=%p, nbytes=%lu",
(long) to_idx, (void *) p, (void *) q, (unsigned long) nbytes));
- /* No net refcount changes. */
-
- if (nbytes > 0) {
- DUK_TVAL_SET_TVAL(&tv_tmp, q);
- DUK_ASSERT(nbytes > 0);
- DUK_MEMMOVE((void *) (p + 1), (const void *) p, (size_t) nbytes);
- DUK_TVAL_SET_TVAL(p, &tv_tmp);
- } else {
- /* nop: insert top to top */
- DUK_ASSERT(nbytes == 0);
- DUK_ASSERT(p == q);
- }
+ /* No net refcount changes. No need to special case nbytes == 0
+ * (p == q).
+ */
+ DUK_TVAL_SET_TVAL(&tv_tmp, q);
+ duk_memmove((void *) (p + 1), (const void *) p, (size_t) nbytes);
+ DUK_TVAL_SET_TVAL(p, &tv_tmp);
}
DUK_INTERNAL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx) {
@@ -18352,7 +18773,7 @@ DUK_EXTERNAL void duk_remove(duk_hthread *thr, duk_idx_t idx) {
#endif
nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */
- DUK_MEMMOVE((void *) p, (const void *) (p + 1), (size_t) nbytes); /* zero size not an issue: pointers are valid */
+ duk_memmove((void *) p, (const void *) (p + 1), (size_t) nbytes);
DUK_TVAL_SET_UNDEFINED(q);
thr->valstack_top--;
@@ -18405,7 +18826,7 @@ DUK_INTERNAL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count)
DUK_TVAL_DECREF_NORZ(thr, tv);
}
- DUK_MEMMOVE((void *) tv_dst, (const void *) tv_src, bytes);
+ duk_memmove((void *) tv_dst, (const void *) tv_src, bytes);
tv_newtop = thr->valstack_top - count;
for (tv = tv_newtop; tv < thr->valstack_top; tv++) {
@@ -18444,14 +18865,14 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_hthread *to_thr, duk_hthread *from_thr,
if (DUK_UNLIKELY(to_thr == from_thr)) {
DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT);
- return;
+ DUK_WO_NORETURN(return;);
}
if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) DUK_USE_VALSTACK_LIMIT)) {
/* Maximum value check ensures 'nbytes' won't wrap below.
* Also handles negative count.
*/
DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
- return;
+ DUK_WO_NORETURN(return;);
}
DUK_ASSERT(count >= 0);
@@ -18462,17 +18883,19 @@ DUK_EXTERNAL void duk_xcopymove_raw(duk_hthread *to_thr, duk_hthread *from_thr,
DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end);
if (DUK_UNLIKELY((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes)) {
DUK_ERROR_RANGE_PUSH_BEYOND(to_thr);
+ DUK_WO_NORETURN(return;);
}
src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes);
if (DUK_UNLIKELY(src < (void *) from_thr->valstack_bottom)) {
DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
+ DUK_WO_NORETURN(return;);
}
- /* copy values (no overlap even if to_thr == from_thr; that's not
- * allowed now anyway)
+ /* Copy values (no overlap even if to_thr == from_thr; that's not
+ * allowed now anyway).
*/
DUK_ASSERT(nbytes > 0);
- DUK_MEMCPY((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes);
+ duk_memcpy((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes);
p = to_thr->valstack_top;
to_thr->valstack_top = (duk_tval *) (void *) (((duk_uint8_t *) p) + nbytes);
@@ -18521,7 +18944,7 @@ DUK_INTERNAL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk
tv_dst = (duk_tval *) (void *) ((duk_uint8_t *) tv_src + gap_bytes);
copy_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src);
thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + gap_bytes);
- DUK_MEMMOVE((void *) tv_dst, (const void *) tv_src, copy_bytes);
+ duk_memmove((void *) tv_dst, (const void *) tv_src, copy_bytes);
/* Values in the gap are left as garbage: caller must fill them in
* and INCREF them before any side effects.
@@ -18542,6 +18965,7 @@ DUK_EXTERNAL void duk_require_undefined(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT(tv != NULL);
if (DUK_UNLIKELY(!DUK_TVAL_IS_UNDEFINED(tv))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", DUK_STR_NOT_UNDEFINED);
+ DUK_WO_NORETURN(return;);
}
}
@@ -18554,6 +18978,7 @@ DUK_EXTERNAL void duk_require_null(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT(tv != NULL);
if (DUK_UNLIKELY(!DUK_TVAL_IS_NULL(tv))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL);
+ DUK_WO_NORETURN(return;);
}
}
@@ -18602,6 +19027,7 @@ DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_hthread *thr, duk_idx_t idx) {
return ret;
} else {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN);
+ DUK_WO_NORETURN(return 0;);
}
}
@@ -18663,6 +19089,7 @@ DUK_EXTERNAL duk_double_t duk_require_number(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT(tv != NULL);
if (DUK_UNLIKELY(!DUK_TVAL_IS_NUMBER(tv))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
+ DUK_WO_NORETURN(return 0.0;);
}
ret.d = DUK_TVAL_GET_NUMBER(tv);
@@ -18894,6 +19321,7 @@ DUK_EXTERNAL void duk_require_object(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT(tv != NULL);
if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
+ DUK_WO_NORETURN(return;);
}
}
@@ -18945,6 +19373,7 @@ DUK_EXTERNAL void *duk_require_pointer(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT(tv != NULL);
if (DUK_UNLIKELY(!DUK_TVAL_IS_POINTER(tv))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER);
+ DUK_WO_NORETURN(return NULL;);
}
p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
return p;
@@ -18992,6 +19421,7 @@ DUK_LOCAL void *duk__get_buffer_helper(duk_hthread *thr, duk_idx_t idx, duk_size
} else {
if (throw_flag) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
+ DUK_WO_NORETURN(return NULL;);
}
len = def_size;
ret = def_ptr;
@@ -19095,6 +19525,7 @@ DUK_INTERNAL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_
if (throw_flag) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
+ DUK_WO_NORETURN(return NULL;);
}
return def_ptr;
}
@@ -19174,6 +19605,7 @@ DUK_INTERNAL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx) {
h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
if (DUK_UNLIKELY(h == NULL)) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING);
+ DUK_WO_NORETURN(return NULL;);
}
return h;
}
@@ -19186,6 +19618,7 @@ DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_id
h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
if (DUK_UNLIKELY(h == NULL || DUK_HSTRING_HAS_SYMBOL(h))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING);
+ DUK_WO_NORETURN(return NULL;);
}
return h;
}
@@ -19203,6 +19636,7 @@ DUK_INTERNAL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx) {
h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
if (DUK_UNLIKELY(h == NULL)) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
+ DUK_WO_NORETURN(return NULL;);
}
return h;
}
@@ -19220,6 +19654,7 @@ DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx) {
h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER);
if (DUK_UNLIKELY(h == NULL)) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
+ DUK_WO_NORETURN(return NULL;);
}
return h;
}
@@ -19244,6 +19679,7 @@ DUK_INTERNAL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx) {
h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_THREAD(h)))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread", DUK_STR_NOT_THREAD);
+ DUK_WO_NORETURN(return NULL;);
}
return (duk_hthread *) h;
}
@@ -19268,6 +19704,7 @@ DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t id
h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h)))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC);
+ DUK_WO_NORETURN(return NULL;);
}
return (duk_hcompfunc *) h;
}
@@ -19292,6 +19729,7 @@ DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx)
h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h)))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
+ DUK_WO_NORETURN(return NULL;);
}
return (duk_hnatfunc *) h;
}
@@ -19350,6 +19788,7 @@ DUK_EXTERNAL duk_c_function duk_require_c_function(duk_hthread *thr, duk_idx_t i
ret = duk_get_c_function(thr, idx);
if (DUK_UNLIKELY(!ret)) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
+ DUK_WO_NORETURN(return ret;);
}
return ret;
}
@@ -19358,6 +19797,7 @@ DUK_EXTERNAL void duk_require_function(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT_API_ENTRY(thr);
if (DUK_UNLIKELY(!duk_is_function(thr, idx))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "function", DUK_STR_NOT_FUNCTION);
+ DUK_WO_NORETURN(return;);
}
}
@@ -19369,6 +19809,7 @@ DUK_INTERNAL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx) {
h = duk_require_hobject_accept_mask(thr, idx, DUK_TYPE_MASK_LIGHTFUNC);
if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE);
+ DUK_WO_NORETURN(return;);
}
/* Lightfuncs (h == NULL) are constructable. */
}
@@ -19456,6 +19897,7 @@ DUK_EXTERNAL void *duk_require_heapptr(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT(tv != NULL);
if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE);
+ DUK_WO_NORETURN(return NULL;);
}
ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
@@ -19489,6 +19931,7 @@ DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_hthread *thr, duk_i
if (type_mask & DUK_TYPE_MASK_THROW) {
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
+ DUK_WO_NORETURN(return NULL;);
}
return NULL;
}
@@ -19549,6 +19992,7 @@ DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_i
DUK_UNREF(h_class);
DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE);
+ DUK_WO_NORETURN(return NULL;);
}
return h;
}
@@ -19741,49 +20185,43 @@ DUK_EXTERNAL void duk_to_null(duk_hthread *thr, duk_idx_t idx) {
}
/* E5 Section 9.1 */
-DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) {
- /* inline initializer for coercers[] is not allowed by old compilers like BCC */
+DUK_LOCAL const char * const duk__toprim_hint_strings[3] = {
+ "default", "string", "number"
+};
+DUK_LOCAL void duk__to_primitive_helper(duk_hthread *thr, duk_idx_t idx, duk_int_t hint, duk_bool_t check_symbol) {
+ /* Inline initializer for coercers[] is not allowed by old compilers like BCC. */
duk_small_uint_t coercers[2];
- duk_small_uint_t class_number;
DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING);
idx = duk_require_normalize_index(thr, idx);
+ /* If already primitive, return as is. */
if (!duk_check_type_mask(thr, idx, DUK_TYPE_MASK_OBJECT |
DUK_TYPE_MASK_LIGHTFUNC |
DUK_TYPE_MASK_BUFFER)) {
- /* Any other values stay as is. */
DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */
return;
}
- class_number = duk_get_class_number(thr, idx);
-
- /* XXX: Symbol objects normally coerce via the ES2015-revised ToPrimitive()
- * algorithm which consults value[@@toPrimitive] and avoids calling
- * .valueOf() and .toString(). Before that is implemented, special
- * case Symbol objects to behave as if they had the default @@toPrimitive
- * algorithm of E6 Section 19.4.3.4, i.e. return the plain symbol value
- * with no further side effects.
+ /* @@toPrimitive lookup. Also do for plain buffers and lightfuncs
+ * which mimic objects.
*/
-
- if (class_number == DUK_HOBJECT_CLASS_SYMBOL) {
- duk_hobject *h_obj;
- duk_hstring *h_str;
-
- /* XXX: pretty awkward, index based API for internal value access? */
- h_obj = duk_known_hobject(thr, idx);
- h_str = duk_hobject_get_internal_value_string(thr->heap, h_obj);
- if (h_str) {
- duk_push_hstring(thr, h_str);
- duk_replace(thr, idx);
- return;
+ if (check_symbol && duk_get_method_stridx(thr, idx, DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE)) {
+ DUK_ASSERT(hint >= 0 && (duk_size_t) hint < sizeof(duk__toprim_hint_strings) / sizeof(const char *));
+ duk_dup(thr, idx);
+ duk_push_string(thr, duk__toprim_hint_strings[hint]);
+ duk_call_method(thr, 1); /* [ ... method value hint ] -> [ ... res] */
+ if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT |
+ DUK_TYPE_MASK_LIGHTFUNC |
+ DUK_TYPE_MASK_BUFFER)) {
+ goto fail;
}
+ duk_replace(thr, idx);
+ return;
}
-
/* Objects are coerced based on E5 specification.
* Lightfuncs are coerced because they behave like
* objects even if they're internally a primitive
@@ -19791,17 +20229,29 @@ DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hi
* like ArrayBuffer objects since Duktape 2.x.
*/
- coercers[0] = DUK_STRIDX_VALUE_OF;
- coercers[1] = DUK_STRIDX_TO_STRING;
-
+ /* Hint magic for Date is unnecessary in ES2015 because of
+ * Date.prototype[@@toPrimitive]. However, it is needed if
+ * symbol support is not enabled.
+ */
+#if defined(DUK_USE_SYMBOL_BUILTIN)
+ if (hint == DUK_HINT_NONE) {
+ hint = DUK_HINT_NUMBER;
+ }
+#else /* DUK_USE_SYMBOL_BUILTIN */
if (hint == DUK_HINT_NONE) {
+ duk_small_uint_t class_number;
+
+ class_number = duk_get_class_number(thr, idx);
if (class_number == DUK_HOBJECT_CLASS_DATE) {
hint = DUK_HINT_STRING;
} else {
hint = DUK_HINT_NUMBER;
}
}
+#endif /* DUK_USE_SYMBOL_BUILTIN */
+ coercers[0] = DUK_STRIDX_VALUE_OF;
+ coercers[1] = DUK_STRIDX_TO_STRING;
if (hint == DUK_HINT_STRING) {
coercers[0] = DUK_STRIDX_TO_STRING;
coercers[1] = DUK_STRIDX_VALUE_OF;
@@ -19817,9 +20267,21 @@ DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hi
return;
}
+ fail:
DUK_ERROR_TYPE(thr, DUK_STR_TOPRIMITIVE_FAILED);
+ DUK_WO_NORETURN(return;);
}
+DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) {
+ duk__to_primitive_helper(thr, idx, hint, 1 /*check_symbol*/);
+}
+
+#if defined(DUK_USE_SYMBOL_BUILTIN)
+DUK_INTERNAL void duk_to_primitive_ordinary(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) {
+ duk__to_primitive_helper(thr, idx, hint, 0 /*check_symbol*/);
+}
+#endif
+
/* E5 Section 9.2 */
DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
@@ -19840,6 +20302,22 @@ DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_hthread *thr, duk_idx_t idx) {
return val;
}
+DUK_INTERNAL duk_bool_t duk_to_boolean_top_pop(duk_hthread *thr) {
+ duk_tval *tv;
+ duk_bool_t val;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ tv = duk_require_tval(thr, -1);
+ DUK_ASSERT(tv != NULL);
+
+ val = duk_js_toboolean(tv);
+ DUK_ASSERT(val == 0 || val == 1);
+
+ duk_pop_unsafe(thr);
+ return val;
+}
+
DUK_EXTERNAL duk_double_t duk_to_number(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_double_t d;
@@ -20119,68 +20597,67 @@ DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx) {
#endif
/* Push Object.prototype.toString() output for 'tv'. */
-DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv) {
- duk_small_uint_t stridx;
- duk_hstring *h_strclass;
+#if 0 /* See XXX note why this variant doesn't work. */
+DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects) {
+ duk_uint_t stridx_bidx = 0; /* (prototype_bidx << 16) + default_tag_stridx */
DUK_ASSERT_API_ENTRY(thr);
+ /* Conceptually for any non-undefined/null value we should do a
+ * ToObject() coercion and look up @@toStringTag (from the object
+ * prototype) to see if a custom tag should be used. Avoid the
+ * actual conversion by doing a prototype lookup without the object
+ * coercion. However, see problem below.
+ */
+
+ duk_push_literal(thr, "[object "); /* -> [ ... "[object" ] */
+
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_UNUSED: /* Treat like 'undefined', shouldn't happen. */
case DUK_TAG_UNDEFINED: {
- stridx = DUK_STRIDX_UC_UNDEFINED;
- break;
+ stridx_bidx = DUK_STRIDX_UC_UNDEFINED;
+ goto use_stridx;
}
case DUK_TAG_NULL: {
- stridx = DUK_STRIDX_UC_NULL;
- break;
+ stridx_bidx = DUK_STRIDX_UC_NULL;
+ goto use_stridx;
}
case DUK_TAG_BOOLEAN: {
- stridx = DUK_STRIDX_UC_BOOLEAN;
- break;
+ stridx_bidx = (DUK_BIDX_BOOLEAN_PROTOTYPE << 16) + DUK_STRIDX_UC_BOOLEAN;
+ goto use_proto_bidx;
}
case DUK_TAG_POINTER: {
- stridx = DUK_STRIDX_UC_POINTER;
- break;
+ stridx_bidx = (DUK_BIDX_POINTER_PROTOTYPE << 16) + DUK_STRIDX_UC_POINTER;
+ goto use_proto_bidx;
}
case DUK_TAG_LIGHTFUNC: {
- stridx = DUK_STRIDX_UC_FUNCTION;
- break;
+ stridx_bidx = (DUK_BIDX_FUNCTION_PROTOTYPE << 16) + DUK_STRIDX_UC_FUNCTION;
+ goto use_proto_bidx;
}
case DUK_TAG_STRING: {
duk_hstring *h;
h = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h != NULL);
if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
- stridx = DUK_STRIDX_UC_SYMBOL;
+ /* Even without DUK_USE_SYMBOL_BUILTIN the Symbol
+ * prototype exists so we can lookup @@toStringTag
+ * and provide [object Symbol] for symbol values
+ * created from C code.
+ */
+ stridx_bidx = (DUK_BIDX_SYMBOL_PROTOTYPE << 16) + DUK_STRIDX_UC_SYMBOL;
} else {
- stridx = DUK_STRIDX_UC_STRING;
+ stridx_bidx = (DUK_BIDX_STRING_PROTOTYPE << 16) + DUK_STRIDX_UC_STRING;
}
- break;
+ goto use_proto_bidx;
}
case DUK_TAG_OBJECT: {
- duk_hobject *h;
- duk_small_uint_t classnum;
-
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
- classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h);
- stridx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum);
-
- /* XXX: This is not entirely correct anymore; in ES2015 the
- * default lookup should use @@toStringTag to come up with
- * e.g. [object Symbol], [object Uint8Array], etc. See
- * ES2015 Section 19.1.3.6. The downside of implementing that
- * directly is that the @@toStringTag lookup may have side
- * effects, so all call sites must be checked for that.
- * Some may need a side-effect free lookup, e.g. avoiding
- * getters which are not typical.
- */
- break;
+ duk_push_tval(thr, tv);
+ stridx_bidx = 0xffffffffUL; /* Marker value. */
+ goto use_pushed_object;
}
case DUK_TAG_BUFFER: {
- stridx = DUK_STRIDX_UINT8_ARRAY;
- break;
+ stridx_bidx = (DUK_BIDX_UINT8ARRAY_PROTOTYPE << 16) + DUK_STRIDX_UINT8_ARRAY;
+ goto use_proto_bidx;
}
#if defined(DUK_USE_FASTINT)
case DUK_TAG_FASTINT:
@@ -20188,14 +20665,142 @@ DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv) {
#endif
default: {
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* number (maybe fastint) */
- stridx = DUK_STRIDX_UC_NUMBER;
- break;
+ stridx_bidx = (DUK_BIDX_NUMBER_PROTOTYPE << 16) + DUK_STRIDX_UC_NUMBER;
+ goto use_proto_bidx;
+ }
+ }
+ DUK_ASSERT(0); /* Never here. */
+
+ use_proto_bidx:
+ DUK_ASSERT_BIDX_VALID((stridx_bidx >> 16) & 0xffffUL);
+ duk_push_hobject(thr, thr->builtins[(stridx_bidx >> 16) & 0xffffUL]);
+ /* Fall through. */
+
+ use_pushed_object:
+ /* [ ... "[object" obj ] */
+
+#if defined(DUK_USE_SYMBOL_BUILTIN)
+ /* XXX: better handling with avoid_side_effects == 1; lookup tval
+ * without Proxy or getter side effects, and use it in sanitized
+ * form if it's a string.
+ */
+ if (!avoid_side_effects) {
+ /* XXX: The problem with using the prototype object as the
+ * lookup base is that if @@toStringTag is a getter, its
+ * 'this' binding must be the ToObject() coerced input value,
+ * not the prototype object of the type.
+ */
+ (void) duk_get_prop_stridx(thr, -1, DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG);
+ if (duk_is_string_notsymbol(thr, -1)) {
+ duk_remove_m2(thr);
+ goto finish;
+ }
+ duk_pop_unsafe(thr);
}
+#endif
+
+ if (stridx_bidx == 0xffffffffUL) {
+ duk_hobject *h_obj;
+ duk_small_uint_t classnum;
+
+ h_obj = duk_known_hobject(thr, -1);
+ DUK_ASSERT(h_obj != NULL);
+ classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h_obj);
+ stridx_bidx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum);
+ } else {
+ /* stridx_bidx already has the desired fallback stridx. */
+ ;
+ }
+ duk_pop_unsafe(thr);
+ /* Fall through. */
+
+ use_stridx:
+ /* [ ... "[object" ] */
+ duk_push_hstring_stridx(thr, stridx_bidx & 0xffffUL);
+
+ finish:
+ /* [ ... "[object" tag ] */
+ duk_push_literal(thr, "]");
+ duk_concat(thr, 3); /* [ ... "[object" tag "]" ] -> [ ... res ] */
+}
+#endif /* 0 */
+
+DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects) {
+ duk_hobject *h_obj;
+ duk_small_uint_t classnum;
+ duk_small_uint_t stridx;
+ duk_tval tv_tmp;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(tv != NULL);
+
+ /* Stabilize 'tv', duk_push_literal() may trigger side effects. */
+ DUK_TVAL_SET_TVAL(&tv_tmp, tv);
+ tv = &tv_tmp;
+
+ /* Conceptually for any non-undefined/null value we should do a
+ * ToObject() coercion and look up @@toStringTag (from the object
+ * prototype) to see if a custom result should be used. We'd like to
+ * avoid the actual conversion, but even for primitive types the
+ * prototype may have @@toStringTag. What's worse, the @@toStringTag
+ * property may be a getter that must get the object coerced value
+ * (not the prototype) as its 'this' binding.
+ *
+ * For now, do an actual object coercion. This could be avoided by
+ * doing a side effect free lookup to see if a getter would be invoked.
+ * If not, the value can be read directly and the object coercion could
+ * be avoided. This may not be worth it in practice, because
+ * Object.prototype.toString() is usually not performance critical.
+ */
+
+ duk_push_literal(thr, "[object "); /* -> [ ... "[object" ] */
+
+ switch (DUK_TVAL_GET_TAG(tv)) {
+ case DUK_TAG_UNUSED: /* Treat like 'undefined', shouldn't happen. */
+ case DUK_TAG_UNDEFINED: {
+ duk_push_hstring_stridx(thr, DUK_STRIDX_UC_UNDEFINED);
+ goto finish;
+ }
+ case DUK_TAG_NULL: {
+ duk_push_hstring_stridx(thr, DUK_STRIDX_UC_NULL);
+ goto finish;
+ }
+ }
+
+ duk_push_tval(thr, tv);
+ tv = NULL; /* Invalidated by ToObject(). */
+ duk_to_object(thr, -1);
+
+ /* [ ... "[object" obj ] */
+
+#if defined(DUK_USE_SYMBOL_BUILTIN)
+ /* XXX: better handling with avoid_side_effects == 1; lookup tval
+ * without Proxy or getter side effects, and use it in sanitized
+ * form if it's a string.
+ */
+ if (!avoid_side_effects) {
+ (void) duk_get_prop_stridx(thr, -1, DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG);
+ if (duk_is_string_notsymbol(thr, -1)) {
+ duk_remove_m2(thr);
+ goto finish;
+ }
+ duk_pop_unsafe(thr);
}
- h_strclass = DUK_HTHREAD_GET_STRING(thr, stridx);
- DUK_ASSERT(h_strclass != NULL);
+#else
+ DUK_UNREF(avoid_side_effects);
+#endif
+
+ h_obj = duk_known_hobject(thr, -1);
+ DUK_ASSERT(h_obj != NULL);
+ classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h_obj);
+ stridx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum);
+ duk_pop_unsafe(thr);
+ duk_push_hstring_stridx(thr, stridx);
- duk_push_sprintf(thr, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
+ finish:
+ /* [ ... "[object" tag ] */
+ duk_push_literal(thr, "]");
+ duk_concat(thr, 3); /* [ ... "[object" tag "]" ] -> [ ... res ] */
}
/* XXX: other variants like uint, u32 etc */
@@ -20255,6 +20860,7 @@ DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, d
/* coerced value is updated to value stack even when RangeError thrown */
if (clamped) {
DUK_ERROR_RANGE(thr, DUK_STR_NUMBER_OUTSIDE_RANGE);
+ DUK_WO_NORETURN(return 0;);
}
}
@@ -20312,12 +20918,14 @@ DUK_EXTERNAL const char *duk_to_string(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT(h != NULL);
if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_STRING_COERCE_SYMBOL);
+ DUK_WO_NORETURN(goto skip_replace;);
} else {
goto skip_replace;
}
#else
goto skip_replace;
#endif
+ break;
}
case DUK_TAG_BUFFER: /* Go through Uint8Array.prototype.toString() for coercion. */
case DUK_TAG_OBJECT: {
@@ -20468,14 +21076,9 @@ DUK_EXTERNAL void *duk_to_buffer_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t
}
dst_data = (duk_uint8_t *) duk_push_buffer(thr, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
- if (DUK_LIKELY(src_size > 0)) {
- /* When src_size == 0, src_data may be NULL (if source
- * buffer is dynamic), and dst_data may be NULL (if
- * target buffer is dynamic). Avoid zero-size memcpy()
- * with an invalid pointer.
- */
- DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size);
- }
+ /* dst_data may be NULL if size is zero. */
+ duk_memcpy_unsafe((void *) dst_data, (const void *) src_data, (size_t) src_size);
+
duk_replace(thr, idx);
skip_copy:
@@ -20591,6 +21194,7 @@ DUK_EXTERNAL void duk_to_object(duk_hthread *thr, duk_idx_t idx) {
case DUK_TAG_UNDEFINED:
case DUK_TAG_NULL: {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
+ DUK_WO_NORETURN(return;);
break;
}
case DUK_TAG_BOOLEAN: {
@@ -20898,7 +21502,7 @@ DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_hthread *thr, duk_idx_t idx, duk
}
if (mask & DUK_TYPE_MASK_THROW) {
DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
- DUK_UNREACHABLE();
+ DUK_WO_NORETURN(return 0;);
}
return 0;
}
@@ -21371,21 +21975,22 @@ DUK_EXTERNAL const char *duk_push_lstring(duk_hthread *thr, const char *str, duk
DUK_ASSERT_API_ENTRY(thr);
- /* check stack before interning (avoid hanging temp) */
+ /* Check stack before interning (avoid hanging temp). */
DUK__CHECK_SPACE();
/* NULL with zero length represents an empty string; NULL with higher
- * length is also now trated like an empty string although it is
+ * length is also now treated like an empty string although it is
* a bit dubious. This is unlike duk_push_string() which pushes a
* 'null' if the input string is a NULL.
*/
- if (!str) {
- len = 0;
+ if (DUK_UNLIKELY(str == NULL)) {
+ len = 0U;
}
- /* Check for maximum string length */
+ /* Check for maximum string length. */
if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) {
DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG);
+ DUK_WO_NORETURN(return NULL;);
}
h = duk_heap_strtable_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
@@ -21409,6 +22014,42 @@ DUK_EXTERNAL const char *duk_push_string(duk_hthread *thr, const char *str) {
}
}
+#if !defined(DUK_USE_PREFER_SIZE)
+#if defined(DUK_USE_LITCACHE_SIZE)
+DUK_EXTERNAL const char *duk_push_literal_raw(duk_hthread *thr, const char *str, duk_size_t len) {
+ duk_hstring *h;
+ duk_tval *tv_slot;
+
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(str != NULL);
+ DUK_ASSERT(str[len] == (char) 0);
+
+ /* Check for maximum string length. */
+ if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) {
+ DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG);
+ DUK_WO_NORETURN(return NULL;);
+ }
+
+ h = duk_heap_strtable_intern_literal_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
+ DUK_ASSERT(h != NULL);
+
+ tv_slot = thr->valstack_top++;
+ DUK_TVAL_SET_STRING(tv_slot, h);
+ DUK_HSTRING_INCREF(thr, h); /* no side effects */
+
+ return (const char *) DUK_HSTRING_GET_DATA(h);
+}
+#else /* DUK_USE_LITCACHE_SIZE */
+DUK_EXTERNAL const char *duk_push_literal_raw(duk_hthread *thr, const char *str, duk_size_t len) {
+ DUK_ASSERT_API_ENTRY(thr);
+ DUK_ASSERT(str != NULL);
+ DUK_ASSERT(str[len] == (char) 0);
+
+ return duk_push_lstring(thr, str, len);
+}
+#endif /* DUK_USE_LITCACHE_SIZE */
+#endif /* !DUK_USE_PREFER_SIZE */
+
DUK_EXTERNAL void duk_push_pointer(duk_hthread *thr, void *val) {
duk_tval *tv_slot;
@@ -21462,6 +22103,7 @@ DUK_LOCAL void duk__push_this_helper(duk_hthread *thr, duk_small_uint_t check_ob
type_error:
DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
+ DUK_WO_NORETURN(return;);
}
DUK_EXTERNAL void duk_push_this(duk_hthread *thr) {
@@ -21505,6 +22147,46 @@ DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr) {
return thr->valstack_bottom - 1;
}
+DUK_EXTERNAL void duk_push_new_target(duk_hthread *thr) {
+ duk_activation *act;
+
+ DUK_ASSERT_API_ENTRY(thr);
+
+ /* https://www.ecma-international.org/ecma-262/6.0/#sec-meta-properties-runt...
+ * https://www.ecma-international.org/ecma-262/6.0/#sec-getnewtarget
+ *
+ * No newTarget support now, so as a first approximation
+ * use the resolved (non-bound) target function.
+ *
+ * Check CONSTRUCT flag from current function, or if running
+ * direct eval, from a non-direct-eval parent (with possibly
+ * more than one nested direct eval). An alternative to this
+ * would be to store [[NewTarget]] as a hidden symbol of the
+ * lexical scope, and then just look up that variable.
+ *
+ * Calls from the application will either be for an empty
+ * call stack, or a Duktape/C function as the top activation.
+ */
+
+ act = thr->callstack_curr;
+ for (;;) {
+ if (act == NULL) {
+ break;
+ }
+
+ if (act->flags & DUK_ACT_FLAG_CONSTRUCT) {
+ duk_push_tval(thr, &act->tv_func);
+ return;
+ } else if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
+ act = act->parent;
+ } else {
+ break;
+ }
+ }
+
+ duk_push_undefined(thr);
+}
+
DUK_EXTERNAL void duk_push_current_function(duk_hthread *thr) {
duk_activation *act;
@@ -21565,7 +22247,7 @@ DUK_EXTERNAL void duk_push_thread_stash(duk_hthread *thr, duk_hthread *target_th
DUK_ASSERT_API_ENTRY(thr);
if (DUK_UNLIKELY(target_thr == NULL)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
- return; /* not reached */
+ DUK_WO_NORETURN(return;);
}
duk_push_hobject(thr, (duk_hobject *) target_thr);
duk__push_stash(thr);
@@ -21641,6 +22323,7 @@ DUK_EXTERNAL const char *duk_push_vsprintf(duk_hthread *thr, const char *fmt, va
sz = sz * 2;
if (DUK_UNLIKELY(sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT)) {
DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
+ DUK_WO_NORETURN(return NULL;);
}
}
@@ -21829,6 +22512,7 @@ DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_hthread *thr, duk_uint_t flags) {
/* important to do this *after* pushing, to make the thread reachable for gc */
if (DUK_UNLIKELY(!duk_hthread_init_stacks(thr->heap, obj))) {
DUK_ERROR_ALLOC_FAILED(thr);
+ DUK_WO_NORETURN(return 0;);
}
/* initialize built-ins - either by copying or creating new ones */
@@ -21870,6 +22554,7 @@ DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr) {
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
if (DUK_UNLIKELY(obj == NULL)) {
DUK_ERROR_ALLOC_FAILED(thr);
+ DUK_WO_NORETURN(return NULL;);
}
DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
@@ -21901,6 +22586,7 @@ DUK_INTERNAL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr) {
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
if (!obj) {
DUK_ERROR_ALLOC_FAILED(thr);
+ DUK_WO_NORETURN(return NULL;);
}
tv_slot = thr->valstack_top++;
@@ -21957,7 +22643,7 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function fu
api_error:
DUK_ERROR_TYPE_INVALID_ARGS(thr);
- return 0; /* not reached */
+ DUK_WO_NORETURN(return 0;);
}
DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
@@ -22049,7 +22735,7 @@ DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_hthread *thr, duk_c_function fun
api_error:
DUK_ERROR_TYPE_INVALID_ARGS(thr);
- return 0; /* not reached */
+ DUK_WO_NORETURN(return 0;);
}
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
@@ -22201,11 +22887,11 @@ DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer,
range_error:
DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS);
- return; /* not reached */
+ DUK_WO_NORETURN(return;);
arg_error:
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_ARGS);
- return; /* not reached */
+ DUK_WO_NORETURN(return;);
}
#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
@@ -22215,6 +22901,7 @@ DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer,
DUK_UNREF(byte_length);
DUK_UNREF(flags);
DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return;);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -22252,7 +22939,7 @@ DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_hthread *thr, duk_errcod
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
} else {
/* If no explicit message given, put error code into message field
- * (as a number). This is not fully in keeping with the Ecmascript
+ * (as a number). This is not fully in keeping with the ECMAScript
* error model because messages are supposed to be strings (Error
* constructors use ToString() on their argument). However, it's
* probably more useful than having a separate 'code' property.
@@ -22314,11 +23001,13 @@ DUK_EXTERNAL void *duk_push_buffer_raw(duk_hthread *thr, duk_size_t size, duk_sm
/* Check for maximum buffer length. */
if (DUK_UNLIKELY(size > DUK_HBUFFER_MAX_BYTELEN)) {
DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
+ DUK_WO_NORETURN(return NULL;);
}
h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data);
if (DUK_UNLIKELY(h == NULL)) {
DUK_ERROR_ALLOC_FAILED(thr);
+ DUK_WO_NORETURN(return NULL;);
}
tv_slot = thr->valstack_top;
@@ -22340,11 +23029,12 @@ DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len)
DUK_ASSERT_API_ENTRY(thr);
ptr = duk_push_buffer_raw(thr, len, 0);
+ DUK_ASSERT(ptr != NULL);
#if !defined(DUK_USE_ZERO_BUFFER_DATA)
/* ES2015 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
* is not set.
*/
- DUK_MEMZERO((void *) ptr, (size_t) len);
+ duk_memzero((void *) ptr, (size_t) len);
#endif
return ptr;
}
@@ -22441,12 +23131,14 @@ DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags)
fail_args:
DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ DUK_WO_NORETURN(return 0;);
}
#else /* DUK_USE_ES6_PROXY */
DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) {
DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(proxy_flags);
DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return 0;);
}
#endif /* DUK_USE_ES6_PROXY */
@@ -22744,7 +23436,7 @@ DUK_EXTERNAL void duk_pop_n(duk_hthread *thr, duk_idx_t count) {
if (DUK_UNLIKELY((duk_uidx_t) (thr->valstack_top - thr->valstack_bottom) < (duk_uidx_t) count)) {
DUK_ERROR_RANGE_INVALID_COUNT(thr);
- return;
+ DUK_WO_NORETURN(return;);
}
DUK_ASSERT(count >= 0);
@@ -22832,6 +23524,7 @@ DUK_EXTERNAL void duk_pop(duk_hthread *thr) {
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
DUK_ERROR_RANGE_INVALID_COUNT(thr);
+ DUK_WO_NORETURN(return;);
}
duk__pop_unsafe_raw(thr);
@@ -22920,6 +23613,7 @@ DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) {
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
if (DUK_UNLIKELY(thr->valstack_top - 2 < thr->valstack_bottom)) {
DUK_ERROR_RANGE_INVALID_COUNT(thr);
+ DUK_WO_NORETURN(return;);
}
duk__pop_2_unsafe_raw(thr);
@@ -22977,7 +23671,7 @@ DUK_INTERNAL void duk_pack(duk_hthread *thr, duk_idx_t count) {
if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) top)) {
/* Also handles negative count. */
DUK_ERROR_RANGE_INVALID_COUNT(thr);
- return;
+ DUK_WO_NORETURN(return;);
}
DUK_ASSERT(count >= 0);
@@ -22994,9 +23688,8 @@ DUK_INTERNAL void duk_pack(duk_hthread *thr, duk_idx_t count) {
/* Copy value stack values directly to the array part without
* any refcount updates: net refcount changes are zero.
*/
-
tv_src = thr->valstack_top - count - 1;
- DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval));
+ duk_memcpy_unsafe((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval));
/* Overwrite result array to final value stack location and wipe
* the rest; no refcount operations needed.
@@ -23114,11 +23807,11 @@ DUK_INTERNAL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx) {
}
DUK_ERROR_TYPE_INVALID_ARGS(thr);
- return 0;
+ DUK_WO_NORETURN(return 0;);
fail_over_2g:
DUK_ERROR_RANGE_INVALID_LENGTH(thr);
- return 0;
+ DUK_WO_NORETURN(return 0;);
}
/*
@@ -23135,6 +23828,7 @@ DUK_EXTERNAL void duk_throw_raw(duk_hthread *thr) {
if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ DUK_WO_NORETURN(return;);
}
/* Errors are augmented when they are created, not when they are
@@ -23198,6 +23892,7 @@ DUK_EXTERNAL void duk_error_va_raw(duk_hthread *thr, duk_errcode_t err_code, con
duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
(void) duk_throw(thr);
+ DUK_WO_NORETURN(return;);
}
DUK_EXTERNAL void duk_error_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
@@ -23209,6 +23904,7 @@ DUK_EXTERNAL void duk_error_raw(duk_hthread *thr, duk_errcode_t err_code, const
duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
va_end(ap);
(void) duk_throw(thr);
+ DUK_WO_NORETURN(return;);
}
#if !defined(DUK_USE_VARIADIC_MACROS)
@@ -23227,6 +23923,7 @@ DUK_LOCAL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_c
duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
(void) duk_throw(thr);
+ DUK_WO_NORETURN(return;);
}
#define DUK__ERROR_STASH_SHARED(code) do { \
@@ -23234,7 +23931,7 @@ DUK_LOCAL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_c
va_start(ap, fmt); \
duk__throw_error_from_stash(thr, (code), fmt, ap); \
va_end(ap); \
- /* Never reached; if return 0 here, gcc/clang will complain. */ \
+ DUK_WO_NORETURN(return 0;); \
} while (0)
DUK_EXTERNAL duk_ret_t duk_error_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) {
@@ -23364,7 +24061,7 @@ DUK_INTERNAL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function f
DUK_ASSERT_API_ENTRY(thr);
- duk_push_sprintf(thr, "light_");
+ duk_push_literal(thr, "light_");
duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func));
duk_push_sprintf(thr, "_%04x", (unsigned int) lf_flags);
duk_concat(thr, 3);
@@ -23389,9 +24086,9 @@ DUK_INTERNAL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv) {
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); /* read before 'tv' potentially invalidated */
- duk_push_string(thr, "function ");
+ duk_push_literal(thr, "function ");
duk_push_lightfunc_name_raw(thr, func, lf_flags);
- duk_push_string(thr, "() { [lightfunc code] }");
+ duk_push_literal(thr, "() { [lightfunc code] }");
duk_concat(thr, 3);
}
@@ -23503,7 +24200,7 @@ DUK_LOCAL const char *duk__push_string_tval_readable(duk_hthread *thr, duk_tval
/* 'tv' may be NULL */
if (tv == NULL) {
- duk_push_string(thr, "none");
+ duk_push_literal(thr, "none");
} else {
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_STRING: {
@@ -23512,11 +24209,11 @@ DUK_LOCAL const char *duk__push_string_tval_readable(duk_hthread *thr, duk_tval
/* XXX: string summary produces question marks
* so this is not very ideal.
*/
- duk_push_string(thr, "[Symbol ");
+ duk_push_literal(thr, "[Symbol ");
duk_push_string(thr, duk__get_symbol_type_string(h));
- duk_push_string(thr, " ");
+ duk_push_literal(thr, " ");
duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS);
- duk_push_string(thr, "]");
+ duk_push_literal(thr, "]");
duk_concat(thr, 5);
break;
}
@@ -23546,7 +24243,7 @@ DUK_LOCAL const char *duk__push_string_tval_readable(duk_hthread *thr, duk_tval
break;
}
}
- duk_push_class_string_tval(thr, tv);
+ duk_push_class_string_tval(thr, tv, 1 /*avoid_side_effects*/);
break;
}
case DUK_TAG_BUFFER: {
@@ -23601,7 +24298,7 @@ DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstri
DUK_ASSERT_API_ENTRY(thr);
/* .toString() */
- duk_push_string(thr, "Symbol(");
+ duk_push_literal(thr, "Symbol(");
p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
p_end = p + DUK_HSTRING_GET_BYTELEN(h);
DUK_ASSERT(p[0] == 0xff || (p[0] & 0xc0) == 0x80);
@@ -23617,7 +24314,7 @@ DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstri
}
}
duk_push_lstring(thr, (const char *) p, (duk_size_t) (q - p));
- duk_push_string(thr, ")");
+ duk_push_literal(thr, ")");
duk_concat(thr, 3);
}
@@ -23653,7 +24350,8 @@ DUK_INTERNAL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_
DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(thr);
DUK_ASSERT(count * sizeof(duk_tval) >= count); /* no wrap */
- DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, count * sizeof(duk_tval));
+
+ duk_memcpy_unsafe((void *) tv_dst, (const void *) tv_src, count * sizeof(duk_tval));
tv = tv_dst;
while (count-- > 0) {
@@ -23689,7 +24387,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in,
if (DUK_UNLIKELY(count_in <= 0)) {
if (count_in < 0) {
DUK_ERROR_RANGE_INVALID_COUNT(thr);
- return;
+ DUK_WO_NORETURN(return;);
}
DUK_ASSERT(count_in == 0);
duk_push_hstring_empty(thr);
@@ -23745,11 +24443,11 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in,
for (i = count; i >= 1; i--) {
if (is_join && i != count) {
h = duk_require_hstring(thr, -((duk_idx_t) count) - 2); /* extra -1 for buffer */
- DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
+ duk_memcpy(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
idx += DUK_HSTRING_GET_BYTELEN(h);
}
h = duk_require_hstring(thr, -((duk_idx_t) i) - 1); /* extra -1 for buffer */
- DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
+ duk_memcpy(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
idx += DUK_HSTRING_GET_BYTELEN(h);
}
@@ -23776,6 +24474,7 @@ DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in,
error_overflow:
DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
+ DUK_WO_NORETURN(return;);
}
DUK_EXTERNAL void duk_concat(duk_hthread *thr, duk_idx_t count) {
@@ -23813,8 +24512,8 @@ DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len);
DUK_ASSERT(buf != NULL);
- DUK_MEMCPY((void *) buf, (const void *) DUK_HSTRING_GET_DATA(h1), (size_t) len1);
- DUK_MEMCPY((void *) (buf + len1), (const void *) DUK_HSTRING_GET_DATA(h2), (size_t) len2);
+ duk_memcpy((void *) buf, (const void *) DUK_HSTRING_GET_DATA(h1), (size_t) len1);
+ duk_memcpy((void *) (buf + len1), (const void *) DUK_HSTRING_GET_DATA(h2), (size_t) len2);
(void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
/* [ ... str1 str2 buf ] */
@@ -23825,6 +24524,7 @@ DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
error_overflow:
DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
+ DUK_WO_NORETURN(return;);
}
#endif /* DUK_USE_PREFER_SIZE */
@@ -24053,7 +24753,7 @@ DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_hthread *thr, duk_idx_t idx, d
/* #include duk_internal.h -> already included */
DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) {
- /* Ecmascript time, with millisecond fractions. Exposed via
+ /* ECMAScript time, with millisecond fractions. Exposed via
* duk_get_now() for example.
*/
DUK_UNREF(thr);
@@ -24061,7 +24761,7 @@ DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) {
}
DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr) {
- /* Ecmascript time without millisecond fractions. Exposed via
+ /* ECMAScript time without millisecond fractions. Exposed via
* the Date built-in which doesn't allow fractions.
*/
DUK_UNREF(thr);
@@ -24104,7 +24804,7 @@ DUK_EXTERNAL void duk_time_to_components(duk_hthread *thr, duk_double_t timeval,
DUK_UNREF(thr);
/* Convert as one-based, but change month to zero-based to match the
- * Ecmascript Date built-in behavior 1:1.
+ * ECMAScript Date built-in behavior 1:1.
*/
flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO;
@@ -24159,9 +24859,9 @@ DUK_EXTERNAL duk_double_t duk_components_to_time(duk_hthread *thr, duk_time_comp
/*
* Array built-ins
*
- * Most Array built-ins are intentionally generic in Ecmascript, and are
+ * Most Array built-ins are intentionally generic in ECMAScript, and are
* intended to work even when the 'this' binding is not an Array instance.
- * This Ecmascript feature is also used by much real world code. For this
+ * This ECMAScript feature is also used by much real world code. For this
* reason the implementations here don't assume exotic Array behavior or
* e.g. presence of a .length property. However, some algorithms have a
* fast path for duk_harray backed actual Array instances, enabled when
@@ -24235,6 +24935,7 @@ DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_hthread *thr) {
duk_uint32_t ret = duk__push_this_obj_len_u32(thr);
if (DUK_UNLIKELY(ret >= 0x80000000UL)) {
DUK_ERROR_RANGE_INVALID_LENGTH(thr);
+ DUK_WO_NORETURN(return 0U;);
}
return ret;
}
@@ -24387,11 +25088,17 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_hthread *thr) {
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_hthread *thr) {
duk_idx_t i, n;
- duk_uarridx_t idx, idx_last;
- duk_uarridx_t j, len;
+ duk_uint32_t j, idx, len;
duk_hobject *h;
+ duk_size_t tmp_len;
+
+ /* XXX: In ES2015 Array .length can be up to 2^53-1. The current
+ * implementation is limited to 2^32-1.
+ */
- /* XXX: the insert here is a bit expensive if there are a lot of items.
+ /* XXX: Fast path for array 'this' and array element. */
+
+ /* XXX: The insert here is a bit expensive if there are a lot of items.
* It could also be special cased in the outermost for loop quite easily
* (as the element is dup()'d anyway).
*/
@@ -24409,59 +25116,97 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_hthread *thr) {
*/
idx = 0;
- idx_last = 0;
for (i = 0; i < n; i++) {
+ duk_bool_t spreadable;
+ duk_bool_t need_has_check;
+
DUK_ASSERT_TOP(thr, n + 1);
/* [ ToObject(this) item1 ... itemN arr ] */
- duk_dup(thr, i);
- h = duk_get_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_ARRAY);
- if (!h) {
- duk_xdef_prop_index_wec(thr, -2, idx++);
- idx_last = idx;
+ h = duk_get_hobject(thr, i);
+
+ if (h == NULL) {
+ spreadable = 0;
+ } else {
+#if defined(DUK_USE_SYMBOL_BUILTIN)
+ duk_get_prop_stridx(thr, i, DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE);
+ if (duk_is_undefined(thr, -1)) {
+ spreadable = (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY);
+ } else {
+ spreadable = duk_to_boolean(thr, -1);
+ }
+ duk_pop_nodecref_unsafe(thr);
+#else
+ spreadable = (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY);
+#endif
+ }
+
+ if (!spreadable) {
+ duk_dup(thr, i);
+ duk_xdef_prop_index_wec(thr, -2, idx);
+ idx++;
+ if (DUK_UNLIKELY(idx == 0U)) {
+ /* Index after update is 0, and index written
+ * was 0xffffffffUL which is no longer a valid
+ * array index.
+ */
+ goto fail_wrap;
+ }
continue;
}
- /* [ ToObject(this) item1 ... itemN arr item(i) ] */
+ DUK_ASSERT(duk_is_object(thr, i));
+ need_has_check = (DUK_HOBJECT_IS_PROXY(h) != 0); /* Always 0 w/o Proxy support. */
- /* XXX: an array can have length higher than 32 bits; this is not handled
- * correctly now.
- */
- len = (duk_uarridx_t) duk_get_length(thr, -1);
+ /* [ ToObject(this) item1 ... itemN arr ] */
+
+ tmp_len = duk_get_length(thr, i);
+ len = (duk_uint32_t) tmp_len;
+ if (DUK_UNLIKELY(tmp_len != (duk_size_t) len)) {
+ goto fail_wrap;
+ }
+ if (DUK_UNLIKELY(idx + len < idx)) {
+ /* Result length must be at most 0xffffffffUL to be
+ * a valid 32-bit array index.
+ */
+ goto fail_wrap;
+ }
for (j = 0; j < len; j++) {
- if (duk_get_prop_index(thr, -1, j)) {
- /* [ ToObject(this) item1 ... itemN arr item(i) item(i)[j] ] */
- duk_xdef_prop_index_wec(thr, -3, idx++);
- idx_last = idx;
+ /* For a Proxy element, an explicit 'has' check is
+ * needed to allow the Proxy to present gaps.
+ */
+ if (need_has_check) {
+ if (duk_has_prop_index(thr, i, j)) {
+ duk_get_prop_index(thr, i, j);
+ duk_xdef_prop_index_wec(thr, -2, idx);
+ }
} else {
- idx++;
- duk_pop_undefined(thr);
-#if defined(DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER)
- /* According to E5.1 Section 15.4.4.4 nonexistent trailing
- * elements do not affect 'length' of the result. Test262
- * and other engines disagree, so update idx_last here too.
- */
- idx_last = idx;
-#else
- /* Strict standard behavior, ignore trailing elements for
- * result 'length'.
- */
-#endif
+ if (duk_get_prop_index(thr, i, j)) {
+ duk_xdef_prop_index_wec(thr, -2, idx);
+ } else {
+ duk_pop_undefined(thr);
+ }
}
+ idx++;
+ DUK_ASSERT(idx != 0U); /* Wrap check above. */
}
- duk_pop_unsafe(thr);
}
- /* The E5.1 Section 15.4.4.4 algorithm doesn't set the length explicitly
- * in the end, but because we're operating with an internal value which
- * is known to be an array, this should be equivalent.
+ /* ES5.1 has a specification "bug" in that nonexistent trailing
+ * elements don't affect the result .length. Test262 and other
+ * engines disagree, and the specification bug was fixed in ES2015
+ * (see NOTE 1 in https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.concat).
*/
- duk_push_uarridx(thr, idx_last);
+ duk_push_uarridx(thr, idx);
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
DUK_ASSERT_TOP(thr, n + 1);
return 1;
+
+ fail_wrap:
+ DUK_ERROR_RANGE_INVALID_LENGTH(thr);
+ DUK_WO_NORETURN(return 0;);
}
/*
@@ -25583,20 +26328,12 @@ DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_hthread *thr) {
DUK_ASSERT_TOP(thr, 5);
if (!duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
-#if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER)
- /* Real world behavior for map(): trailing non-existent
- * elements don't invoke the user callback, but are still
- * counted towards result 'length'.
+ /* For 'map' trailing missing elements don't invoke the
+ * callback but count towards the result length.
*/
if (iter_type == DUK__ITER_MAP) {
res_length = i + 1;
}
-#else
- /* Standard behavior for map(): trailing non-existent
- * elements don't invoke the user callback and are not
- * counted towards result 'length'.
- */
-#endif
duk_pop_undefined(thr);
continue;
}
@@ -26021,6 +26758,7 @@ DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_hthread *thr, duk_small_u
if (flags & DUK__BUFOBJ_FLAG_THROW) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
+ DUK_WO_NORETURN(return NULL;);
}
return NULL;
}
@@ -26062,7 +26800,7 @@ DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_hthread *thr, duk_idx_t idx
}
DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
- return NULL; /* not reachable */
+ DUK_WO_NORETURN(return NULL;);
}
DUK_LOCAL void duk__set_bufobj_buffer(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_hbuffer *h_val) {
@@ -26137,6 +26875,7 @@ DUK_LOCAL void duk__resolve_offset_opt_length(duk_hthread *thr,
fail_range:
DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS);
+ DUK_WO_NORETURN(return;);
}
/* Shared lenient buffer length clamping helper. No negative indices, no
@@ -26287,7 +27026,8 @@ DUK_INTERNAL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_h
DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
duk_double_union du;
- DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size);
+ DUK_ASSERT(elem_size > 0);
+ duk_memcpy((void *) du.uc, (const void *) p, (size_t) elem_size);
switch (h_bufobj->elem_type) {
case DUK_HBUFOBJ_ELEM_UINT8:
@@ -26355,7 +27095,11 @@ DUK_INTERNAL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_b
du.ui[0] = (duk_uint32_t) duk_to_int32(thr, -1);
break;
case DUK_HBUFOBJ_ELEM_FLOAT32:
- du.f[0] = (duk_float_t) duk_to_number_m1(thr);
+ /* A double-to-float cast is undefined behavior in C99 if
+ * the cast is out-of-range, so use a helper. Example:
+ * runtime error: value -1e+100 is outside the range of representable values of type 'float'
+ */
+ du.f[0] = duk_double_to_float_t(duk_to_number_m1(thr));
break;
case DUK_HBUFOBJ_ELEM_FLOAT64:
du.d = (duk_double_t) duk_to_number_m1(thr);
@@ -26364,7 +27108,8 @@ DUK_INTERNAL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_b
DUK_UNREACHABLE();
}
- DUK_MEMCPY((void *) p, (const void *) du.uc, (size_t) elem_size);
+ DUK_ASSERT(elem_size > 0);
+ duk_memcpy((void *) p, (const void *) du.uc, (size_t) elem_size);
}
/* Helper to create a fixed buffer from argument value at index 0.
@@ -26400,12 +27145,14 @@ DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_hthread *thr) {
h_bufobj = (duk_hbufobj *) h;
if (DUK_UNLIKELY(h_bufobj->buf == NULL)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ DUK_WO_NORETURN(return NULL;);
}
if (DUK_UNLIKELY(h_bufobj->offset != 0 || h_bufobj->length != DUK_HBUFFER_GET_SIZE(h_bufobj->buf))) {
/* No support for ArrayBuffers with slice
* offset/length.
*/
DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ DUK_WO_NORETURN(return NULL;);
}
duk_push_hbuffer(thr, h_bufobj->buf);
return h_bufobj->buf;
@@ -26421,6 +27168,7 @@ DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_hthread *thr) {
}
default:
DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ DUK_WO_NORETURN(return NULL;);
}
done:
@@ -26462,7 +27210,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_hthread *thr) {
duk_push_buffer_object(thr,
-1,
0,
- DUK_HBUFFER_FIXED_GET_SIZE((duk_hbuffer_fixed *) h_buf),
+ DUK_HBUFFER_FIXED_GET_SIZE((duk_hbuffer_fixed *) (void *) h_buf),
DUK_BUFOBJ_UINT8ARRAY);
duk_push_hobject_bidx(thr, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
duk_set_prototype(thr, -2);
@@ -26790,7 +27538,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) {
DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld",
(void *) p_src, (void *) p_dst, (long) byte_length));
- DUK_MEMCPY((void *) p_dst, (const void *) p_src, (size_t) byte_length);
+ duk_memcpy_unsafe((void *) p_dst, (const void *) p_src, (size_t) byte_length);
break;
}
case 1: {
@@ -27026,7 +27774,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_hthread *thr) {
h_this = duk__get_bufobj_this(thr);
if (h_this == NULL) {
/* XXX: happens e.g. when evaluating: String(Buffer.prototype). */
- duk_push_string(thr, "[object Object]");
+ duk_push_literal(thr, "[object Object]");
return 1;
}
DUK_ASSERT_HBUFOBJ_VALID(h_this);
@@ -27057,9 +27805,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_hthread *thr) {
*/
DUK_ASSERT(DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length));
- DUK_MEMCPY((void *) buf_slice,
- (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
- (size_t) slice_length);
+ duk_memcpy_unsafe((void *) buf_slice,
+ (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
+ (size_t) slice_length);
/* Use the equivalent of: new TextEncoder().encode(this) to convert the
* string. Result will be valid UTF-8; non-CESU-8 inputs are currently
@@ -27221,7 +27969,7 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_hthread *thr) {
/* Handle single character fills as memset() even when
* the fill data comes from a one-char argument.
*/
- DUK_MEMSET((void *) p, (int) fill_str_ptr[0], (size_t) fill_length);
+ duk_memset_unsafe((void *) p, (int) fill_str_ptr[0], (size_t) fill_length);
} else if (fill_str_len > 1) {
duk_size_t i, n, t;
@@ -27272,9 +28020,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_hthread *thr) {
if (DUK_HBUFOBJ_VALID_SLICE(h_this)) {
/* Cannot overlap. */
- DUK_MEMCPY((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset),
- (const void *) str_data,
- (size_t) length);
+ duk_memcpy_unsafe((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset),
+ (const void *) str_data,
+ (size_t) length);
} else {
DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore"));
}
@@ -27370,9 +28118,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_hthread *thr) {
/* Must use memmove() because copy area may overlap (source and target
* buffer may be the same, or from different slices.
*/
- DUK_MEMMOVE((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
- (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
- (size_t) copy_size);
+ duk_memmove_unsafe((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
+ (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
+ (size_t) copy_size);
} else {
DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring"));
}
@@ -27558,7 +28306,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_hthread *thr) {
DUK_ASSERT(src_length == dst_length);
DUK_DDD(DUK_DDDPRINT("fast path: able to use memmove() because views are compatible"));
- DUK_MEMMOVE((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length);
+ duk_memmove_unsafe((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length);
return 0;
}
DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item"));
@@ -27601,7 +28349,7 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_hthread *thr) {
DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source"));
p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_length);
DUK_ASSERT(p_src_copy != NULL);
- DUK_MEMCPY((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length);
+ duk_memcpy_unsafe((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length);
p_src_base = p_src_copy; /* use p_src_base from now on */
}
@@ -27728,9 +28476,9 @@ DUK_LOCAL void duk__arraybuffer_plain_slice(duk_hthread *thr, duk_hbuffer *h_val
DUK_ASSERT(p_copy != NULL);
copy_length = slice_length;
- DUK_MEMCPY((void *) p_copy,
- (const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset),
- copy_length);
+ duk_memcpy_unsafe((void *) p_copy,
+ (const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset),
+ copy_length);
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
@@ -27852,9 +28600,9 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_hthread *thr) {
* is left as zero.
*/
copy_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, slice_length);
- DUK_MEMCPY((void *) p_copy,
- (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
- copy_length);
+ duk_memcpy_unsafe((void *) p_copy,
+ (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
+ copy_length);
h_val = duk_known_hbuffer(thr, -1);
@@ -28046,9 +28794,9 @@ DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_hthread *thr) {
if (h_bufobj->buf != NULL &&
DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
- DUK_MEMCPY((void *) p,
- (const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj),
- copy_size);
+ duk_memcpy_unsafe((void *) p,
+ (const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj),
+ copy_size);
} else {
/* Just skip, leaving zeroes in the result. */
;
@@ -28198,7 +28946,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) {
if (offset + 2U > check_length) {
goto fail_bounds;
}
- DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 2);
+ duk_memcpy((void *) du.uc, (const void *) (buf + offset), 2);
tmp = du.us[0];
if (endswap) {
tmp = DUK_BSWAP16(tmp);
@@ -28215,7 +28963,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) {
if (offset + 4U > check_length) {
goto fail_bounds;
}
- DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4);
+ duk_memcpy((void *) du.uc, (const void *) (buf + offset), 4);
tmp = du.ui[0];
if (endswap) {
tmp = DUK_BSWAP32(tmp);
@@ -28232,7 +28980,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) {
if (offset + 4U > check_length) {
goto fail_bounds;
}
- DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4);
+ duk_memcpy((void *) du.uc, (const void *) (buf + offset), 4);
if (endswap) {
tmp = du.ui[0];
tmp = DUK_BSWAP32(tmp);
@@ -28245,7 +28993,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) {
if (offset + 8U > check_length) {
goto fail_bounds;
}
- DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 8);
+ duk_memcpy((void *) du.uc, (const void *) (buf + offset), 8);
if (endswap) {
DUK_DBLUNION_BSWAP64(&du);
}
@@ -28302,9 +29050,12 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) {
} while (i != i_end);
if (magic_signed) {
- /* Shift to sign extend. */
+ /* Shift to sign extend. Left shift must be unsigned
+ * to avoid undefined behavior; right shift must be
+ * signed to sign extend properly.
+ */
shift_tmp = (duk_small_uint_t) (64U - (duk_small_uint_t) field_bytelen * 8U);
- tmp = (tmp << shift_tmp) >> shift_tmp;
+ tmp = (duk_int64_t) ((duk_uint64_t) tmp << shift_tmp) >> shift_tmp;
}
duk_push_i64(thr, tmp);
@@ -28480,7 +29231,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) {
}
du.us[0] = tmp;
/* sign doesn't matter when writing */
- DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 2);
+ duk_memcpy((void *) (buf + offset), (const void *) du.uc, 2);
break;
}
case DUK__FLD_32BIT: {
@@ -28494,7 +29245,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) {
}
du.ui[0] = tmp;
/* sign doesn't matter when writing */
- DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4);
+ duk_memcpy((void *) (buf + offset), (const void *) du.uc, 4);
break;
}
case DUK__FLD_FLOAT: {
@@ -28509,7 +29260,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) {
du.ui[0] = tmp;
}
/* sign doesn't matter when writing */
- DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4);
+ duk_memcpy((void *) (buf + offset), (const void *) du.uc, 4);
break;
}
case DUK__FLD_DOUBLE: {
@@ -28521,7 +29272,7 @@ DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) {
DUK_DBLUNION_BSWAP64(&du);
}
/* sign doesn't matter when writing */
- DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 8);
+ duk_memcpy((void *) (buf + offset), (const void *) du.uc, 8);
break;
}
case DUK__FLD_VARINT: {
@@ -28967,7 +29718,7 @@ DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_hthread *thr, const ch
duk_small_uint_t i;
/* During parsing, month and day are one-based; set defaults here. */
- DUK_MEMZERO(parts, sizeof(parts));
+ duk_memzero(parts, sizeof(parts));
DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] == 0); /* don't care value, year is mandatory */
parts[DUK_DATE_IDX_MONTH] = 1;
parts[DUK_DATE_IDX_DAY] = 1;
@@ -29194,13 +29945,13 @@ DUK_LOCAL duk_uint8_t duk__days_in_month[12] = {
};
/* Maximum iteration count for computing UTC-to-local time offset when
- * creating an Ecmascript time value from local parts.
+ * creating an ECMAScript time value from local parts.
*/
#define DUK__LOCAL_TZOFFSET_MAXITER 4
/* Because 'day since epoch' can be negative and is used to compute weekday
* using a modulo operation, add this multiple of 7 to avoid negative values
- * when year is below 1970 epoch. Ecmascript time values are restricted to
+ * when year is below 1970 epoch. ECMAScript time values are restricted to
* +/- 100 million days from epoch, so this adder fits nicely into 32 bits.
* Round to a multiple of 7 (= floor(100000000 / 7) * 7) and add margin.
*/
@@ -29391,10 +30142,10 @@ DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts,
d = DUK_FLOOR(d); /* remove fractions if present */
DUK_ASSERT(DUK_FLOOR(d) == d);
- /* The timevalue must be in valid Ecmascript range, but since a local
+ /* The timevalue must be in valid ECMAScript range, but since a local
* time offset can be applied, we need to allow a +/- 24h leeway to
* the value. In other words, although the UTC time is within the
- * Ecmascript range, the local part values can be just outside of it.
+ * ECMAScript range, the local part values can be just outside of it.
*/
DUK_UNREF(duk_bi_date_timeval_in_leeway_range);
DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d));
@@ -29437,7 +30188,7 @@ DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts,
(long) parts[DUK_DATE_IDX_MILLISECOND]));
/* This assert depends on the input parts representing time inside
- * the Ecmascript range.
+ * the ECMAScript range.
*/
DUK_ASSERT(t2 + DUK__WEEKDAY_MOD_ADDER >= 0);
parts[DUK_DATE_IDX_WEEKDAY] = (t2 + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */
@@ -29557,7 +30308,7 @@ DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dpar
* computation happens with intermediate results coerced to
* double values (instead of using something more accurate).
* E.g. E5.1 Section 15.9.1.11 requires use of IEEE 754
- * rules (= Ecmascript '+' and '*' operators).
+ * rules (= ECMAScript '+' and '*' operators).
*
* Without 'volatile' even this approach fails on some platform
* and compiler combinations. For instance, gcc 4.8.1 on Ubuntu
@@ -29664,6 +30415,7 @@ DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk
h = duk_get_hobject(thr, -1); /* XXX: getter with class check, useful in built-ins */
if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) {
DUK_ERROR_TYPE(thr, "expected Date");
+ DUK_WO_NORETURN(return 0.0;);
}
duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
@@ -29676,6 +30428,7 @@ DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk
}
if (flags & DUK_DATE_FLAG_NAN_TO_RANGE_ERROR) {
DUK_ERROR_RANGE(thr, "Invalid Date");
+ DUK_WO_NORETURN(return 0.0;);
}
}
/* if no NaN handling flag, may still be NaN here, but not Inf */
@@ -30292,7 +31045,7 @@ DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_hthread *thr) {
* Notes:
*
* - Date.prototype.toGMTString() and Date.prototype.toUTCString() are
- * required to be the same Ecmascript function object (!), so it is
+ * required to be the same ECMAScript function object (!), so it is
* omitted from here.
*
* - Date.prototype.toUTCString(): E5.1 specification does not require a
@@ -30488,6 +31241,41 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_hthread *thr) {
return 1;
}
+/*
+ * Misc.
+ */
+
+#if defined(DUK_USE_SYMBOL_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_date_prototype_toprimitive(duk_hthread *thr) {
+ duk_size_t hintlen;
+ const char *hintstr;
+ duk_int_t hint;
+
+ /* Invokes OrdinaryToPrimitive() with suitable hint. Note that the
+ * method is generic, and works on non-Date arguments too.
+ *
+ * https://www.ecma-international.org/ecma-262/6.0/#sec-date.prototype-@@top...
+ */
+
+ duk_push_this(thr);
+ duk_require_object(thr, -1);
+ DUK_ASSERT_TOP(thr, 2);
+
+ hintstr = duk_require_lstring(thr, 0, &hintlen);
+ if ((hintlen == 6 && DUK_STRCMP(hintstr, "string") == 0) ||
+ (hintlen == 7 && DUK_STRCMP(hintstr, "default") == 0)) {
+ hint = DUK_HINT_STRING;
+ } else if (hintlen == 6 && DUK_STRCMP(hintstr, "number") == 0) {
+ hint = DUK_HINT_NUMBER;
+ } else {
+ DUK_DCERROR_TYPE_INVALID_ARGS(thr);
+ }
+
+ duk_to_primitive_ordinary(thr, -1, hint);
+ return 1;
+}
+#endif /* DUK_USE_SYMBOL_BUILTIN */
+
#endif /* DUK_USE_DATE_BUILTIN */
/* automatic undefs */
@@ -30555,7 +31343,7 @@ DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_hthread *thr) {
#define DUK__STRFTIME_BUF_SIZE 64
#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
-/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */
+/* Get current ECMAScript time (= UNIX/Posix time, but in milliseconds). */
DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(void) {
struct timeval tv;
duk_double_t d;
@@ -30603,7 +31391,7 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
return 0;
}
- /* If not within Ecmascript range, some integer time calculations
+ /* If not within ECMAScript range, some integer time calculations
* won't work correctly (and some asserts will fail), so bail out
* if so. This fixes test-bug-date-insane-setyear.js. There is
* a +/- 24h leeway in this range check to avoid a test262 corner
@@ -30654,10 +31442,10 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
* Since we rely on the platform APIs for conversions between local
* time and UTC, we can't guarantee the above. Rather, if the platform
* has historical DST rules they will be applied. This seems to be the
- * general preferred direction in Ecmascript standardization (or at least
+ * general preferred direction in ECMAScript standardization (or at least
* implementations) anyway, and even the equivalent year mapping should
* be disabled if the platform is known to handle DST properly for the
- * full Ecmascript range.
+ * full ECMAScript range.
*
* The following has useful discussion and links:
*
@@ -30672,7 +31460,7 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
t = (time_t) (d / 1000.0);
DUK_DDD(DUK_DDDPRINT("timeval: %lf -> time_t %ld", (double) d, (long) t));
- DUK_MEMZERO((void *) tms, sizeof(struct tm) * 2);
+ duk_memzero((void *) tms, sizeof(struct tm) * 2);
#if defined(DUK_USE_DATE_TZO_GMTIME_R)
(void) gmtime_r(&t, &tms[0]);
@@ -30682,9 +31470,9 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
(void) localtime_s(&t, &tms[1]);
#elif defined(DUK_USE_DATE_TZO_GMTIME)
tm_ptr = gmtime(&t);
- DUK_MEMCPY((void *) &tms[0], tm_ptr, sizeof(struct tm));
+ duk_memcpy((void *) &tms[0], tm_ptr, sizeof(struct tm));
tm_ptr = localtime(&t);
- DUK_MEMCPY((void *) &tms[1], tm_ptr, sizeof(struct tm));
+ duk_memcpy((void *) &tms[1], tm_ptr, sizeof(struct tm));
#else
#error internal error
#endif
@@ -30745,13 +31533,13 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, cons
/* Copy to buffer with slack to avoid Valgrind gripes from strptime. */
DUK_ASSERT(str != NULL);
- DUK_MEMZERO(buf, sizeof(buf)); /* valgrind whine without this */
+ duk_memzero(buf, sizeof(buf)); /* valgrind whine without this */
DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str);
buf[sizeof(buf) - 1] = (char) 0;
DUK_DDD(DUK_DDDPRINT("parsing: '%s'", (const char *) buf));
- DUK_MEMZERO(&tm, sizeof(tm));
+ duk_memzero(&tm, sizeof(tm));
if (strptime((const char *) buf, "%c", &tm) != NULL) {
DUK_DDD(DUK_DDDPRINT("before mktime: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
"wday:%ld,yday:%ld,isdst:%ld}",
@@ -30782,7 +31570,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const
* convenient for an embeddable interpreter.
*/
- DUK_MEMZERO(&tm, sizeof(struct tm));
+ duk_memzero(&tm, sizeof(struct tm));
rc = (duk_small_int_t) getdate_r(str, &tm);
DUK_DDD(DUK_DDDPRINT("getdate_r() -> %ld", (long) rc));
@@ -30807,16 +31595,16 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_
DUK_UNREF(tzoffset);
- /* If the platform doesn't support the entire Ecmascript range, we need
+ /* If the platform doesn't support the entire ECMAScript range, we need
* to return 0 so that the caller can fall back to the default formatter.
*
- * For now, assume that if time_t is 8 bytes or more, the whole Ecmascript
+ * For now, assume that if time_t is 8 bytes or more, the whole ECMAScript
* range is supported. For smaller time_t values (4 bytes in practice),
* assumes that the signed 32-bit range is supported.
*
* XXX: detect this more correctly per platform. The size of time_t is
* probably not an accurate guarantee of strftime() supporting or not
- * supporting a large time range (the full Ecmascript range).
+ * supporting a large time range (the full ECMAScript range).
*/
if (sizeof(time_t) < 8 &&
(parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) {
@@ -30824,7 +31612,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_
return 0;
}
- DUK_MEMZERO(&tm, sizeof(tm));
+ duk_memzero(&tm, sizeof(tm));
tm.tm_sec = parts[DUK_DATE_IDX_SECOND];
tm.tm_min = parts[DUK_DATE_IDX_MINUTE];
tm.tm_hour = parts[DUK_DATE_IDX_HOUR];
@@ -30834,7 +31622,7 @@ DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_
tm.tm_wday = parts[DUK_DATE_IDX_WEEKDAY];
tm.tm_isdst = 0;
- DUK_MEMZERO(buf, sizeof(buf));
+ duk_memzero(buf, sizeof(buf));
if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
fmt = "%c";
} else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
@@ -30892,13 +31680,15 @@ DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEG
}
}
+#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
DUK_LOCAL void duk__convert_filetime_to_ularge(const FILETIME *ft, ULARGE_INTEGER *res) {
res->LowPart = ft->dwLowDateTime;
res->HighPart = ft->dwHighDateTime;
}
+#endif /* DUK_USE_DATE_NOW_WINDOWS_SUBMS */
DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
- DUK_MEMZERO((void *) st, sizeof(*st));
+ duk_memzero((void *) st, sizeof(*st));
st->wYear = 1970;
st->wMonth = 1;
st->wDayOfWeek = 4; /* not sure whether or not needed; Thursday */
@@ -30963,10 +31753,11 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
ULARGE_INTEGER tmp2;
ULARGE_INTEGER tmp3;
FILETIME ft1;
+ BOOL ret;
/* XXX: handling of timestamps outside Windows supported range.
* How does Windows deal with dates before 1600? Does windows
- * support all Ecmascript years (like -200000 and +200000)?
+ * support all ECMAScript years (like -200000 and +200000)?
* Should equivalent year mapping be used here too? If so, use
* a shared helper (currently integrated into timeval-to-parts).
*/
@@ -30982,7 +31773,11 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
ft1.dwLowDateTime = tmp2.LowPart;
ft1.dwHighDateTime = tmp2.HighPart;
- FileTimeToSystemTime((const FILETIME *) &ft1, &st2);
+ ret = FileTimeToSystemTime((const FILETIME *) &ft1, &st2);
+ if (!ret) {
+ DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0"));
+ return 0;
+ }
if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) {
DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0"));
return 0;
@@ -31002,6 +31797,7 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_
FILETIME ft2;
ULARGE_INTEGER tmp1;
ULARGE_INTEGER tmp2;
+ BOOL ret;
/* Do a similar computation to duk_bi_date_get_local_tzoffset_windows
* but without accounting for daylight savings time. Use this on
@@ -31017,9 +31813,17 @@ DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_
ft1.dwLowDateTime = tmp1.LowPart;
ft1.dwHighDateTime = tmp1.HighPart;
- FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2);
+ ret = FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2);
+ if (!ret) {
+ DUK_D(DUK_DPRINT("FileTimeToLocalFileTime() failed, return tzoffset 0"));
+ return 0;
+ }
- FileTimeToSystemTime((const FILETIME *) &ft2, &st2);
+ ret = FileTimeToSystemTime((const FILETIME *) &ft2, &st2);
+ if (!ret) {
+ DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0"));
+ return 0;
+ }
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
@@ -31055,7 +31859,7 @@ DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void) {
*
* Size optimization note: it might seem that vararg multipurpose functions
* like fin(), enc(), and dec() are not very size optimal, but using a single
- * user-visible Ecmascript function saves a lot of run-time footprint; each
+ * user-visible ECMAScript function saves a lot of run-time footprint; each
* Function instance takes >100 bytes. Using a shared native helper and a
* 'magic' value won't save much if there are multiple Function instances
* anyway.
@@ -31449,7 +32253,7 @@ DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *de
DUK_TYPE_MASK_LIGHTFUNC |
DUK_TYPE_MASK_BUFFER |
DUK_TYPE_MASK_OBJECT);
- if (duk_get_prop_string(thr, 1, "stream")) {
+ if (duk_get_prop_literal(thr, 1, "stream")) {
stream = duk_to_boolean(thr, -1);
}
}
@@ -31464,6 +32268,7 @@ DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *de
*/
if (len >= (DUK_HBUFFER_MAX_BYTELEN / 3) - 3) {
DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
+ DUK_WO_NORETURN(return 0;);
}
output = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, 3 + (3 * len)); /* used parts will be always manually written over */
@@ -31541,7 +32346,7 @@ DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *de
fail_type:
DUK_ERROR_TYPE(thr, DUK_STR_UTF8_DECODE_FAILED);
- DUK_UNREACHABLE();
+ DUK_WO_NORETURN(return 0;);
}
/*
@@ -31559,7 +32364,7 @@ DUK_INTERNAL duk_ret_t duk_bi_textencoder_constructor(duk_hthread *thr) {
}
DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_hthread *thr) {
- duk_push_string(thr, "utf-8");
+ duk_push_literal(thr, "utf-8");
return 1;
}
@@ -31581,6 +32386,7 @@ DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) {
len = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_input);
if (len >= DUK_HBUFFER_MAX_BYTELEN / 3) {
DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
+ DUK_WO_NORETURN(return 0;);
}
}
@@ -31600,14 +32406,14 @@ DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) {
DUK_ASSERT(duk_is_string(thr, 0)); /* True if len > 0. */
/* XXX: duk_decode_string() is used to process the input
- * string. For standard Ecmascript strings, represented
+ * string. For standard ECMAScript strings, represented
* internally as CESU-8, this is fine. However, behavior
* beyond CESU-8 is not very strict: codepoints using an
* extended form of UTF-8 are also accepted, and invalid
* codepoint sequences (which are allowed in Duktape strings)
* are not handled as well as they could (e.g. invalid
* continuation bytes may mask following codepoints).
- * This is how Ecmascript code would also see such strings.
+ * This is how ECMAScript code would also see such strings.
* Maybe replace duk_decode_string() with an explicit strict
* CESU-8 decoder here?
*/
@@ -31635,7 +32441,7 @@ DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) {
/* Standard WHATWG output is a Uint8Array. Here the Uint8Array will
* be backed by a dynamic buffer which differs from e.g. Uint8Arrays
- * created as 'new Uint8Array(N)'. Ecmascript code won't see the
+ * created as 'new Uint8Array(N)'. ECMAScript code won't see the
* difference but C code will. When bufferobjects are not supported,
* returns a plain dynamic buffer.
*/
@@ -31657,10 +32463,10 @@ DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) {
duk_to_string(thr, 0);
}
if (!duk_is_null_or_undefined(thr, 1)) {
- if (duk_get_prop_string(thr, 1, "fatal")) {
+ if (duk_get_prop_literal(thr, 1, "fatal")) {
fatal = duk_to_boolean(thr, -1);
}
- if (duk_get_prop_string(thr, 1, "ignoreBOM")) {
+ if (duk_get_prop_literal(thr, 1, "ignoreBOM")) {
ignore_bom = duk_to_boolean(thr, -1);
}
}
@@ -31675,7 +32481,7 @@ DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) {
dec_ctx->ignore_bom = (duk_uint8_t) ignore_bom;
duk__utf8_decode_init(dec_ctx); /* Initializes remaining fields. */
- duk_put_prop_string(thr, -2, DUK_INTERNAL_SYMBOL("Context"));
+ duk_put_prop_literal(thr, -2, DUK_INTERNAL_SYMBOL("Context"));
return 0;
}
@@ -31683,7 +32489,7 @@ DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) {
DUK_LOCAL duk__decode_context *duk__get_textdecoder_context(duk_hthread *thr) {
duk__decode_context *dec_ctx;
duk_push_this(thr);
- duk_get_prop_string(thr, -1, DUK_INTERNAL_SYMBOL("Context"));
+ duk_get_prop_literal(thr, -1, DUK_INTERNAL_SYMBOL("Context"));
dec_ctx = (duk__decode_context *) duk_require_buffer(thr, -1, NULL);
DUK_ASSERT(dec_ctx != NULL);
return dec_ctx;
@@ -31700,7 +32506,7 @@ DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_hthread *t
/* Encoding is now fixed, so _Context lookup is only needed to
* validate the 'this' binding (TypeError if not TextDecoder-like).
*/
- duk_push_string(thr, "utf-8");
+ duk_push_literal(thr, "utf-8");
break;
case 1:
duk_push_boolean(thr, dec_ctx->fatal);
@@ -31800,7 +32606,7 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_hthread *thr) {
duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME);
if (duk_is_undefined(thr, -1)) {
duk_pop(thr);
- duk_push_string(thr, "Error");
+ duk_push_literal(thr, "Error");
} else {
duk_to_string(thr, -1);
}
@@ -31830,7 +32636,7 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_hthread *thr) {
duk_pop(thr);
return 1;
}
- duk_push_string(thr, ": ");
+ duk_push_literal(thr, ": ");
duk_insert(thr, -2); /* ... name ': ' message */
duk_concat(thr, 3);
@@ -31899,13 +32705,13 @@ DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_hthread *thr, duk_small_int_t o
duk_get_prop_index(thr, idx_td, (duk_uarridx_t) i);
duk_get_prop_index(thr, idx_td, (duk_uarridx_t) (i + 1));
d = duk_to_number_m1(thr);
- pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32);
- flags = (duk_uint_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
+ pc = duk_double_to_int_t(DUK_FMOD(d, DUK_DOUBLE_2TO32));
+ flags = duk_double_to_uint_t(DUK_FLOOR(d / DUK_DOUBLE_2TO32));
t = (duk_small_int_t) duk_get_type(thr, -2);
if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) {
/*
- * Ecmascript/native function call or lightfunc call
+ * ECMAScript/native function call or lightfunc call
*/
count_func++;
@@ -32174,7 +32980,7 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) {
duk_push_hstring_empty(thr);
} else {
duk_insert(thr, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
- duk_push_string(thr, ",");
+ duk_push_literal(thr, ",");
duk_insert(thr, 1);
duk_join(thr, nargs - 1);
}
@@ -32186,11 +32992,11 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) {
/* XXX: this placeholder is not always correct, but use for now.
* It will fail in corner cases; see test-dev-func-cons-args.js.
*/
- duk_push_string(thr, "function(");
+ duk_push_literal(thr, "function(");
duk_dup_1(thr);
- duk_push_string(thr, "){");
+ duk_push_literal(thr, "){");
duk_dup_0(thr);
- duk_push_string(thr, "}");
+ duk_push_literal(thr, "\n}"); /* Newline is important to handle trailing // comment. */
duk_concat(thr, 5);
/* [ body formals source ] */
@@ -32208,7 +33014,7 @@ DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) {
comp_flags);
/* Force .name to 'anonymous' (ES2015). */
- duk_push_string(thr, "anonymous");
+ duk_push_literal(thr, "anonymous");
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
func = (duk_hcompfunc *) duk_known_hobject(thr, -1);
@@ -32420,7 +33226,7 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) {
if (DUK_HOBJECT_HAS_BOUNDFUNC(h_target)) {
duk_hboundfunc *h_boundtarget;
- h_boundtarget = (duk_hboundfunc *) h_target;
+ h_boundtarget = (duk_hboundfunc *) (void *) h_target;
/* The final function should always be non-bound, unless
* there's a bug in the internals. Assert for it.
@@ -32454,7 +33260,7 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) {
DUK_DCERROR_RANGE_INVALID_COUNT(thr);
}
tv_res = (duk_tval *) DUK_ALLOC_CHECKED(thr, ((duk_size_t) bound_nargs) * sizeof(duk_tval));
- DUK_ASSERT(tv_res != NULL);
+ DUK_ASSERT(tv_res != NULL || bound_nargs == 0);
DUK_ASSERT(h_bound->args == NULL);
DUK_ASSERT(h_bound->nargs == 0);
h_bound->args = tv_res;
@@ -32494,7 +33300,7 @@ DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) {
duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_LC_ARGUMENTS);
/* Function name and fileName (non-standard). */
- duk_push_string(thr, "bound "); /* ES2015 19.2.3.2. */
+ duk_push_literal(thr, "bound "); /* ES2015 19.2.3.2. */
duk_get_prop_stridx(thr, -3, DUK_STRIDX_NAME);
if (!duk_is_string_notsymbol(thr, -1)) {
/* ES2015 has requirement to check that .name of target is a string
@@ -32578,6 +33384,17 @@ DUK_INTERNAL duk_ret_t duk_bi_native_function_name(duk_hthread *thr) {
fail_type:
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
+
+#if defined(DUK_USE_SYMBOL_BUILTIN)
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_hasinstance(duk_hthread *thr) {
+ /* This binding: RHS, stack index 0: LHS. */
+ duk_bool_t ret;
+
+ ret = duk_js_instanceof_ordinary(thr, DUK_GET_TVAL_POSIDX(thr, 0), DUK_GET_THIS_TVAL_PTR(thr));
+ duk_push_boolean(thr, ret);
+ return 1;
+}
+#endif /* DUK_USE_SYMBOL_BUILTIN */
/*
* Global object built-ins
*/
@@ -32780,6 +33597,7 @@ DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ct
uri_error:
DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
+ DUK_WO_NORETURN(return;);
}
DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
@@ -32918,6 +33736,7 @@ DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ct
uri_error:
DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
+ DUK_WO_NORETURN(return;);
}
#if defined(DUK_USE_SECTION_B)
@@ -32958,6 +33777,7 @@ DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, c
esc_error:
DUK_ERROR_TYPE(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
+ DUK_WO_NORETURN(return;);
}
DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
@@ -32990,7 +33810,7 @@ DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx,
* Eval needs to handle both a "direct eval" and an "indirect eval".
* Direct eval handling needs access to the caller's activation so that its
* lexical environment can be accessed. A direct eval is only possible from
- * Ecmascript code; an indirect eval call is possible also from C code.
+ * ECMAScript code; an indirect eval call is possible also from C code.
* When an indirect eval call is made from C code, there may not be a
* calling activation at all which needs careful handling.
*/
@@ -33029,7 +33849,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_hthread *thr) {
#if defined(DUK_USE_DEBUGGER_SUPPORT)
/* NOTE: level is used only by the debugger and should never be present
- * for an Ecmascript eval().
+ * for an ECMAScript eval().
*/
DUK_ASSERT(level == -2); /* by default, use caller's environment */
if (duk_get_top(thr) >= 2 && duk_is_number(thr, 1)) {
@@ -33522,6 +34342,7 @@ DUK_LOCAL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx) {
*/
DUK_ERROR_FMT1(js_ctx->thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_FMT_INVALID_JSON,
(long) (js_ctx->p - js_ctx->p_start));
+ DUK_WO_NORETURN(return;);
}
DUK_LOCAL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) {
@@ -33937,7 +34758,7 @@ DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
src_len = (duk_size_t) (p - js_ctx->p);
buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_len);
DUK_ASSERT(buf != NULL);
- DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len);
+ duk_memcpy((void *) buf, (const void *) js_ctx->p, src_len);
duk_hex_decode(thr, -1);
js_ctx->p = p + 1; /* skip '|' */
@@ -34028,6 +34849,7 @@ DUK_LOCAL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) {
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
DUK_ERROR_RANGE(thr, DUK_STR_JSONDEC_RECLIMIT);
+ DUK_WO_NORETURN(return;);
}
js_ctx->recursion_depth++;
}
@@ -34604,9 +35426,9 @@ DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_st
/* If XUTF-8 decoding fails, treat the offending byte as a codepoint directly
* and go forward one byte. This is of course very lossy, but allows some kind
* of output to be produced even for internal strings which don't conform to
- * XUTF-8. All standard Ecmascript strings are always CESU-8, so this behavior
- * does not violate the Ecmascript specification. The behavior is applied to
- * all modes, including Ecmascript standard JSON. Because the current XUTF-8
+ * XUTF-8. All standard ECMAScript strings are always CESU-8, so this behavior
+ * does not violate the ECMAScript specification. The behavior is applied to
+ * all modes, including ECMAScript standard JSON. Because the current XUTF-8
* decoding is not very strict, this behavior only really affects initial bytes
* and truncated codepoints.
*
@@ -34743,7 +35565,7 @@ DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size
/* Unlike in duk_hex_encode() 'dst' is not necessarily aligned by 2.
* For platforms where unaligned accesses are not allowed, shift 'dst'
- * ahead by 1 byte to get alignment and then DUK_MEMMOVE() the result
+ * ahead by 1 byte to get alignment and then duk_memmove() the result
* in place. The faster encoding loop makes up the difference.
* There's always space for one extra byte because a terminator always
* follows the hex data and that's been accounted for by the caller.
@@ -34776,7 +35598,7 @@ DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size
#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
if (shift_dst) {
q--;
- DUK_MEMMOVE((void *) dst, (const void *) (dst + 1), 2 * len_safe);
+ duk_memmove((void *) dst, (const void *) (dst + 1), 2 * len_safe);
DUK_ASSERT(dst + 2 * len_safe == q);
}
#endif
@@ -34852,7 +35674,7 @@ DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_d
#if defined(DUK_USE_JC)
{
DUK_ASSERT(js_ctx->flag_ext_compatible);
- DUK_MEMCPY((void *) q, (const void *) "{\"_buf\":\"", 9); /* len: 9 */
+ duk_memcpy((void *) q, (const void *) "{\"_buf\":\"", 9); /* len: 9 */
q += 9;
q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
*q++ = DUK_ASC_DOUBLEQUOTE;
@@ -34925,7 +35747,7 @@ DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */
DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
- DUK_MEMZERO(buf, sizeof(buf));
+ duk_memzero(buf, sizeof(buf));
/* The #if defined() clutter here needs to handle the three
* cases: (1) JX+JC, (2) JX only, (3) JC only.
@@ -35015,21 +35837,21 @@ DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t dept
p = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, need_bytes);
p_start = p;
- DUK_MEMCPY((void *) p, (const void *) gap_data, (size_t) gap_len);
+ duk_memcpy((void *) p, (const void *) gap_data, (size_t) gap_len);
p += gap_len;
avail_bytes = gap_len;
DUK_ASSERT(need_bytes >= gap_len);
need_bytes -= gap_len;
while (need_bytes >= avail_bytes) {
- DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) avail_bytes);
+ duk_memcpy((void *) p, (const void *) p_start, (size_t) avail_bytes);
p += avail_bytes;
need_bytes -= avail_bytes;
avail_bytes <<= 1;
}
DUK_ASSERT(need_bytes < avail_bytes); /* need_bytes may be zero */
- DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) need_bytes);
+ duk_memcpy((void *) p, (const void *) p_start, (size_t) need_bytes);
p += need_bytes;
/*avail_bytes += need_bytes*/
@@ -35061,6 +35883,7 @@ DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_
if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) {
DUK_DD(DUK_DDPRINT("slow path loop detect"));
DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT);
+ DUK_WO_NORETURN(return;);
}
}
if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
@@ -35070,6 +35893,7 @@ DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_
duk_dup_top(thr); /* -> [ ... voidp voidp ] */
if (duk_has_prop(thr, js_ctx->idx_loop)) {
DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT);
+ DUK_WO_NORETURN(return;);
}
duk_push_true(thr); /* -> [ ... voidp true ] */
duk_put_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */
@@ -35081,6 +35905,7 @@ DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_
DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
DUK_ERROR_RANGE(thr, DUK_STR_JSONENC_RECLIMIT);
+ DUK_WO_NORETURN(return;);
}
js_ctx->recursion_depth++;
@@ -35678,12 +36503,14 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
DUK_DD(DUK_DDPRINT("fast path recursion limit"));
DUK_ERROR_RANGE(js_ctx->thr, DUK_STR_JSONDEC_RECLIMIT);
+ DUK_WO_NORETURN(return 0;);
}
for (i = 0, n = (duk_uint_fast32_t) js_ctx->recursion_depth; i < n; i++) {
if (DUK_UNLIKELY(js_ctx->visiting[i] == obj)) {
DUK_DD(DUK_DDPRINT("fast path loop detect"));
DUK_ERROR_TYPE(js_ctx->thr, DUK_STR_CYCLIC_INPUT);
+ DUK_WO_NORETURN(return 0;);
}
}
@@ -36064,7 +36891,7 @@ DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, du
/* Error message doesn't matter: the error is ignored anyway. */
DUK_DD(DUK_DDPRINT("aborting fast path"));
DUK_ERROR_INTERNAL(js_ctx->thr);
- return 0; /* unreachable */
+ DUK_WO_NORETURN(return 0;);
}
DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_hthread *thr, void *udata) {
@@ -36113,7 +36940,7 @@ void duk_bi_json_parse_helper(duk_hthread *thr,
(unsigned long) flags,
(long) duk_get_top(thr)));
- DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
+ duk_memzero(&js_ctx_alloc, sizeof(js_ctx_alloc));
js_ctx->thr = thr;
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
/* nothing now */
@@ -36223,7 +37050,7 @@ void duk_bi_json_stringify_helper(duk_hthread *thr,
* Context init
*/
- DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
+ duk_memzero(&js_ctx_alloc, sizeof(js_ctx_alloc));
js_ctx->thr = thr;
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
js_ctx->h_replacer = NULL;
@@ -36621,7 +37448,7 @@ DUK_LOCAL duk_ret_t duk__math_minmax(duk_hthread *thr, duk_double_t initial, duk
DUK_LOCAL double duk__fmin_fixed(double x, double y) {
/* fmin() with args -0 and +0 is not guaranteed to return
- * -0 as Ecmascript requires.
+ * -0 as ECMAScript requires.
*/
if (x == 0 && y == 0) {
duk_double_union du1, du2;
@@ -36648,7 +37475,7 @@ DUK_LOCAL double duk__fmin_fixed(double x, double y) {
DUK_LOCAL double duk__fmax_fixed(double x, double y) {
/* fmax() with args -0 and +0 is not guaranteed to return
- * +0 as Ecmascript requires.
+ * +0 as ECMAScript requires.
*/
if (x == 0 && y == 0) {
if (DUK_SIGNBIT(x) == 0 || DUK_SIGNBIT(y) == 0) {
@@ -37111,6 +37938,7 @@ DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_hthread *thr) {
(DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) {
DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(thr, -1)));
DUK_ERROR_TYPE(thr, "number expected");
+ DUK_WO_NORETURN(return 0.0;);
}
duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
DUK_ASSERT(duk_is_number(thr, -1));
@@ -37217,8 +38045,11 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_hthread *thr) {
duk_small_int_t c;
duk_small_uint_t n2s_flags;
- frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20);
+ /* In ES5.1 frac_digits is coerced first; in ES2015 the 'this number
+ * value' check is done first.
+ */
d = duk__push_this_number_plain(thr);
+ frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20);
c = (duk_small_int_t) DUK_FPCLASSIFY(d);
if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
@@ -37325,6 +38156,42 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_hthread *thr) {
return 1;
}
+/*
+ * ES2015 isFinite() etc
+ */
+
+#if defined(DUK_USE_ES6)
+DUK_INTERNAL duk_ret_t duk_bi_number_check_shared(duk_hthread *thr) {
+ duk_int_t magic;
+ duk_bool_t ret = 0;
+
+ if (duk_is_number(thr, 0)) {
+ duk_double_t d;
+
+ magic = duk_get_current_magic(thr);
+ d = duk_get_number(thr, 0);
+
+ switch (magic) {
+ case 0: /* isFinite() */
+ ret = duk_double_is_finite(d);
+ break;
+ case 1: /* isInteger() */
+ ret = duk_double_is_integer(d);
+ break;
+ case 2: /* isNaN() */
+ ret = duk_double_is_nan(d);
+ break;
+ default: /* isSafeInteger() */
+ DUK_ASSERT(magic == 3);
+ ret = duk_double_is_safe_integer(d);
+ }
+ }
+
+ duk_push_boolean(thr, ret);
+ return 1;
+}
+#endif /* DUK_USE_ES6 */
+
#endif /* DUK_USE_NUMBER_BUILTIN */
/*
* Object built-ins
@@ -37335,12 +38202,9 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_hthread *thr) {
/* Needed even when Object built-in disabled. */
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr) {
duk_tval *tv;
+
tv = DUK_HTHREAD_THIS_PTR(thr);
- /* XXX: This is not entirely correct anymore; in ES2015 the
- * default lookup should use @@toStringTag to come up with
- * e.g. [object Symbol].
- */
- duk_push_class_string_tval(thr, tv);
+ duk_push_class_string_tval(thr, tv, 0 /*avoid_side_effects*/);
return 1;
}
@@ -37845,7 +38709,7 @@ DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_hthread *th
DUK_ASSERT(duk_get_hobject(thr, 2) != NULL);
/*
- * Validate and convert argument property descriptor (an Ecmascript
+ * Validate and convert argument property descriptor (an ECMAScript
* object) into a set of defprop_flags and possibly property value,
* getter, and/or setter values on the value stack.
*
@@ -38123,6 +38987,7 @@ DUK_INTERNAL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_hthread *thr)
if (DUK_UNLIKELY(sanity-- == 0)) {
DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
+ DUK_WO_NORETURN(return 0;);
}
duk_get_prototype(thr, -1);
@@ -38247,37 +39112,37 @@ DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_hthread *thr
DUK_INTERNAL duk_ret_t duk_bi_promise_constructor(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
- return 0;
+ DUK_WO_NORETURN(return 0;);
}
DUK_INTERNAL duk_ret_t duk_bi_promise_all(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
- return 0;
+ DUK_WO_NORETURN(return 0;);
}
DUK_INTERNAL duk_ret_t duk_bi_promise_race(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
- return 0;
+ DUK_WO_NORETURN(return 0;);
}
DUK_INTERNAL duk_ret_t duk_bi_promise_reject(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
- return 0;
+ DUK_WO_NORETURN(return 0;);
}
DUK_INTERNAL duk_ret_t duk_bi_promise_resolve(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
- return 0;
+ DUK_WO_NORETURN(return 0;);
}
DUK_INTERNAL duk_ret_t duk_bi_promise_catch(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
- return 0;
+ DUK_WO_NORETURN(return 0;);
}
DUK_INTERNAL duk_ret_t duk_bi_promise_then(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
- return 0;
+ DUK_WO_NORETURN(return 0;);
}
#endif /* DUK_USE_PROMISE_BUILTIN */
@@ -38311,6 +39176,7 @@ DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h
h = duk_get_hstring(thr, -1);
if (h == NULL) {
DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr);
+ DUK_WO_NORETURN(return;);
}
if (!(flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
@@ -38418,6 +39284,7 @@ DUK_INTERNAL duk_ret_t duk_bi_reflect_object_get(duk_hthread *thr) {
if (nargs >= 3 && !duk_strict_equals(thr, 0, 2)) {
/* XXX: [[Get]] receiver currently unsupported */
DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return 0;);
}
/* [ target key receiver? ...? ] */
@@ -38461,6 +39328,7 @@ DUK_INTERNAL duk_ret_t duk_bi_reflect_object_set(duk_hthread *thr) {
if (nargs >= 4 && !duk_strict_equals(thr, 0, 3)) {
/* XXX: [[Set]] receiver currently unsupported */
DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return 0;);
}
/* [ target key value receiver? ...? ] */
@@ -38594,7 +39462,7 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_tostring(duk_hthread *thr) {
/* This must be generic in ES2015 and later. */
DUK_ASSERT_TOP(thr, 0);
duk_push_this(thr);
- duk_push_string(thr, "/");
+ duk_push_literal(thr, "/");
duk_get_prop_stridx(thr, 0, DUK_STRIDX_SOURCE);
duk_dup_m2(thr); /* another "/" */
duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS);
@@ -38658,7 +39526,7 @@ DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_hthread *thr) {
if (magic != 16 /* .source */) {
return 0;
}
- duk_push_string(thr, "(?:)"); /* .source handled by switch-case */
+ duk_push_literal(thr, "(?:)"); /* .source handled by switch-case */
re_flags = 0;
} else {
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
@@ -38729,6 +39597,7 @@ DUK_LOCAL duk_hstring *duk__str_tostring_notregexp(duk_hthread *thr, duk_idx_t i
if (duk_get_class_number(thr, idx) == DUK_HOBJECT_CLASS_REGEXP) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ DUK_WO_NORETURN(return NULL;);
}
h = duk_to_hstring(thr, idx);
DUK_ASSERT(h != NULL);
@@ -38775,14 +39644,14 @@ DUK_LOCAL duk_int_t duk__str_search_shared(duk_hthread *thr, duk_hstring *h_this
while (p <= p_end && p >= p_start) {
t = *p;
- /* For Ecmascript strings, this check can only match for
+ /* For ECMAScript strings, this check can only match for
* initial UTF-8 bytes (not continuation bytes). For other
* strings all bets are off.
*/
if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) {
- DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */
- if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
+ DUK_ASSERT(q_blen > 0);
+ if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
return cpos;
}
}
@@ -38964,13 +39833,37 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_hthread *thr) {
*/
DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_hthread *thr) {
+ duk_hstring *h;
duk_int_t pos;
/* XXX: faster implementation */
- (void) duk_push_this_coercible_to_string(thr);
+ h = duk_push_this_coercible_to_string(thr);
+ DUK_ASSERT(h != NULL);
+
pos = duk_to_int(thr, 0);
- duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) (pos + 1));
+
+ if (sizeof(duk_size_t) >= sizeof(duk_uint_t)) {
+ /* Cast to duk_size_t works in this case:
+ * - If pos < 0, (duk_size_t) pos will always be
+ * >= max_charlen, and result will be the empty string
+ * (see duk_substring()).
+ * - If pos >= 0, pos + 1 cannot wrap.
+ */
+ DUK_ASSERT((duk_size_t) DUK_INT_MIN >= DUK_HSTRING_MAX_BYTELEN);
+ DUK_ASSERT((duk_size_t) DUK_INT_MAX + 1U > (duk_size_t) DUK_INT_MAX);
+ duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) pos + 1U);
+ } else {
+ /* If size_t is smaller than int, explicit bounds checks
+ * are needed because an int may wrap multiple times.
+ */
+ if (DUK_UNLIKELY(pos < 0 || (duk_uint_t) pos >= (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h))) {
+ duk_push_hstring_empty(thr);
+ } else {
+ duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) pos + 1U);
+ }
+ }
+
return 1;
}
@@ -39360,7 +40253,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_hthread *thr) {
while (p <= p_end) {
DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
- if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
+ if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
duk_dup_0(thr);
h_match = duk_known_hstring(thr, -1);
#if defined(DUK_USE_REGEXP_SUPPORT)
@@ -39741,7 +40634,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_hthread *thr) {
while (p <= p_end) {
DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
DUK_ASSERT(q_blen > 0); /* no issues with empty memcmp() */
- if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
+ if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
/* never an empty match, so step 13.c.iii can't be triggered */
goto found;
}
@@ -40054,12 +40947,14 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_hthread *thr) {
/* Temporary fixed buffer, later converted to string. */
buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, result_len);
+ DUK_ASSERT(buf != NULL);
src = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
+ DUK_ASSERT(src != NULL);
#if defined(DUK_USE_PREFER_SIZE)
p = buf;
while (count-- > 0) {
- DUK_MEMCPY((void *) p, (const void *) src, input_blen); /* copy size may be zero */
+ duk_memcpy((void *) p, (const void *) src, input_blen); /* copy size may be zero, but pointers are valid */
p += input_blen;
}
#else /* DUK_USE_PREFER_SIZE */
@@ -40076,12 +40971,12 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_hthread *thr) {
(long) result_len));
if (remain <= copy_size) {
/* If result_len is zero, this case is taken and does
- * a zero size copy.
+ * a zero size copy (with valid pointers).
*/
- DUK_MEMCPY((void *) p, (const void *) src, remain);
+ duk_memcpy((void *) p, (const void *) src, remain);
break;
} else {
- DUK_MEMCPY((void *) p, (const void *) src, copy_size);
+ duk_memcpy((void *) p, (const void *) src, copy_size);
p += copy_size;
}
@@ -40136,8 +41031,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_hthread *thr)
h2_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
prefix_len = (h1_len <= h2_len ? h1_len : h2_len);
- /* Zero size compare not an issue with DUK_MEMCMP. */
- rc = (duk_small_int_t) DUK_MEMCMP((const void *) DUK_HSTRING_GET_DATA(h1),
+ rc = (duk_small_int_t) duk_memcmp((const void *) DUK_HSTRING_GET_DATA(h1),
(const void *) DUK_HSTRING_GET_DATA(h2),
(size_t) prefix_len);
@@ -40187,7 +41081,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_hthread *
if (duk_is_undefined(thr, 1)) {
if (magic) {
- p_cmp_start += DUK_HSTRING_GET_BYTELEN(h) - blen_search;
+ p_cmp_start = p_cmp_start + DUK_HSTRING_GET_BYTELEN(h) - blen_search;
} else {
/* p_cmp_start already OK */
}
@@ -40218,7 +41112,7 @@ DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_hthread *
result = 0;
if (p_cmp_start >= DUK_HSTRING_GET_DATA(h) &&
(duk_size_t) (p_cmp_start - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h)) + blen_search <= DUK_HSTRING_GET_BYTELEN(h)) {
- if (DUK_MEMCMP((const void *) p_cmp_start,
+ if (duk_memcmp((const void *) p_cmp_start,
(const void *) DUK_HSTRING_GET_DATA(h_search),
(size_t) blen_search) == 0) {
result = 1;
@@ -40292,9 +41186,10 @@ DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_hthread *thr) {
* +1 0xff after unique suffix for symbols with undefined description
*/
buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, 1 + len + 1 + 17 + 1);
+ DUK_ASSERT(buf != NULL);
p = buf + 1;
DUK_ASSERT(desc != NULL || len == 0); /* may be NULL if len is 0 */
- DUK_MEMCPY((void *) p, (const void *) desc, len);
+ duk_memcpy_unsafe((void *) p, (const void *) desc, len);
p += len;
if (magic == 0) {
/* Symbol(): create unique symbol. Use two 32-bit values
@@ -40465,7 +41360,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_hthread *thr) {
*
* The thread must be in resumable state, either (a) new thread which hasn't
* yet started, or (b) a thread which has previously yielded. This method
- * must be called from an Ecmascript function.
+ * must be called from an ECMAScript function.
*
* Args:
* - thread
@@ -40491,8 +41386,9 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) {
DUK_ASSERT(thr->heap->curr_thread == thr);
thr_resume = duk_require_hthread(thr, 0);
- is_error = (duk_small_uint_t) duk_to_boolean(thr, 2);
- duk_set_top(thr, 2);
+ DUK_ASSERT(duk_get_top(thr) == 3);
+ is_error = (duk_small_uint_t) duk_to_boolean_top_pop(thr);
+ DUK_ASSERT(duk_get_top(thr) == 2);
/* [ thread value ] */
@@ -40512,7 +41408,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) {
caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent);
if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
- DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code"));
+ DUK_DD(DUK_DDPRINT("resume state invalid: caller must be ECMAScript code"));
goto state_error;
}
@@ -40540,7 +41436,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) {
DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE);
- /* The initial function must be an Ecmascript function (but
+ /* The initial function must be an ECMAScript function (but
* can be bound). We must make sure of that before we longjmp
* because an error in the RESUME handler call processing will
* not be handled very cleanly.
@@ -40619,7 +41515,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) {
* The thread must be in yieldable state: it must have a resumer, and there
* must not be any yield-preventing calls (native calls and constructor calls,
* currently) in the thread's call stack (otherwise a resume would not be
- * possible later). This method must be called from an Ecmascript function.
+ * possible later). This method must be called from an ECMAScript function.
*
* Args:
* - value
@@ -40640,8 +41536,9 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_hthread *thr) {
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
DUK_ASSERT(thr->heap->curr_thread == thr);
- is_error = (duk_small_uint_t) duk_to_boolean(thr, 1);
- duk_set_top(thr, 1);
+ DUK_ASSERT(duk_get_top(thr) == 2);
+ is_error = (duk_small_uint_t) duk_to_boolean_top_pop(thr);
+ DUK_ASSERT(duk_get_top(thr) == 1);
/* [ value ] */
@@ -40667,7 +41564,7 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_hthread *thr) {
caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent);
if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
- DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code"));
+ DUK_DD(DUK_DDPRINT("yield state invalid: caller must be ECMAScript code"));
goto state_error;
}
@@ -40764,7 +41661,7 @@ DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffe
} else {
copylen = length;
}
- DUK_MEMCPY(fb->buffer + fb->offset, buffer, copylen);
+ duk_memcpy_unsafe(fb->buffer + fb->offset, buffer, copylen);
fb->offset += copylen;
}
@@ -40850,7 +41747,7 @@ DUK_INTERNAL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb) {
* (excluding the null terminator). If retval == buffer size,
* output was truncated (except for corner cases).
*
- * * Output format is intentionally different from Ecmascript
+ * * Output format is intentionally different from ECMAScript
* formatting requirements, as formatting here serves debugging
* of internals.
*
@@ -41636,7 +42533,7 @@ DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const cha
const char *p_end = p + DUK_STRLEN(format);
duk_int_t retval;
- DUK_MEMZERO(&fb, sizeof(fb));
+ duk_memzero(&fb, sizeof(fb));
fb.buffer = (duk_uint8_t *) str;
fb.length = size;
fb.offset = 0;
@@ -41661,7 +42558,7 @@ DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const cha
* understand. See man 3 printf.
*/
- DUK_MEMZERO(&st, sizeof(st));
+ duk_memzero(&st, sizeof(st));
st.fb = &fb;
st.depth = 0;
st.depth_limit = 1;
@@ -41728,8 +42625,8 @@ DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const cha
/* format is too large, abort */
goto format_error;
}
- DUK_MEMZERO(fmtbuf, sizeof(fmtbuf));
- DUK_MEMCPY(fmtbuf, p_begfmt, fmtlen);
+ duk_memzero(fmtbuf, sizeof(fmtbuf));
+ duk_memcpy(fmtbuf, p_begfmt, fmtlen);
/* assume exactly 1 arg, which is why '*' is forbidden; arg size still
* depends on type though.
@@ -41834,7 +42731,8 @@ DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_u
duk_uint8_t *p = (duk_uint8_t *) buf;
duk_uint8_t *p_end = (duk_uint8_t *) (buf + buf_size - 1);
- DUK_MEMZERO(buf, buf_size);
+ DUK_ASSERT(buf != NULL);
+ duk_memzero(buf, buf_size);
for (i = 0; i < fptr_size; i++) {
duk_int_t left = (duk_int_t) (p_end - p);
@@ -42172,6 +43070,7 @@ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_
DUK_ASSERT(thr != NULL);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
+ DUK_ASSERT(data != NULL);
if (heap->dbg_read_cb == NULL) {
DUK_D(DUK_DPRINT("attempt to read %ld bytes in detached state, return zero data", (long) length));
@@ -42209,7 +43108,7 @@ DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_
return;
fail:
- DUK_MEMZERO((void *) data, (size_t) length);
+ duk_memzero((void *) data, (size_t) length);
}
DUK_INTERNAL duk_uint8_t duk_debug_read_byte(duk_hthread *thr) {
@@ -42822,7 +43721,7 @@ DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) {
(unsigned int) du2.uc[4], (unsigned int) du2.uc[5],
(unsigned int) du2.uc[6], (unsigned int) du2.uc[7]));
- if (DUK_MEMCMP((const void *) du1.uc, (const void *) du2.uc, sizeof(du1.uc)) == 0) {
+ if (duk_memcmp((const void *) du1.uc, (const void *) du2.uc, sizeof(du1.uc)) == 0) {
duk_debug_write_int(thr, i32);
} else {
DUK_DBLUNION_DOUBLE_HTON(&du1);
@@ -42931,9 +43830,9 @@ DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) {
duk_debug_write_int(thr, 0);
} else {
duk_push_tval(thr, &act->tv_func);
- duk_get_prop_string(thr, -1, "fileName");
+ duk_get_prop_literal(thr, -1, "fileName");
duk__debug_write_hstring_safe_top(thr);
- duk_get_prop_string(thr, -2, "name");
+ duk_get_prop_literal(thr, -2, "name");
duk__debug_write_hstring_safe_top(thr);
duk_pop_3(thr);
/* Report next pc/line to be executed. */
@@ -42978,7 +43877,7 @@ DUK_INTERNAL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal) {
act = thr->callstack_curr;
if (act != NULL) {
duk_push_tval(thr, &act->tv_func);
- duk_get_prop_string(thr, -1, "fileName");
+ duk_get_prop_literal(thr, -1, "fileName");
duk__debug_write_hstring_safe_top(thr);
pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr, act);
duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(thr, -2, pc));
@@ -43455,7 +44354,7 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
fun = DUK_ACT_GET_FUNC(act);
if (fun != NULL && DUK_HOBJECT_IS_COMPFUNC(fun)) {
/* Direct eval requires that there's a current
- * activation and it is an Ecmascript function.
+ * activation and it is an ECMAScript function.
* When Eval is executed from e.g. cooperate API
* call we'll need to do an indirect eval instead.
*/
@@ -44121,7 +45020,7 @@ DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *h
if (DUK_HOBJECT_IS_BOUNDFUNC(h_obj)) {
duk_hboundfunc *h_bfun;
- h_bfun = (duk_hboundfunc *) h_obj;
+ h_bfun = (duk_hboundfunc *) (void *) h_obj;
duk__debug_getinfo_flags_key(thr, "target");
duk_debug_write_tval(thr, &h_bfun->target);
@@ -44598,7 +45497,7 @@ DUK_INTERNAL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev
fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
/* Short circuit if is safe: if act->curr_pc != NULL, 'fun' is
- * guaranteed to be a non-NULL Ecmascript function.
+ * guaranteed to be a non-NULL ECMAScript function.
*/
DUK_ASSERT(act->curr_pc == NULL ||
(fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun)));
@@ -44694,11 +45593,10 @@ DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_
DUK_ASSERT(h != NULL);
move_size = sizeof(duk_breakpoint) * (heap->dbg_breakpoint_count - breakpoint_index - 1);
- if (move_size > 0) {
- DUK_MEMMOVE((void *) b,
- (const void *) (b + 1),
- (size_t) move_size);
- }
+ duk_memmove((void *) b,
+ (const void *) (b + 1),
+ (size_t) move_size);
+
heap->dbg_breakpoint_count--;
heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
@@ -44784,7 +45682,7 @@ DUK_INTERNAL void duk_debug_clear_pause_state(duk_heap *heap) {
*
* Error augmentation may throw an internal error (e.g. alloc error).
*
- * Ecmascript allows throwing any values, so all values cannot be
+ * ECMAScript allows throwing any values, so all values cannot be
* augmented. Currently, the built-in augmentation at error creation
* only augments error values which are Error instances (= have the
* built-in Error.prototype in their prototype chain) and are also
@@ -45124,7 +46022,6 @@ DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, c
DUK_UNREF(pc);
DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
- act = NULL; /* invalidated by pushes, so get out of the way */
duk_push_hobject(thr, func);
@@ -45339,12 +46236,15 @@ DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) {
/* #include duk_internal.h -> already included */
#if defined(DUK_USE_PREFER_SIZE)
+DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_minimal(duk_hthread *thr));
DUK_LOCAL void duk__uncaught_minimal(duk_hthread *thr) {
(void) duk_fatal(thr, "uncaught error");
+ DUK_WO_NORETURN(return;);
}
#endif
#if 0
+DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_readable(duk_hthread *thr));
DUK_LOCAL void duk__uncaught_readable(duk_hthread *thr) {
const char *summary;
char buf[DUK_USE_FATAL_MAXLEN];
@@ -45353,10 +46253,12 @@ DUK_LOCAL void duk__uncaught_readable(duk_hthread *thr) {
DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
buf[sizeof(buf) - 1] = (char) 0;
(void) duk_fatal(thr, (const char *) buf);
+ DUK_WO_NORETURN(return;);
}
#endif
#if !defined(DUK_USE_PREFER_SIZE)
+DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_error_aware(duk_hthread *thr));
DUK_LOCAL void duk__uncaught_error_aware(duk_hthread *thr) {
const char *summary;
char buf[DUK_USE_FATAL_MAXLEN];
@@ -45366,6 +46268,7 @@ DUK_LOCAL void duk__uncaught_error_aware(duk_hthread *thr) {
DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
buf[sizeof(buf) - 1] = (char) 0;
(void) duk_fatal(thr, (const char *) buf);
+ DUK_WO_NORETURN(return;);
}
#endif
@@ -45403,14 +46306,9 @@ DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
DUK_DD(DUK_DDPRINT("about to longjmp, pf_prevent_count=%ld", (long) thr->heap->pf_prevent_count));
-#if !defined(DUK_USE_CPP_EXCEPTIONS)
/* If we don't have a jmpbuf_ptr, there is little we can do except
* cause a fatal error. The caller's expectation is that we never
* return.
- *
- * With C++ exceptions we now just propagate an uncaught error
- * instead of invoking the fatal error handler. Because there's
- * a dummy jmpbuf for C++ exceptions now, this could be changed.
*/
if (!thr->heap->lj.jmpbuf_ptr) {
DUK_D(DUK_DPRINT("uncaught error: type=%d iserror=%d value1=%!T value2=%!T",
@@ -45424,16 +46322,12 @@ DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
#endif
DUK_UNREACHABLE();
}
-#endif /* DUK_USE_CPP_EXCEPTIONS */
#if defined(DUK_USE_CPP_EXCEPTIONS)
- {
- duk_internal_exception exc; /* dummy */
- throw exc;
- }
-#else /* DUK_USE_CPP_EXCEPTIONS */
+ throw duk_internal_exception(); /* dummy */
+#else
DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb);
-#endif /* DUK_USE_CPP_EXCEPTIONS */
+#endif
DUK_UNREACHABLE();
}
@@ -45612,10 +46506,10 @@ DUK_INTERNAL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_t
DUK_ASSERT_LJSTATE_SET(heap);
}
/*
- * Create and throw an Ecmascript error object based on a code and a message.
+ * Create and throw an ECMAScript error object based on a code and a message.
*
- * Used when we throw errors internally. Ecmascript generated error objects
- * are created by Ecmascript code, and the throwing is handled by the bytecode
+ * Used when we throw errors internally. ECMAScript generated error objects
+ * are created by ECMAScript code, and the throwing is handled by the bytecode
* executor.
*/
@@ -45771,7 +46665,7 @@ DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t r
*/
duk_error_raw(thr, -rc, NULL, 0, "error (rc %ld)", (long) rc);
- DUK_UNREACHABLE();
+ DUK_WO_NORETURN(return;);
}
/*
* duk_hbuffer allocation and freeing.
@@ -45822,10 +46716,10 @@ DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk
/* zero everything unless requested not to do so */
#if defined(DUK_USE_ZERO_BUFFER_DATA)
- DUK_MEMZERO((void *) res,
+ duk_memzero((void *) res,
(flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size);
#else
- DUK_MEMZERO((void *) res, header_size);
+ duk_memzero((void *) res, header_size);
#endif
if (flags & DUK_BUF_FLAG_EXTERNAL) {
@@ -45872,7 +46766,7 @@ DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk
DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL);
}
} else {
- *out_bufdata = (void *) ((duk_hbuffer_fixed *) res + 1);
+ *out_bufdata = (void *) ((duk_hbuffer_fixed *) (void *) res + 1);
}
DUK_HBUFFER_SET_SIZE(res, size);
@@ -45931,6 +46825,7 @@ DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf,
if (new_size > DUK_HBUFFER_MAX_BYTELEN) {
DUK_ERROR_RANGE(thr, "buffer too long");
+ DUK_WO_NORETURN(return;);
}
/*
@@ -45959,7 +46854,7 @@ DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf,
if (new_size > prev_size) {
DUK_ASSERT(new_size - prev_size > 0);
#if defined(DUK_USE_ZERO_BUFFER_DATA)
- DUK_MEMZERO((void *) ((char *) res + prev_size),
+ duk_memzero((void *) ((char *) res + prev_size),
(duk_size_t) (new_size - prev_size));
#endif
}
@@ -45968,6 +46863,7 @@ DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf,
DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(thr->heap, buf, res);
} else {
DUK_ERROR_ALLOC_FAILED(thr);
+ DUK_WO_NORETURN(return;);
}
DUK_ASSERT(res != NULL || new_size == 0);
@@ -46069,7 +46965,7 @@ DUK_INTERNAL void duk_free_hobject(duk_heap *heap, duk_hobject *h) {
* functions in the callstack.
*/
} else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
- duk_hboundfunc *f = (duk_hboundfunc *) h;
+ duk_hboundfunc *f = (duk_hboundfunc *) (void *) h;
DUK_FREE(heap, f->args);
}
@@ -46467,7 +47363,7 @@ DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
duk_small_uint_t i;
- DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
+ duk_memzero(&bd_ctx, sizeof(bd_ctx));
bd->data = (const duk_uint8_t *) duk_strings_data;
bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH;
@@ -46688,7 +47584,8 @@ DUK_LOCAL void duk__dump_type_sizes(void) {
DUK__DUMPSZ(duk_heap);
DUK__DUMPSZ(duk_activation);
DUK__DUMPSZ(duk_catcher);
- DUK__DUMPSZ(duk_strcache);
+ DUK__DUMPSZ(duk_strcache_entry);
+ DUK__DUMPSZ(duk_litcache_entry);
DUK__DUMPSZ(duk_ljstate);
DUK__DUMPSZ(duk_fixedbuffer);
DUK__DUMPSZ(duk_bitdecoder_ctx);
@@ -46897,7 +47794,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
* Zero the struct, and start initializing roughly in order
*/
- DUK_MEMZERO(res, sizeof(*res));
+ duk_memzero(res, sizeof(*res));
#if defined(DUK_USE_ASSERTIONS)
res->heap_initializing = 1;
#endif
@@ -46982,7 +47879,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
/* XXX: use the pointer as a seed for now: mix in time at least */
- /* The casts through duk_intptr_t is to avoid the following GCC warning:
+ /* The casts through duk_uintptr_t is to avoid the following GCC warning:
*
* warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
*
@@ -46993,7 +47890,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
DUK_D(DUK_DPRINT("using rom strings, force heap hash_seed to fixed value 0x%08lx", (long) DUK__FIXED_HASH_SEED));
res->hash_seed = (duk_uint32_t) DUK__FIXED_HASH_SEED;
#else /* DUK_USE_ROM_STRINGS */
- res->hash_seed = (duk_uint32_t) (duk_intptr_t) res;
+ res->hash_seed = (duk_uint32_t) (duk_uintptr_t) res;
#if !defined(DUK_USE_STRHASH_DENSE)
res->hash_seed ^= 5381; /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */
#endif
@@ -47033,17 +47930,17 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
#if defined(DUK_USE_STRTAB_PTRCOMP)
/* zero assumption */
- DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * st_initsize);
+ duk_memzero(res->strtable16, sizeof(duk_uint16_t) * st_initsize);
#else
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
{
- duk_small_uint_t i;
+ duk_uint32_t i;
for (i = 0; i < st_initsize; i++) {
res->strtable[i] = NULL;
}
}
#else
- DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * st_initsize);
+ duk_memzero(res->strtable, sizeof(duk_hstring *) * st_initsize);
#endif /* DUK_USE_EXPLICIT_NULL_INIT */
#endif /* DUK_USE_STRTAB_PTRCOMP */
@@ -47053,13 +47950,30 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
{
- duk_small_uint_t i;
+ duk_uint_t i;
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
res->strcache[i].h = NULL;
}
}
#endif
+ /*
+ * Init litcache
+ */
+#if defined(DUK_USE_LITCACHE_SIZE)
+ DUK_ASSERT(DUK_USE_LITCACHE_SIZE > 0);
+ DUK_ASSERT(DUK_IS_POWER_OF_TWO((duk_uint_t) DUK_USE_LITCACHE_SIZE));
+#if defined(DUK_USE_EXPLICIT_NULL_INIT)
+ {
+ duk_uint_t i;
+ for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) {
+ res->litcache[i].addr = NULL;
+ res->litcache[i].h = NULL;
+ }
+ }
+#endif
+#endif /* DUK_USE_LITCACHE_SIZE */
+
/* XXX: error handling is incomplete. It would be cleanest if
* there was a setjmp catchpoint, so that all init code could
* freely throw errors. If that were the case, the return code
@@ -47131,7 +48045,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
{
duk_uint64_t tmp_u64;
tmp_u64 = 0;
- DUK_MEMCPY((void *) &tmp_u64,
+ duk_memcpy((void *) &tmp_u64,
(const void *) &res,
(size_t) (sizeof(void *) >= sizeof(duk_uint64_t) ? sizeof(duk_uint64_t) : sizeof(void *)));
res->rnd_state[1] ^= tmp_u64;
@@ -47886,7 +48800,7 @@ DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop);
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
} else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
- duk_hboundfunc *f = (duk_hboundfunc *) h;
+ duk_hboundfunc *f = (duk_hboundfunc *) (void *) h;
DUK_ASSERT_HBOUNDFUNC_VALID(f);
duk__mark_tval(heap, &f->target);
duk__mark_tval(heap, &f->this_binding);
@@ -48360,7 +49274,8 @@ DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep
duk_hstring *next;
next = h->hdr.h_next;
- if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
+ if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h))
+ {
DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
count_keep++;
prev = h;
@@ -48369,13 +49284,26 @@ DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep
count_free++;
#endif
+ /* For pinned strings the refcount has been
+ * bumped. We could unbump it here before
+ * freeing, but that's actually not necessary
+ * except for assertions.
+ */
+#if 0
+ if (DUK_HSTRING_HAS_PINNED_LITERAL(h)) {
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) > 0U);
+ DUK_HSTRING_DECREF_NORZ(heap->heap_thread, h);
+ DUK_HSTRING_CLEAR_PINNED_LITERAL(h);
+ }
+#endif
#if defined(DUK_USE_REFERENCE_COUNTING)
/* Non-zero refcounts should not happen for unreachable strings,
* because we refcount finalize all unreachable objects which
* should have decreased unreachable string refcounts to zero
- * (even for cycles).
+ * (even for cycles). However, pinned strings have a +1 bump.
*/
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
+ DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) ==
+ DUK_HSTRING_HAS_PINNED_LITERAL(h) ? 1U : 0U);
#endif
/* Deal with weak references first. */
@@ -48579,6 +49507,26 @@ DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_small_uint_t flags, duk_size_
}
/*
+ * Litcache helpers.
+ */
+
+#if defined(DUK_USE_LITCACHE_SIZE)
+DUK_LOCAL void duk__wipe_litcache(duk_heap *heap) {
+ duk_uint_t i;
+ duk_litcache_entry *e;
+
+ e = heap->litcache;
+ for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) {
+ e->addr = NULL;
+ /* e->h does not need to be invalidated: when e->addr is
+ * NULL, e->h is considered garbage.
+ */
+ e++;
+ }
+}
+#endif /* DUK_USE_LITCACHE_SIZE */
+
+/*
* Object compaction.
*
* Compaction is assumed to never throw an error.
@@ -48762,6 +49710,7 @@ DUK_LOCAL void duk__clear_assert_refcounts(duk_heap *heap) {
DUK_LOCAL void duk__check_refcount_heaphdr(duk_heaphdr *hdr) {
duk_bool_t count_ok;
+ duk_size_t expect_refc;
/* The refcount check only makes sense for reachable objects on
* heap_allocated or string table, after the sweep phase. Prior to
@@ -48778,7 +49727,11 @@ DUK_LOCAL void duk__check_refcount_heaphdr(duk_heaphdr *hdr) {
*/
DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr));
- count_ok = ((duk_size_t) DUK_HEAPHDR_GET_REFCOUNT(hdr) == hdr->h_assert_refcount);
+ expect_refc = hdr->h_assert_refcount;
+ if (DUK_HEAPHDR_IS_STRING(hdr) && DUK_HSTRING_HAS_PINNED_LITERAL((duk_hstring *) hdr)) {
+ expect_refc++;
+ }
+ count_ok = ((duk_size_t) DUK_HEAPHDR_GET_REFCOUNT(hdr) == expect_refc);
if (!count_ok) {
DUK_D(DUK_DPRINT("refcount mismatch for: %p: header=%ld counted=%ld --> %!iO",
(void *) hdr, (long) DUK_HEAPHDR_GET_REFCOUNT(hdr),
@@ -48815,6 +49768,22 @@ DUK_LOCAL void duk__check_assert_refcounts(duk_heap *heap) {
}
}
#endif /* DUK_USE_REFERENCE_COUNTING */
+
+#if defined(DUK_USE_LITCACHE_SIZE)
+DUK_LOCAL void duk__assert_litcache_nulls(duk_heap *heap) {
+ duk_uint_t i;
+ duk_litcache_entry *e;
+
+ e = heap->litcache;
+ for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) {
+ /* Entry addresses were NULLed before mark-and-sweep, check
+ * that they're still NULL afterwards to ensure no pointers
+ * were recorded through any side effects.
+ */
+ DUK_ASSERT(e->addr == NULL);
+ }
+}
+#endif /* DUK_USE_LITCACHE_SIZE */
#endif /* DUK_USE_ASSERTIONS */
/*
@@ -48835,10 +49804,13 @@ DUK_LOCAL void duk__dump_stats(duk_heap *heap) {
DUK_D(DUK_DPRINT("stats mark-and-sweep: try_count=%ld, skip_count=%ld, emergency_count=%ld",
(long) heap->stats_ms_try_count, (long) heap->stats_ms_skip_count,
(long) heap->stats_ms_emergency_count));
- DUK_D(DUK_DPRINT("stats stringtable: intern_hit=%ld, intern_miss=%ld, resize_check=%ld, resize_grow=%ld, resize_shrink=%ld",
+ DUK_D(DUK_DPRINT("stats stringtable: intern_hit=%ld, intern_miss=%ld, "
+ "resize_check=%ld, resize_grow=%ld, resize_shrink=%ld, "
+ "litcache_hit=%ld, litcache_miss=%ld, litcache_pin=%ld",
(long) heap->stats_strtab_intern_hit, (long) heap->stats_strtab_intern_miss,
(long) heap->stats_strtab_resize_check, (long) heap->stats_strtab_resize_grow,
- (long) heap->stats_strtab_resize_shrink));
+ (long) heap->stats_strtab_resize_shrink, (long) heap->stats_strtab_litcache_hit,
+ (long) heap->stats_strtab_litcache_miss, (long) heap->stats_strtab_litcache_pin));
DUK_D(DUK_DPRINT("stats object: realloc_props=%ld, abandon_array=%ld",
(long) heap->stats_object_realloc_props, (long) heap->stats_object_abandon_array));
DUK_D(DUK_DPRINT("stats getownpropdesc: count=%ld, hit=%ld, miss=%ld",
@@ -48979,6 +49951,9 @@ DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags
#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
duk__clear_assert_refcounts(heap);
#endif
+#if defined(DUK_USE_LITCACHE_SIZE)
+ duk__wipe_litcache(heap);
+#endif
duk__mark_roots_heap(heap); /* Mark main reachability roots. */
#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */
@@ -49084,6 +50059,9 @@ DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags
*/
duk__assert_valid_refcounts(heap);
#endif /* DUK_USE_REFERENCE_COUNTING */
+#if defined(DUK_USE_LITCACHE_SIZE)
+ duk__assert_litcache_nulls(heap);
+#endif /* DUK_USE_LITCACHE_SIZE */
#endif /* DUK_USE_ASSERTIONS */
/*
@@ -49273,8 +50251,7 @@ DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) {
res = DUK_ALLOC(heap, size);
if (DUK_LIKELY(res != NULL)) {
- /* assume memset with zero size is OK */
- DUK_MEMZERO(res, size);
+ duk_memzero(res, size);
}
return res;
}
@@ -49288,7 +50265,7 @@ DUK_INTERNAL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size)
return res;
}
DUK_ERROR_ALLOC_FAILED(thr);
- return NULL;
+ DUK_WO_NORETURN(return NULL;);
}
DUK_INTERNAL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size) {
@@ -49300,7 +50277,7 @@ DUK_INTERNAL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_
return res;
}
DUK_ERROR_ALLOC_FAILED(thr);
- return NULL;
+ DUK_WO_NORETURN(return NULL;);
}
/*
@@ -49863,7 +50840,7 @@ DUK_INTERNAL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) b->buf_prop);
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
} else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
- duk_hboundfunc *f = (duk_hboundfunc *) h;
+ duk_hboundfunc *f = (duk_hboundfunc *) (void *) h;
DUK_ASSERT_HBOUNDFUNC_VALID(f);
DUK_TVAL_DECREF_NORZ(thr, &f->target);
DUK_TVAL_DECREF_NORZ(thr, &f->this_binding);
@@ -50553,9 +51530,9 @@ DUK_INTERNAL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h) {
*/
DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h) {
- duk_small_int_t i;
+ duk_uint_t i;
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
- duk_strcache *c = heap->strcache + i;
+ duk_strcache_entry *c = heap->strcache + i;
if (c->h == h) {
DUK_DD(DUK_DDPRINT("deleting weak strcache reference to hstring %p from heap %p",
(void *) h, (void *) heap));
@@ -50627,9 +51604,9 @@ DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk
DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) {
duk_heap *heap;
- duk_strcache *sce;
+ duk_strcache_entry *sce;
duk_uint_fast32_t byte_offset;
- duk_small_int_t i;
+ duk_uint_t i;
duk_bool_t use_cache;
duk_uint_fast32_t dist_start, dist_end, dist_sce;
duk_uint_fast32_t char_length;
@@ -50680,14 +51657,14 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):"));
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
- duk_strcache *c = heap->strcache + i;
+ duk_strcache_entry *c = heap->strcache + i;
DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
(long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
}
#endif
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
- duk_strcache *c = heap->strcache + i;
+ duk_strcache_entry *c = heap->strcache + i;
if (c->h == h) {
sce = c;
@@ -50816,10 +51793,10 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
* C <- sce ==> B
* D D
*/
- duk_strcache tmp;
+ duk_strcache_entry tmp;
tmp = *sce;
- DUK_MEMMOVE((void *) (&heap->strcache[1]),
+ duk_memmove((void *) (&heap->strcache[1]),
(const void *) (&heap->strcache[0]),
(size_t) (((char *) sce) - ((char *) &heap->strcache[0])));
heap->strcache[0] = tmp;
@@ -50829,7 +51806,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):"));
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
- duk_strcache *c = heap->strcache + i;
+ duk_strcache_entry *c = heap->strcache + i;
DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
(long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
}
@@ -50840,7 +51817,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
scan_error:
DUK_ERROR_INTERNAL(thr);
- return 0;
+ DUK_WO_NORETURN(return 0;);
}
/*
* Heap string table handling, string interning.
@@ -50898,7 +51875,7 @@ DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap) {
return;
}
- DUK_MEMZERO((void *) count_len, sizeof(count_len));
+ duk_memzero((void *) count_len, sizeof(count_len));
for (i = 0; i < heap->st_size; i++) {
h = DUK__HEAPPTR_DEC16(heap, strtable[i]);
count_chain = 0;
@@ -51010,7 +51987,7 @@ DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap,
if (DUK_UNLIKELY(res == NULL)) {
goto alloc_error;
}
- DUK_MEMZERO(res, sizeof(duk_hstring_external));
+ duk_memzero(res, sizeof(duk_hstring_external));
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
#endif
@@ -51030,14 +52007,14 @@ DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap,
if (DUK_UNLIKELY(res == NULL)) {
goto alloc_error;
}
- DUK_MEMZERO(res, sizeof(duk_hstring));
+ duk_memzero(res, sizeof(duk_hstring));
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
#endif
DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0);
data_tmp = (duk_uint8_t *) (res + 1);
- DUK_MEMCPY(data_tmp, str, blen);
+ duk_memcpy(data_tmp, str, blen);
data_tmp[blen] = (duk_uint8_t) 0;
data = (const duk_uint8_t *) data_tmp;
}
@@ -51530,11 +52507,12 @@ DUK_LOCAL duk_hstring *duk__strtab_romstring_lookup(duk_heap *heap, const duk_ui
}
lookup_hash &= 0xff;
- curr = DUK_LOSE_CONST(duk_rom_strings_lookup[lookup_hash]);
+ curr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_lookup[lookup_hash]);
while (curr != NULL) {
+ /* Unsafe memcmp() because for zero blen, str may be NULL. */
if (strhash == DUK_HSTRING_GET_HASH(curr) &&
blen == DUK_HSTRING_GET_BYTELEN(curr) &&
- DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) {
+ duk_memcmp_unsafe((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) {
DUK_DDD(DUK_DDDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx",
curr, (unsigned long) strhash, (unsigned long) DUK_HSTRING_GET_HASH(curr)));
return curr;
@@ -51554,6 +52532,7 @@ DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uin
/* Preliminaries. */
+ /* XXX: maybe just require 'str != NULL' even for zero size? */
DUK_ASSERT(heap != NULL);
DUK_ASSERT(blen == 0 || str != NULL);
DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); /* Caller is responsible for ensuring this. */
@@ -51572,7 +52551,7 @@ DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uin
while (h != NULL) {
if (DUK_HSTRING_GET_HASH(h) == strhash &&
DUK_HSTRING_GET_BYTELEN(h) == blen &&
- DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
+ duk_memcmp_unsafe((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
/* Found existing entry. */
DUK_STATS_INC(heap, stats_strtab_intern_hit);
return h;
@@ -51645,10 +52624,67 @@ DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, con
res = duk_heap_strtable_intern(thr->heap, str, blen);
if (DUK_UNLIKELY(res == NULL)) {
DUK_ERROR_ALLOC_FAILED(thr);
+ DUK_WO_NORETURN(return NULL;);
}
return res;
}
+#if defined(DUK_USE_LITCACHE_SIZE)
+DUK_LOCAL duk_uint_t duk__strtable_litcache_key(const duk_uint8_t *str, duk_uint32_t blen) {
+ duk_uintptr_t key;
+
+ DUK_ASSERT(DUK_USE_LITCACHE_SIZE > 0);
+ DUK_ASSERT(DUK_IS_POWER_OF_TWO((duk_uint_t) DUK_USE_LITCACHE_SIZE));
+
+ key = (duk_uintptr_t) blen ^ (duk_uintptr_t) str;
+ key &= (duk_uintptr_t) (DUK_USE_LITCACHE_SIZE - 1); /* Assumes size is power of 2. */
+ /* Due to masking, cast is in 32-bit range. */
+ DUK_ASSERT(key <= DUK_UINT_MAX);
+ return (duk_uint_t) key;
+}
+
+DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_literal_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) {
+ duk_uint_t key;
+ duk_litcache_entry *ent;
+ duk_hstring *h;
+
+ /* Fast path check: literal exists in literal cache. */
+ key = duk__strtable_litcache_key(str, blen);
+ ent = thr->heap->litcache + key;
+ if (ent->addr == str) {
+ DUK_DD(DUK_DDPRINT("intern check for cached, pinned literal: str=%p, blen=%ld -> duk_hstring %!O",
+ (const void *) str, (long) blen, (duk_heaphdr *) ent->h));
+ DUK_ASSERT(ent->h != NULL);
+ DUK_ASSERT(DUK_HSTRING_HAS_PINNED_LITERAL(ent->h));
+ DUK_STATS_INC(thr->heap, stats_strtab_litcache_hit);
+ return ent->h;
+ }
+
+ /* Intern and update (overwrite) cache entry. */
+ h = duk_heap_strtable_intern_checked(thr, str, blen);
+ ent->addr = str;
+ ent->h = h;
+ DUK_STATS_INC(thr->heap, stats_strtab_litcache_miss);
+
+ /* Pin the duk_hstring until the next mark-and-sweep. This means
+ * litcache entries don't need to be invalidated until the next
+ * mark-and-sweep as their target duk_hstring is not freed before
+ * the mark-and-sweep happens. The pin remains even if the literal
+ * cache entry is overwritten, and is still useful to avoid string
+ * table traffic.
+ */
+ if (!DUK_HSTRING_HAS_PINNED_LITERAL(h)) {
+ DUK_DD(DUK_DDPRINT("pin duk_hstring because it is a literal: %!O", (duk_heaphdr *) h));
+ DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
+ DUK_HSTRING_INCREF(thr, h);
+ DUK_HSTRING_SET_PINNED_LITERAL(h);
+ DUK_STATS_INC(thr->heap, stats_strtab_litcache_pin);
+ }
+
+ return h;
+}
+#endif /* DUK_USE_LITCACHE_SIZE */
+
DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) {
duk_hstring *res;
@@ -51658,6 +52694,7 @@ DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr,
res = duk_heap_strtable_intern_u32(thr->heap, val);
if (DUK_UNLIKELY(res == NULL)) {
DUK_ERROR_ALLOC_FAILED(thr);
+ DUK_WO_NORETURN(return NULL;);
}
return res;
}
@@ -51963,7 +53000,7 @@ DUK_INTERNAL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hob
if (!res) {
return NULL;
}
- DUK_MEMZERO(res, sizeof(duk_hboundfunc));
+ duk_memzero(res, sizeof(duk_hboundfunc));
duk__init_object_parts(heap, hobject_flags, &res->obj);
@@ -52005,7 +53042,7 @@ DUK_INTERNAL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t
if (DUK_UNLIKELY(res == NULL)) {
return NULL;
}
- DUK_MEMZERO(res, sizeof(duk_hthread));
+ duk_memzero(res, sizeof(duk_hthread));
duk__init_object_parts(heap, hobject_flags, &res->obj);
@@ -52047,6 +53084,7 @@ DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject
res = duk_hthread_alloc_unchecked(thr->heap, hobject_flags);
if (res == NULL) {
DUK_ERROR_ALLOC_FAILED(thr);
+ DUK_WO_NORETURN(return NULL;);
}
return res;
}
@@ -52262,7 +53300,7 @@ DUK_LOCAL void duk__sort_enum_keys_es6(duk_hthread *thr, duk_hobject *h_obj, duk
* are very often in order already.
*/
if (idx != idx_insert) {
- DUK_MEMMOVE((void *) (keys + idx_insert + 1),
+ duk_memmove((void *) (keys + idx_insert + 1),
(const void *) (keys + idx_insert),
((size_t) (idx - idx_insert) * sizeof(duk_hstring *)));
keys[idx_insert] = h_curr;
@@ -52746,7 +53784,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t
}
/*
- * Get enumerated keys in an Ecmascript array. Matches Object.keys() behavior
+ * Get enumerated keys in an ECMAScript array. Matches Object.keys() behavior
* described in E5 Section 15.2.3.14.
*/
@@ -52832,6 +53870,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, d
break;
} else {
DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
+ DUK_WO_NORETURN(return 0;);
}
}
h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
@@ -52915,7 +53954,7 @@ DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr
(long) hdr[hdr_index + 1]));
#endif
- DUK_MEMZERO(be_ctx, sizeof(*be_ctx));
+ duk_memzero(be_ctx, sizeof(*be_ctx));
be_ctx->data = ((duk_uint8_t *) hdr) + curr_offset;
be_ctx->length = (duk_size_t) DUK_PC2LINE_MAX_DIFF_LENGTH;
@@ -53026,7 +54065,7 @@ DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk
* Iterate the bitstream (line diffs) until PC is reached
*/
- DUK_MEMZERO(bd_ctx, sizeof(*bd_ctx));
+ duk_memzero(bd_ctx, sizeof(*bd_ctx));
bd_ctx->data = ((duk_uint8_t *) hdr) + start_offset;
bd_ctx->length = (duk_size_t) (DUK_HBUFFER_FIXED_GET_SIZE(buf) - start_offset);
@@ -53086,7 +54125,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_i
*/
duk_get_prop_stridx(thr, idx_func, DUK_STRIDX_INT_PC2LINE);
- pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(thr, -1);
+ pc2line = (duk_hbuffer_fixed *) (void *) duk_get_hbuffer(thr, -1);
if (pc2line != NULL) {
DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) pc2line));
line = duk__hobject_pc2line_query_raw(thr, pc2line, (duk_uint_fast32_t) pc);
@@ -53154,7 +54193,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_i
#define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED
/* Valstack space that suffices for all local calls, excluding any recursion
- * into Ecmascript or Duktape/C calls (Proxy, getters, etc).
+ * into ECMAScript or Duktape/C calls (Proxy, getters, etc).
*/
#define DUK__VALSTACK_SPACE 10
@@ -53704,6 +54743,7 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
if (new_e_size_adjusted + new_a_size > DUK_HOBJECT_MAX_PROPERTIES) {
DUK_ERROR_ALLOC_FAILED(thr);
+ DUK_WO_NORETURN(return;);
}
/*
@@ -53907,18 +54947,14 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
} else {
array_copy_size = sizeof(duk_tval) * new_a_size;
}
- if (array_copy_size > 0) {
- /* Avoid zero copy with an invalid pointer. If obj->p is NULL,
- * the 'new_a' pointer will be invalid which is not allowed even
- * when copy size is zero.
- */
- DUK_ASSERT(new_a != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0);
- DUK_MEMCPY((void *) new_a,
- (const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj),
- array_copy_size);
- }
+
+ DUK_ASSERT(new_a != NULL || array_copy_size == 0U);
+ DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || array_copy_size == 0U);
+ DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0 || array_copy_size == 0U);
+ duk_memcpy_unsafe((void *) new_a,
+ (const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj),
+ array_copy_size);
+
for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) {
duk_tval *tv = &new_a[i];
DUK_TVAL_SET_UNUSED(tv);
@@ -53943,7 +54979,7 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
/* fill new_h with u32 0xff = UNUSED */
DUK_ASSERT(new_h_size > 0);
- DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size);
+ duk_memset(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size);
DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */
@@ -54053,6 +55089,7 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
#endif
DUK_ERROR_ALLOC_FAILED(thr);
+ DUK_WO_NORETURN(return;);
}
/*
@@ -54530,7 +55567,7 @@ DUK_INTERNAL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap,
/* This is not strictly necessary, but avoids compiler warnings; e.g.
* gcc won't reliably detect that no uninitialized data is read below.
*/
- DUK_MEMZERO((void *) &tv, sizeof(duk_tval));
+ duk_memzero((void *) &tv, sizeof(duk_tval));
if (duk_hobject_get_internal_value(heap, obj, &tv)) {
duk_hstring *h;
@@ -54718,7 +55755,7 @@ DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject
}
/*
- * Ecmascript compliant [[GetOwnProperty]](P), for internal use only.
+ * ECMAScript compliant [[GetOwnProperty]](P), for internal use only.
*
* If property is found:
* - Fills descriptor fields to 'out_desc'
@@ -55093,7 +56130,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobje
}
/*
- * Ecmascript compliant [[GetProperty]](P), for internal use only.
+ * ECMAScript compliant [[GetProperty]](P), for internal use only.
*
* If property is found:
* - Fills descriptor fields to 'out_desc'
@@ -55150,6 +56187,7 @@ DUK_LOCAL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_h
break;
} else {
DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
+ DUK_WO_NORETURN(return 0;);
}
}
curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
@@ -55431,7 +56469,7 @@ DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hob
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/*
- * GETPROP: Ecmascript property read.
+ * GETPROP: ECMAScript property read.
*/
DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
@@ -55485,7 +56523,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot read property %s of %s",
duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
#endif
- return 0;
+ DUK_WO_NORETURN(return 0;);
+ break;
}
case DUK_TAG_BOOLEAN: {
@@ -55641,6 +56680,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
!DUK_TVAL_IS_UNDEFINED(tv_hook);
if (datadesc_reject || accdesc_reject) {
DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
+ DUK_WO_NORETURN(return 0;);
}
duk_pop_2_unsafe(thr);
@@ -55832,6 +56872,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
*/
if (DUK_UNLIKELY(sanity-- == 0)) {
DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
+ DUK_WO_NORETURN(return 0;);
}
curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
} while (curr != NULL);
@@ -55902,6 +56943,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_HOBJECT_HAS_STRICT(h)) {
/* XXX: sufficient to check 'strict', assert for 'is function' */
DUK_ERROR_TYPE(thr, DUK_STR_STRICT_CALLER_READ);
+ DUK_WO_NORETURN(return 0;);
}
}
}
@@ -55914,7 +56956,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
}
/*
- * HASPROP: Ecmascript property existence check ("in" operator).
+ * HASPROP: ECMAScript property existence check ("in" operator).
*
* Interestingly, the 'in' operator does not do any coercion of
* the target object.
@@ -55980,6 +57022,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
/* Note: unconditional throw */
DUK_DDD(DUK_DDDPRINT("base object is not an object -> reject"));
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
+ DUK_WO_NORETURN(return 0;);
}
/* XXX: fast path for arrays? */
@@ -56004,7 +57047,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
duk_push_hobject(thr, h_target); /* target */
duk_push_tval(thr, tv_key); /* P */
duk_call_method(thr, 2 /*nargs*/);
- tmp_bool = duk_to_boolean(thr, -1);
+ tmp_bool = duk_to_boolean_top_pop(thr);
if (!tmp_bool) {
/* Target object must be checked for a conflicting
* non-configurable property.
@@ -56023,11 +57066,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj,
if (!((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && /* property is configurable and */
DUK_HOBJECT_HAS_EXTENSIBLE(h_target))) { /* ... target is extensible */
DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
+ DUK_WO_NORETURN(return 0;);
}
}
}
- duk_pop_2_unsafe(thr); /* [ key trap_result ] -> [] */
+ duk_pop_unsafe(thr); /* [ key ] -> [] */
return tmp_bool;
}
@@ -56119,7 +57163,7 @@ DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr, duk_tv
/* Refuse to update an Array's 'length' to a value outside the
* 32-bit range. Negative zero is accepted as zero.
*/
- res = (duk_uint32_t) d;
+ res = duk_double_to_uint32_t(d);
if ((duk_double_t) res != d) {
goto fail_range;
}
@@ -56128,7 +57172,7 @@ DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr, duk_tv
fail_range:
DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH);
- return 0; /* unreachable */
+ DUK_WO_NORETURN(return 0;);
}
/* Delete elements required by a smaller length, taking into account
@@ -56397,9 +57441,9 @@ DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject
}
/*
- * PUTPROP: Ecmascript property write.
+ * PUTPROP: ECMAScript property write.
*
- * Unlike Ecmascript primitive which returns nothing, returns 1 to indicate
+ * Unlike ECMAScript primitive which returns nothing, returns 1 to indicate
* success and 0 to indicate failure (assuming throw is not set).
*
* This is an extremely tricky function. Some examples:
@@ -56486,7 +57530,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
#endif
- return 0;
+ DUK_WO_NORETURN(return 0;);
+ break;
}
case DUK_TAG_BOOLEAN: {
@@ -56590,8 +57635,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
duk_push_tval(thr, tv_val); /* V */
duk_push_tval(thr, tv_obj); /* Receiver: Proxy object */
duk_call_method(thr, 4 /*nargs*/);
- tmp_bool = duk_to_boolean(thr, -1);
- duk_pop_nodecref_unsafe(thr);
+ tmp_bool = duk_to_boolean_top_pop(thr);
if (!tmp_bool) {
goto fail_proxy_rejected;
}
@@ -56623,6 +57667,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
(desc.set == NULL);
if (datadesc_reject || accdesc_reject) {
DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
+ DUK_WO_NORETURN(return 0;);
}
duk_pop_2_unsafe(thr);
@@ -56922,6 +57967,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
*/
if (DUK_UNLIKELY(sanity-- == 0)) {
DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
+ DUK_WO_NORETURN(return 0;);
}
curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
} while (curr != NULL);
@@ -57271,6 +58317,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_DDD(DUK_DDDPRINT("result: error, proxy rejects"));
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
+ DUK_WO_NORETURN(return 0;);
}
/* Note: no key on stack */
return 0;
@@ -57285,6 +58332,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
#endif
+ DUK_WO_NORETURN(return 0;);
}
duk_pop_unsafe(thr); /* remove key */
return 0;
@@ -57293,6 +58341,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_DDD(DUK_DDDPRINT("result: error, not extensible"));
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
+ DUK_WO_NORETURN(return 0;);
}
duk_pop_unsafe(thr); /* remove key */
return 0;
@@ -57301,6 +58350,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
+ DUK_WO_NORETURN(return 0;);
}
duk_pop_unsafe(thr); /* remove key */
return 0;
@@ -57310,6 +58360,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
+ DUK_WO_NORETURN(return 0;);
}
return 0;
#endif
@@ -57318,6 +58369,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_DD(DUK_DDPRINT("result: error, array length write only partially successful"));
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
+ DUK_WO_NORETURN(return 0;);
}
duk_pop_unsafe(thr); /* remove key */
return 0;
@@ -57326,6 +58378,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_DDD(DUK_DDDPRINT("result: error, accessor property without setter"));
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_SETTER_UNDEFINED);
+ DUK_WO_NORETURN(return 0;);
}
duk_pop_unsafe(thr); /* remove key */
return 0;
@@ -57334,13 +58387,14 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_DDD(DUK_DDDPRINT("result: error, internal"));
if (throw_flag) {
DUK_ERROR_INTERNAL(thr);
+ DUK_WO_NORETURN(return 0;);
}
duk_pop_unsafe(thr); /* remove key */
return 0;
}
/*
- * Ecmascript compliant [[Delete]](P, Throw).
+ * ECMAScript compliant [[Delete]](P, Throw).
*/
DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
@@ -57494,12 +58548,13 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
+ DUK_WO_NORETURN(return 0;);
}
return 0;
}
/*
- * DELPROP: Ecmascript property deletion.
+ * DELPROP: ECMAScript property deletion.
*/
DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag) {
@@ -57554,8 +58609,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
duk_push_hobject(thr, h_target); /* target */
duk_dup_m4(thr); /* P */
duk_call_method(thr, 2 /*nargs*/);
- tmp_bool = duk_to_boolean(thr, -1);
- duk_pop_nodecref_unsafe(thr);
+ tmp_bool = duk_to_boolean_top_pop(thr);
if (!tmp_bool) {
goto fail_proxy_rejected; /* retval indicates delete failed */
}
@@ -57580,6 +58634,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
if (desc_reject) {
/* unconditional */
DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
+ DUK_WO_NORETURN(return 0;);
}
}
rc = 1; /* success */
@@ -57663,12 +58718,13 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot delete property %s of %s",
duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
#endif
- return 0;
+ DUK_WO_NORETURN(return 0;);
#if defined(DUK_USE_ES6_PROXY)
fail_proxy_rejected:
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
+ DUK_WO_NORETURN(return 0;);
}
duk_set_top_unsafe(thr, entry_top);
return 0;
@@ -57677,6 +58733,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj,
fail_not_configurable:
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
+ DUK_WO_NORETURN(return 0;);
}
duk_set_top_unsafe(thr, entry_top);
return 0;
@@ -57816,7 +58873,7 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
error_virtual: /* share error message */
error_internal:
DUK_ERROR_INTERNAL(thr);
- return;
+ DUK_WO_NORETURN(return;);
}
/*
@@ -57896,7 +58953,7 @@ DUK_INTERNAL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *ob
val = duk_to_number_m1(thr);
duk_pop_3_unsafe(thr);
- /* This isn't part of Ecmascript semantics; return a value within
+ /* This isn't part of ECMAScript semantics; return a value within
* duk_size_t range, or 0 otherwise.
*/
if (val >= 0.0 && val <= (duk_double_t) DUK_SIZE_MAX) {
@@ -58007,7 +59064,7 @@ DUK_INTERNAL void duk_hobject_object_get_own_property_descriptor(duk_hthread *th
* NormalizePropertyDescriptor() related helper.
*
* Internal helper which validates and normalizes a property descriptor
- * represented as an Ecmascript object (e.g. argument to defineProperty()).
+ * represented as an ECMAScript object (e.g. argument to defineProperty()).
* The output of this conversion is a set of defprop_flags and possibly
* some values pushed on the value stack to (1) ensure borrowed pointers
* remain valid, and (2) avoid unnecessary pops for footprint reasons.
@@ -58057,7 +59114,7 @@ void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_WRITABLE)) {
is_data_desc = 1;
- if (duk_to_boolean(thr, -1)) {
+ if (duk_to_boolean_top_pop(thr)) {
defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE;
} else {
defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE;
@@ -58109,7 +59166,7 @@ void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
}
if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_ENUMERABLE)) {
- if (duk_to_boolean(thr, -1)) {
+ if (duk_to_boolean_top_pop(thr)) {
defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE;
} else {
defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE;
@@ -58117,7 +59174,7 @@ void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
}
if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_CONFIGURABLE)) {
- if (duk_to_boolean(thr, -1)) {
+ if (duk_to_boolean_top_pop(thr)) {
defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE;
} else {
defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE;
@@ -58138,6 +59195,7 @@ void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
type_error:
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
+ DUK_WO_NORETURN(return;);
}
/*
@@ -58146,7 +59204,7 @@ void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
*
* Inlines all [[DefineOwnProperty]] exotic behaviors.
*
- * Note: Ecmascript compliant [[DefineOwnProperty]](P, Desc, Throw) is not
+ * Note: ECMAScript compliant [[DefineOwnProperty]](P, Desc, Throw) is not
* implemented directly, but Object.defineProperty() serves its purpose.
* We don't need the [[DefineOwnProperty]] internally and we don't have a
* property descriptor with 'missing values' so it's easier to avoid it
@@ -59019,6 +60077,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
fail_not_extensible:
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
+ DUK_WO_NORETURN(return 0;);
}
return 0;
@@ -59026,6 +60085,7 @@ duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
fail_not_configurable:
if (throw_flag) {
DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
+ DUK_WO_NORETURN(return 0;);
}
return 0;
}
@@ -59081,6 +60141,7 @@ DUK_INTERNAL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_ho
if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
DUK_DD(DUK_DDPRINT("attempt to seal/freeze a readonly object, reject"));
DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
+ DUK_WO_NORETURN(return;);
}
#endif
@@ -59228,7 +60289,7 @@ DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk
(const void *) p_start, (const void *) p_end,
(const void *) p));
- /* For invalid UTF-8 (never happens for standard Ecmascript strings)
+ /* For invalid UTF-8 (never happens for standard ECMAScript strings)
* return U+FFFD replacement character.
*/
if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp1)) {
@@ -59384,7 +60445,7 @@ DUK_INTERNAL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const c
if (len != DUK_HSTRING_GET_BYTELEN(h)) {
return 0;
}
- if (DUK_MEMCMP((const void *) cstr, (const void *) DUK_HSTRING_GET_DATA(h), len) == 0) {
+ if (duk_memcmp((const void *) cstr, (const void *) DUK_HSTRING_GET_DATA(h), len) == 0) {
return 1;
}
return 0;
@@ -59421,7 +60482,7 @@ DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr
if (!thr->valstack) {
goto fail;
}
- DUK_MEMZERO(thr->valstack, alloc_size);
+ duk_memzero(thr->valstack, alloc_size);
thr->valstack_end = thr->valstack + DUK_VALSTACK_API_ENTRY_MINIMUM;
thr->valstack_alloc_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE;
thr->valstack_bottom = thr->valstack;
@@ -59525,7 +60586,7 @@ DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
props = DUK_ALLOC_CHECKED(thr, alloc_size);
DUK_ASSERT(props != NULL);
DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal) != NULL);
- DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size);
+ duk_memcpy((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size);
/* XXX: keep property attributes or tweak them here?
* Properties will now be non-configurable even when they're
@@ -59652,7 +60713,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
DUK_D(DUK_DPRINT("INITBUILTINS BEGIN: DUK_NUM_BUILTINS=%d, DUK_NUM_BUILTINS_ALL=%d", (int) DUK_NUM_BUILTINS, (int) DUK_NUM_ALL_BUILTINS));
- DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
+ duk_memzero(&bd_ctx, sizeof(bd_ctx));
bd->data = (const duk_uint8_t *) duk_builtins_data;
bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH;
@@ -59894,11 +60955,9 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
* signaled using a single flag bit in the bitstream.
*/
- if (duk_bd_decode_flag(bd)) {
- defprop_flags = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_FLAGS_BITS);
- } else {
- defprop_flags = DUK_PROPDESC_FLAGS_WC;
- }
+ defprop_flags = (duk_small_uint_t) duk_bd_decode_flagged(bd,
+ DUK__PROP_FLAGS_BITS,
+ (duk_uint32_t) DUK_PROPDESC_FLAGS_WC);
defprop_flags |= DUK_DEFPROP_FORCE |
DUK_DEFPROP_HAVE_VALUE |
DUK_DEFPROP_HAVE_WRITABLE |
@@ -60003,6 +61062,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
duk_small_int_t lightfunc_eligible;
#endif
+ duk_small_uint_t defprop_flags;
duk__push_stridx_or_string(thr, bd);
h_key = duk_known_hstring(thr, -1);
@@ -60122,10 +61182,19 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
lightfunc_skip:
#endif
- /* XXX: So far all ES builtins are 'wc' but e.g.
- * performance.now() should be 'wec'.
- */
- duk_xdef_prop(thr, (duk_idx_t) i, DUK_PROPDESC_FLAGS_WC);
+ defprop_flags = (duk_small_uint_t) duk_bd_decode_flagged(bd,
+ DUK__PROP_FLAGS_BITS,
+ (duk_uint32_t) DUK_PROPDESC_FLAGS_WC);
+ defprop_flags |= DUK_DEFPROP_FORCE |
+ DUK_DEFPROP_HAVE_VALUE |
+ DUK_DEFPROP_HAVE_WRITABLE |
+ DUK_DEFPROP_HAVE_ENUMERABLE |
+ DUK_DEFPROP_HAVE_CONFIGURABLE;
+ DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE);
+ DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE);
+ DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE);
+
+ duk_def_prop(thr, (duk_idx_t) i, defprop_flags);
/* [ (builtin objects) ] */
}
@@ -60198,7 +61267,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
"f"
#endif
" "
- /* Low memory options */
+ /* Low memory/performance options */
#if defined(DUK_USE_STRTAB_PTRCOMP)
"s"
#endif
@@ -60239,6 +61308,9 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
*/
"Z"
#endif
+#if defined(DUK_USE_LITCACHE_SIZE)
+ "l"
+#endif
" "
/* Object property allocation layout */
#if defined(DUK_USE_HOBJECT_LAYOUT_1)
@@ -60813,8 +61885,8 @@ DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) {
/* Use DUK_ALLOC_RAW() to avoid side effects. */
new_ptr = (duk_tval *) DUK_ALLOC_RAW(thr->heap, alloc_size);
if (new_ptr != NULL) {
- DUK_MEMCPY((void *) new_ptr, (const void *) thr->valstack, alloc_size);
- DUK_MEMSET((void *) thr->valstack, 0x55, alloc_size);
+ duk_memcpy((void *) new_ptr, (const void *) thr->valstack, alloc_size);
+ duk_memset((void *) thr->valstack, 0x55, alloc_size);
DUK_FREE_CHECKED(thr, (void *) thr->valstack);
thr->valstack = new_ptr;
thr->valstack_alloc_end = (duk_tval *) ((duk_uint8_t *) new_ptr + alloc_end_off);
@@ -60832,7 +61904,7 @@ DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) {
/* #include duk_internal.h -> already included */
-/* Ecmascript modulus ('%') does not match IEEE 754 "remainder" operation
+/* ECMAScript modulus ('%') does not match IEEE 754 "remainder" operation
* (implemented by remainder() in C99) but does seem to match ANSI C fmod().
* Compare E5 Section 11.5.3 and "man fmod".
*/
@@ -60886,9 +61958,9 @@ DUK_INTERNAL double duk_js_arith_mod(double d1, double d2) {
/* Shared helper for Math.pow() and exponentiation operator. */
DUK_INTERNAL double duk_js_arith_pow(double x, double y) {
- /* The ANSI C pow() semantics differ from Ecmascript.
+ /* The ANSI C pow() semantics differ from ECMAScript.
*
- * E.g. when x==1 and y is +/- infinite, the Ecmascript required
+ * E.g. when x==1 and y is +/- infinite, the ECMAScript required
* result is NaN, while at least Linux pow() returns 1.
*/
@@ -60968,7 +62040,7 @@ DUK_INTERNAL double duk_js_arith_pow(double x, double y) {
*
* duk_handle_call_unprotected():
*
- * - Unprotected call to Ecmascript or Duktape/C function, from native
+ * - Unprotected call to ECMAScript or Duktape/C function, from native
* code or bytecode executor.
*
* - Also handles Ecma-to-Ecma calls which reuses a currently running
@@ -61022,6 +62094,7 @@ DUK_LOCAL DUK_NOINLINE void duk__call_c_recursion_limit_check_slowpath(duk_hthre
DUK_D(DUK_DPRINT("call prevented because C recursion limit reached"));
DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
+ DUK_WO_NORETURN(return;);
}
DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_c_recursion_limit_check(duk_hthread *thr) {
@@ -61057,6 +62130,7 @@ DUK_LOCAL DUK_NOINLINE void duk__call_callstack_limit_check_slowpath(duk_hthread
*/
DUK_D(DUK_DPRINT("call prevented because call stack limit reached"));
DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT);
+ DUK_WO_NORETURN(return;);
}
DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_callstack_limit_check(duk_hthread *thr) {
@@ -61470,6 +62544,7 @@ DUK_INTERNAL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uin
if (DUK_UNLIKELY(proxy_invariant != 0U)) {
/* Proxy 'construct' return value invariant violated. */
DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr);
+ DUK_WO_NORETURN(return;);
}
/* XXX: direct value stack access */
duk_pop(thr);
@@ -61530,7 +62605,7 @@ DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr,
duk_tval *tv_args;
duk_tval *tv_gap;
- h_bound = (duk_hboundfunc *) func;
+ h_bound = (duk_hboundfunc *) (void *) func;
tv_args = h_bound->args;
len = h_bound->nargs;
DUK_ASSERT(len == 0 || tv_args != NULL);
@@ -61570,6 +62645,7 @@ DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr,
} else {
/* Shouldn't happen, so ugly error is enough. */
DUK_ERROR_INTERNAL(thr);
+ DUK_WO_NORETURN(return;);
}
DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
@@ -61745,11 +62821,13 @@ DUK_LOCAL duk_bool_t duk__handle_specialfuncs_for_call(duk_hthread *thr, duk_idx
if (top < idx_func + 3) {
/* argArray is a mandatory argument for Reflect.construct(). */
DUK_ERROR_TYPE_INVALID_ARGS(thr);
+ DUK_WO_NORETURN(return 0;);
}
if (top > idx_func + 3) {
if (!duk_strict_equals(thr, idx_func, idx_func + 3)) {
/* XXX: [[Construct]] newTarget currently unsupported */
DUK_ERROR_UNSUPPORTED(thr);
+ DUK_WO_NORETURN(return 0;);
}
duk_set_top_unsafe(thr, idx_func + 3); /* remove any args beyond argArray */
}
@@ -62286,6 +63364,7 @@ DUK_LOCAL duk_hobject *duk__resolve_target_func_and_this_binding(duk_hthread *th
if (duk_hobject_find_existing_entry_tval_ptr(thr->heap, DUK_TVAL_GET_OBJECT(tv_func), DUK_HTHREAD_STRING_INT_TARGET(thr)) != NULL) {
duk_push_tval(thr, tv_func);
(void) duk_throw(thr);
+ DUK_WO_NORETURN(return NULL;);
}
}
#endif
@@ -62299,8 +63378,7 @@ DUK_LOCAL duk_hobject *duk__resolve_target_func_and_this_binding(duk_hthread *th
#else
DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
#endif
- DUK_UNREACHABLE();
- return NULL; /* never executed */
+ DUK_WO_NORETURN(return NULL;);
not_constructable:
/* For now GETPROPC delayed error not needed for constructor calls. */
@@ -62313,8 +63391,7 @@ DUK_LOCAL duk_hobject *duk__resolve_target_func_and_this_binding(duk_hthread *th
#else
DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE);
#endif
- DUK_UNREACHABLE();
- return NULL; /* never executed */
+ DUK_WO_NORETURN(return NULL;);
}
/*
@@ -62338,6 +63415,7 @@ DUK_LOCAL void duk__safe_call_adjust_valstack(duk_hthread *thr, duk_idx_t idx_re
idx_rcbase = duk_get_top(thr) - num_actual_rets; /* base of known return values */
if (DUK_UNLIKELY(idx_rcbase < 0)) {
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC);
+ DUK_WO_NORETURN(return;);
}
DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: "
@@ -62472,9 +63550,10 @@ DUK_LOCAL duk_small_uint_t duk__call_setup_act_attempt_tailcall(duk_hthread *thr
* - Disable StepOut processing for the activation unwind because
* we reuse the activation, see:
* https://github.com/svaarala/duktape/issues/1684.
- * - Disable line change pause flag permanently (if set) because
- * it would no longer be relevant, see:
- * https://github.com/svaarala/duktape/issues/1726.
+ * - Disable line change pause flag permanently if act == dbg_pause_act
+ * (if set) because it would no longer be relevant, see:
+ * https://github.com/svaarala/duktape/issues/1726,
+ * https://github.com/svaarala/duktape/issues/1786.
* - Check for function entry (e.g. StepInto) pause flag here, because
* the executor pause check won't trigger due to shared activation, see:
* https://github.com/svaarala/duktape/issues/1726.
@@ -62495,9 +63574,12 @@ DUK_LOCAL duk_small_uint_t duk__call_setup_act_attempt_tailcall(duk_hthread *thr
DUK_ASSERT(thr->callstack_top > 0);
DUK_ASSERT(thr->callstack_curr != NULL);
#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ if (act == thr->heap->dbg_pause_act) {
+ thr->heap->dbg_pause_flags &= ~DUK_PAUSE_FLAG_LINE_CHANGE;
+ }
+
prev_pause_act = thr->heap->dbg_pause_act;
thr->heap->dbg_pause_act = NULL;
- thr->heap->dbg_pause_flags &= ~DUK_PAUSE_FLAG_LINE_CHANGE;
if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) {
DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry (tailcall)"));
duk_debug_set_paused(thr->heap);
@@ -62637,10 +63719,10 @@ DUK_LOCAL void duk__call_setup_act_not_tailcall(duk_hthread *thr,
* Update return value stack index of current activation (if any).
*
* Although it might seem this is not necessary (bytecode executor
- * does this for Ecmascript-to-Ecmascript calls; other calls are
+ * does this for ECMAScript-to-ECMAScript calls; other calls are
* handled here), this turns out to be necessary for handling yield
- * and resume. For them, an Ecmascript-to-native call happens, and
- * the Ecmascript call's retval_byteoff must be set for things to work.
+ * and resume. For them, an ECMAScript-to-native call happens, and
+ * the ECMAScript call's retval_byteoff must be set for things to work.
*/
act->retval_byteoff = entry_valstack_bottom_byteoff + (duk_size_t) idx_func * sizeof(duk_tval);
@@ -62847,16 +63929,16 @@ DUK_LOCAL void duk__call_thread_state_update(duk_hthread *thr) {
thread_state_error:
DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state (%ld)", (long) thr->state);
- DUK_UNREACHABLE();
+ DUK_WO_NORETURN(return;);
}
/*
* Main unprotected call handler, handles:
*
- * - All combinations of native/Ecmascript caller and native/Ecmascript
+ * - All combinations of native/ECMAScript caller and native/ECMAScript
* target.
*
- * - Optimized Ecmascript-to-Ecmascript call where call handling only
+ * - Optimized ECMAScript-to-ECMAScript call where call handling only
* sets up a new duk_activation but reuses an existing bytecode executor
* (the caller) without native recursion.
*
@@ -62905,7 +63987,7 @@ DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr,
DUK_STATS_INC(thr->heap, stats_call_all);
/* If a tail call:
- * - an Ecmascript activation must be on top of the callstack
+ * - an ECMAScript activation must be on top of the callstack
* - there cannot be any catch stack entries that would catch
* a return
*/
@@ -63010,6 +64092,12 @@ DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr,
* Because 'act' is not zeroed, all fields must be filled in.
*/
+ /* Should not be necessary, but initialize to silence warnings. */
+ act = NULL;
+ nargs = 0;
+ nregs = 0;
+ vs_min_bytes = 0;
+
#if defined(DUK_USE_TAILCALL)
use_tailcall = (call_flags & DUK_CALL_FLAG_TAILCALL);
if (use_tailcall) {
@@ -63057,7 +64145,7 @@ DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr,
* compiler; the compiled function's parent env will contain
* the (immutable) binding already.
*
- * This handling is now identical for C and Ecmascript functions.
+ * This handling is now identical for C and ECMAScript functions.
* C functions always have the 'NEWENV' flag set, so their
* environment record initialization is delayed (which is good).
*
@@ -63104,7 +64192,7 @@ DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr,
if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) {
/*
- * Ecmascript call.
+ * ECMAScript call.
*/
DUK_ASSERT(func != NULL);
@@ -63198,9 +64286,10 @@ DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr,
;
} else if (rc < 0) {
duk_error_throw_from_negative_rc(thr, rc);
- DUK_UNREACHABLE();
+ DUK_WO_NORETURN(return 0;);
} else {
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC);
+ DUK_WO_NORETURN(return 0;);
}
}
DUK_ASSERT(thr->ptr_curr_pc == NULL);
@@ -63288,7 +64377,7 @@ DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr,
* calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see
* GH-303. Only needed for success path, error path always causes a
* breakpoint recheck in the executor. It would be enough to set this
- * only when returning to an Ecmascript activation, but setting the flag
+ * only when returning to an ECMAScript activation, but setting the flag
* on every return should have no ill effect.
*/
#if defined(DUK_USE_DEBUGGER_SUPPORT)
@@ -63400,6 +64489,7 @@ DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
if (DUK_UNLIKELY(rc < 0)) {
duk_error_throw_from_negative_rc(thr, rc);
+ DUK_WO_NORETURN(return;);
}
DUK_ASSERT(rc >= 0);
@@ -63677,7 +64767,10 @@ DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
retval = DUK_EXEC_ERROR;
}
#if defined(DUK_USE_CPP_EXCEPTIONS)
- catch (std::exception &exc) {
+ catch (duk_fatal_exception &exc) {
+ DUK_D(DUK_DPRINT("rethrow duk_fatal_exception"));
+ throw;
+ } catch (std::exception &exc) {
const char *what = exc.what();
DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
DUK_STATS_INC(thr->heap, stats_safecall_throw);
@@ -63687,6 +64780,7 @@ DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
try {
DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
+ DUK_WO_NORETURN(return 0;);
} catch (duk_internal_exception exc) {
DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
DUK_UNREF(exc);
@@ -63709,6 +64803,7 @@ DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
DUK_STATS_INC(thr->heap, stats_safecall_throw);
try {
DUK_ERROR_TYPE(thr, "caught invalid c++ exception (perhaps thrown by user code)");
+ DUK_WO_NORETURN(return 0;);
} catch (duk_internal_exception exc) {
DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
DUK_UNREF(exc);
@@ -63768,7 +64863,7 @@ DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
/*
* Property-based call (foo.noSuch()) error setup: replace target function
* on stack top with a specially tagged (hidden Symbol) error which gets
- * thrown in call handling at the proper spot to follow Ecmascript semantics.
+ * thrown in call handling at the proper spot to follow ECMAScript semantics.
*/
#if defined(DUK_USE_VERBOSE_ERRORS)
@@ -63826,7 +64921,7 @@ DUK_INTERNAL DUK_NOINLINE DUK_COLD void duk_call_setup_propcall_error(duk_hthrea
/* automatic undefs */
#undef DUK__AUGMENT_CALL_RELAX_COUNT
/*
- * Ecmascript compiler.
+ * ECMAScript compiler.
*
* Parses an input string and generates a function template result.
* Compilation may happen in multiple contexts (global code, eval
@@ -64062,9 +65157,9 @@ DUK_LOCAL_DECL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *
DUK_LOCAL_DECL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
DUK_LOCAL_DECL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem);
DUK_LOCAL_DECL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id);
-DUK_LOCAL_DECL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof);
+DUK_LOCAL_DECL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof, duk_bool_t regexp_after);
-DUK_LOCAL_DECL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_small_int_t expect_token);
+DUK_LOCAL_DECL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_bool_t regexp_after, duk_small_int_t expect_token);
DUK_LOCAL_DECL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx);
DUK_LOCAL_DECL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags);
DUK_LOCAL_DECL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags);
@@ -64236,6 +65331,7 @@ DUK_LOCAL void duk__comp_recursion_increase(duk_compiler_ctx *comp_ctx) {
DUK_ASSERT(comp_ctx->recursion_depth >= 0);
if (comp_ctx->recursion_depth >= comp_ctx->recursion_limit) {
DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_COMPILER_RECURSION_LIMIT);
+ DUK_WO_NORETURN(return;);
}
comp_ctx->recursion_depth++;
}
@@ -64290,15 +65386,20 @@ DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t e
comp_ctx->curr_func.reject_regexp_in_adv = 0;
regexp = 0;
}
+ if (comp_ctx->curr_func.allow_regexp_in_adv) {
+ comp_ctx->curr_func.allow_regexp_in_adv = 0;
+ regexp = 1;
+ }
if (expect >= 0 && comp_ctx->curr_token.t != (duk_small_uint_t) expect) {
DUK_D(DUK_DPRINT("parse error: expect=%ld, got=%ld",
(long) expect, (long) comp_ctx->curr_token.t));
DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
+ DUK_WO_NORETURN(return;);
}
/* make current token the previous; need to fiddle with valstack "backing store" */
- DUK_MEMCPY(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token));
+ duk_memcpy(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token));
duk_copy(thr, comp_ctx->tok11_idx, comp_ctx->tok21_idx);
duk_copy(thr, comp_ctx->tok12_idx, comp_ctx->tok22_idx);
@@ -64346,7 +65447,7 @@ DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
entry_top = duk_get_top(thr);
- DUK_MEMZERO(func, sizeof(*func)); /* intentional overlap with earlier memzero */
+ duk_memzero(func, sizeof(*func)); /* intentional overlap with earlier memzero */
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
func->h_name = NULL;
func->h_consts = NULL;
@@ -64593,7 +65694,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
(long) code_size, (long) data_size));
duk_push_fixed_buffer_nozero(thr, data_size);
- h_data = (duk_hbuffer_fixed *) duk_known_hbuffer(thr, -1);
+ h_data = (duk_hbuffer_fixed *) (void *) duk_known_hbuffer(thr, -1);
DUK_HCOMPFUNC_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data);
DUK_HEAPHDR_INCREF(thr, h_data);
@@ -64798,7 +65899,7 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
*/
#if 0
- duk_push_string(thr, "XXX");
+ duk_push_literal(thr, "XXX");
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
#endif
}
@@ -64997,6 +66098,7 @@ DUK_LOCAL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins) {
fail_bc_limit:
DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
+ DUK_WO_NORETURN(return;);
}
/* Update function min/max line from current token. Needed to improve
@@ -65281,6 +66383,7 @@ DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_f
error_outofregs:
DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
+ DUK_WO_NORETURN(return;);
}
/* For many of the helpers below it'd be technically correct to add
@@ -65379,6 +66482,7 @@ DUK_LOCAL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_fl
error_outofregs:
DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
+ DUK_WO_NORETURN(return;);
}
DUK_LOCAL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc) {
@@ -65413,6 +66517,7 @@ DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, du
error_outofregs:
DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
+ DUK_WO_NORETURN(return;);
}
DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val, duk_small_uint_t op_flags) {
@@ -65510,6 +66615,7 @@ DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump
fail_bc_limit:
DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
+ DUK_WO_NORETURN(return;);
}
/* Does not assume that jump_pc contains a DUK_OP_JUMP previously; this is intentional
@@ -65565,6 +66671,7 @@ DUK_LOCAL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst
DUK_D(DUK_DPRINT("failed to patch trycatch: flags=%ld, reg_catch=%ld, const_varname=%ld (0x%08lx)",
(long) flags, (long) reg_catch, (long) const_varname, (long) const_varname));
DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
+ DUK_WO_NORETURN(return;);
}
instr->ins |= DUK_ENC_OP_A_BC(0, 0, const_varname);
} else {
@@ -65756,6 +66863,7 @@ DUK_LOCAL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_i
if (comp_ctx->curr_func.temp_next > DUK__MAX_TEMPS) { /* == DUK__MAX_TEMPS is OK */
DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_TEMP_LIMIT);
+ DUK_WO_NORETURN(return 0;);
}
/* maintain highest 'used' temporary, needed to figure out nregs of function */
@@ -65815,6 +66923,7 @@ DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
if (n > DUK__MAX_CONSTS) {
DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_CONST_LIMIT);
+ DUK_WO_NORETURN(return 0;);
}
DUK_DDD(DUK_DDDPRINT("allocating new constant for %!T -> const index %ld",
@@ -65988,6 +67097,7 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
}
}
} /* end switch */
+ goto fail_internal; /* never here */
}
case DUK_ISPEC_REGCONST: {
if (forced_reg >= 0) {
@@ -66020,12 +67130,13 @@ duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
return x->regconst;
}
default: {
- break;
+ break; /* never here */
}
}
+ fail_internal:
DUK_ERROR_INTERNAL(thr);
- return 0;
+ DUK_WO_NORETURN(return 0;);
}
DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg) {
@@ -66098,7 +67209,10 @@ DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *co