<feed xmlns='http://www.w3.org/2005/Atom'>
<title>puzzles/emccpre.js, branch master</title>
<subtitle>My sgt-puzzles tree</subtitle>
<link rel='alternate' type='text/html' href='https://www.franklinwei.com/cgit/puzzles/'/>
<entry>
<title>js: allow for multiple environment blocks in HTML</title>
<updated>2023-08-21T22:06:39+00:00</updated>
<author>
<name>Ben Harris</name>
<email>bjh21@bjh21.me.uk</email>
</author>
<published>2023-08-21T21:48:59+00:00</published>
<link rel='alternate' type='text/html' href='https://www.franklinwei.com/cgit/puzzles/commit/?id=f97d11df670597136e34f1078d9a2eb2cdbcd85b'/>
<id>f97d11df670597136e34f1078d9a2eb2cdbcd85b</id>
<content type='text'>
Not that I actually need it, but it's just as easy to load multiple
environment &lt;script&gt;s from the DOM as it is to load one, so we may as
well do that.  Since only one element can have id="environment", we do
this by matching class="environment" as well.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Not that I actually need it, but it's just as easy to load multiple
environment &lt;script&gt;s from the DOM as it is to load one, so we may as
well do that.  Since only one element can have id="environment", we do
this by matching class="environment" as well.
</pre>
</div>
</content>
</entry>
<entry>
<title>js: keep colour strings in JavaScript rather than in C</title>
<updated>2023-07-30T10:50:25+00:00</updated>
<author>
<name>Ben Harris</name>
<email>bjh21@bjh21.me.uk</email>
</author>
<published>2023-07-29T15:06:19+00:00</published>
<link rel='alternate' type='text/html' href='https://www.franklinwei.com/cgit/puzzles/commit/?id=76da6ec140cbbdac6136469ce50aab40e218f398'/>
<id>76da6ec140cbbdac6136469ce50aab40e218f398</id>
<content type='text'>
The drawing routines in JavaScript used to take pointers to a C string
containing a CSS colour name.  That meant that JavaScript had to create
a new JavaScript string on ever call to a drawing function, which seemed
ugly.

So now we instead pass colour numbers all the way down into JavaScript
and keep an array of JavaScript strings there that can be re-used.  The
conversion from RGB triples to strings is still done in C, though.

This doesn't seem to have fixed either of the bugs I hoped it would, but
it does measurably improve drawing performance so I think it's worth
doing.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The drawing routines in JavaScript used to take pointers to a C string
containing a CSS colour name.  That meant that JavaScript had to create
a new JavaScript string on ever call to a drawing function, which seemed
ugly.

So now we instead pass colour numbers all the way down into JavaScript
and keep an array of JavaScript strings there that can be re-used.  The
conversion from RGB triples to strings is still done in C, though.

This doesn't seem to have fixed either of the bugs I hoped it would, but
it does measurably improve drawing performance so I think it's worth
doing.
</pre>
</div>
</content>
</entry>
<entry>
<title>js: Copy-to-clipboard support</title>
<updated>2023-07-05T18:39:57+00:00</updated>
<author>
<name>Ben Harris</name>
<email>bjh21@bjh21.me.uk</email>
</author>
<published>2023-07-05T18:39:57+00:00</published>
<link rel='alternate' type='text/html' href='https://www.franklinwei.com/cgit/puzzles/commit/?id=ad7042db989eb525defea9298b2b14d564498473'/>
<id>ad7042db989eb525defea9298b2b14d564498473</id>
<content type='text'>
Now using the browser's "copy" operation while the focus is in the
puzzle will copy the puzzle state to the clipboard.  Browsers seem to
have odd ideas about whate element to target with the "copy" event:
Firefox targets the parent of the &lt;canvas&gt; while Chromium targets the
&lt;body&gt;.  To cope with these and possible future weirdness I attach the
event handler to the document and then look to see if it's plausibly
related to the canvas.

Arguably we might want to handle a wider range of "copy" events, maybe
any where the selection isn't empty.  I'm not sure, though, so we'll
start with the minimal change.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Now using the browser's "copy" operation while the focus is in the
puzzle will copy the puzzle state to the clipboard.  Browsers seem to
have odd ideas about whate element to target with the "copy" event:
Firefox targets the parent of the &lt;canvas&gt; while Chromium targets the
&lt;body&gt;.  To cope with these and possible future weirdness I attach the
event handler to the document and then look to see if it's plausibly
related to the canvas.

Arguably we might want to handle a wider range of "copy" events, maybe
any where the selection isn't empty.  I'm not sure, though, so we'll
start with the minimal change.
</pre>
</div>
</content>
</entry>
<entry>
<title>js: pass preferences file from JS to C on the heap, not the stack</title>
<updated>2023-05-30T15:00:31+00:00</updated>
<author>
<name>Ben Harris</name>
<email>bjh21@bjh21.me.uk</email>
</author>
<published>2023-05-30T14:55:22+00:00</published>
<link rel='alternate' type='text/html' href='https://www.franklinwei.com/cgit/puzzles/commit/?id=5acce15ed907d29a5575668a09e7d94cf7a36b3f'/>
<id>5acce15ed907d29a5575668a09e7d94cf7a36b3f</id>
<content type='text'>
The C stack used by Emscripten is quite small, so passing more than a
few klilobytes of data on it tends to cause an overflow.  Current
versions of puzzles will only generate tiny preferences files, but this
might change in future and in any case Puzzles shouldn't crash just
because the preferences in local storage have got corrupted.

To fix this, we now have JavaScript allocate a suitable amount of C heap
memory using malloc() and stick the preferences file in there.

This could plausibly fail if the preferences file were really big, but
that's unlikely since browsers generally limit an origin to about 5 MB
of local storage.  In any case, if malloc() does fail, we'll just ignore
the preferences file, which is probably the right thing to do.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The C stack used by Emscripten is quite small, so passing more than a
few klilobytes of data on it tends to cause an overflow.  Current
versions of puzzles will only generate tiny preferences files, but this
might change in future and in any case Puzzles shouldn't crash just
because the preferences in local storage have got corrupted.

To fix this, we now have JavaScript allocate a suitable amount of C heap
memory using malloc() and stick the preferences file in there.

This could plausibly fail if the preferences file were really big, but
that's unlikely since browsers generally limit an origin to about 5 MB
of local storage.  In any case, if malloc() does fail, we'll just ignore
the preferences file, which is probably the right thing to do.
</pre>
</div>
</content>
</entry>
<entry>
<title>Support user preferences in the Emscripten frontend.</title>
<updated>2023-04-24T09:17:33+00:00</updated>
<author>
<name>Simon Tatham</name>
<email>anakin@pobox.com</email>
</author>
<published>2023-04-24T09:17:33+00:00</published>
<link rel='alternate' type='text/html' href='https://www.franklinwei.com/cgit/puzzles/commit/?id=43db4aa38e83595dc6df245cb952795f9f306ed0'/>
<id>43db4aa38e83595dc6df245cb952795f9f306ed0</id>
<content type='text'>
Here, user preferences are stored in localStorage, so that they can
persist when you come back to the same puzzle page later.

localStorage is global across a whole web server, which means we need
to take care to put our uses of it in a namespace reasonably unlikely
to collide with unrelated web pages on the same server. Ben suggested
that a good way to do this would be to store things in localStorage
under keys derived from location.pathname. In this case I've appended
a fragment id "#preferences" to that, so that space alongside it
remains for storing other things we might want in future (such as
serialised saved-game files used as quick-save slots).

When loading preferences, I've chosen to pass the whole serialised
preferences buffer from Javascript to C as a single C string argument
to a callback, rather than reusing the existing system for C to read
the save file a chunk at a time. Partly that's because preferences
data is bounded in size whereas saved games can keep growing; also
it's because the way I'm storing preferences data means it will be a
UTF-8 string, and I didn't fancy trying to figure out byte offsets in
the data on the JS side.

I think at this point I should stop keeping a list in the docs of
which frontends support preferences. Most of the in-tree ones do now,
and that means the remaining interesting frontends are ones I don't
have a full list of. At this moment I guess no out-of-tree frontends
support preferences (unless someone is _very_ quick off the mark), but
as and when that changes, I won't necessarily know, and don't want to
have to keep updating the docs when I find out.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Here, user preferences are stored in localStorage, so that they can
persist when you come back to the same puzzle page later.

localStorage is global across a whole web server, which means we need
to take care to put our uses of it in a namespace reasonably unlikely
to collide with unrelated web pages on the same server. Ben suggested
that a good way to do this would be to store things in localStorage
under keys derived from location.pathname. In this case I've appended
a fragment id "#preferences" to that, so that space alongside it
remains for storing other things we might want in future (such as
serialised saved-game files used as quick-save slots).

When loading preferences, I've chosen to pass the whole serialised
preferences buffer from Javascript to C as a single C string argument
to a callback, rather than reusing the existing system for C to read
the save file a chunk at a time. Partly that's because preferences
data is bounded in size whereas saved games can keep growing; also
it's because the way I'm storing preferences data means it will be a
UTF-8 string, and I didn't fancy trying to figure out byte offsets in
the data on the JS side.

I think at this point I should stop keeping a list in the docs of
which frontends support preferences. Most of the in-tree ones do now,
and that means the remaining interesting frontends are ones I don't
have a full list of. At this moment I guess no out-of-tree frontends
support preferences (unless someone is _very_ quick off the mark), but
as and when that changes, I won't necessarily know, and don't want to
have to keep updating the docs when I find out.
</pre>
</div>
</content>
</entry>
<entry>
<title>js: use the "load" event for loading save files</title>
<updated>2023-04-03T21:11:42+00:00</updated>
<author>
<name>Ben Harris</name>
<email>bjh21@bjh21.me.uk</email>
</author>
<published>2023-04-03T21:11:42+00:00</published>
<link rel='alternate' type='text/html' href='https://www.franklinwei.com/cgit/puzzles/commit/?id=4de5d20368d4b2ca4f0851eafa900cd0c9a3c691'/>
<id>4de5d20368d4b2ca4f0851eafa900cd0c9a3c691</id>
<content type='text'>
This is in place of the "loadend" event.  In Chromium, (and in the
specification), "loadend" is triggered not only when the file is
loaded but also when loading fails.  Obviously when loading fails we
don't want to try to parse the (nonexistent) resulting file.

Using the "load" event works better, since it's only fired on success,
and we can also have an "error" handler to report problems with
loading files, albeit with no detail at all.

This doesn't seem to make any difference in Firefox, which in my
testing fires "load" and "loadend" on success and nothing at all on
failure.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This is in place of the "loadend" event.  In Chromium, (and in the
specification), "loadend" is triggered not only when the file is
loaded but also when loading fails.  Obviously when loading fails we
don't want to try to parse the (nonexistent) resulting file.

Using the "load" event works better, since it's only fired on success,
and we can also have an "error" handler to report problems with
loading files, albeit with no detail at all.

This doesn't seem to make any difference in Firefox, which in my
testing fires "load" and "loadend" on success and nothing at all on
failure.
</pre>
</div>
</content>
</entry>
<entry>
<title>js: Load save files into the C side incrementally</title>
<updated>2023-04-03T20:09:57+00:00</updated>
<author>
<name>Ben Harris</name>
<email>bjh21@bjh21.me.uk</email>
</author>
<published>2023-04-03T14:16:35+00:00</published>
<link rel='alternate' type='text/html' href='https://www.franklinwei.com/cgit/puzzles/commit/?id=36c282aaa92bd42d570cdc76fe3b9e76d8da1ff1'/>
<id>36c282aaa92bd42d570cdc76fe3b9e76d8da1ff1</id>
<content type='text'>
Before this commit, JavaScript Puzzles loaded a save file by pushing the
entire file onto the Emscripten stack and then reading it from there.
This worked tolerably for typical save files, but Emscripten's stack
defaults to only having 64 kiB of space.  That meant that trying to load
something that wasn't a real save file tended to cause a stack overflow.
I expect that at least some real save files would suffer from the same
problem.

The stack overflow would generally cause a JavaScript exception and then
leave the stack pointer outside the stack, so that any future attempt to
call into C would fail as well.

To fix this, arrange that the C function for reading data from the save
file calls out to JavaScript.  The JavaScript can then copy just the
requested data into the caller's buffer.  We can't pass a JavaScript
function pointer to C, but since only one file can be loaded at a time,
we can just have a global variable that's the current loading callback.

There might still be a problem if you try to load a stupendously large
file, since I think FileReader.readAsArrayBuffer() reads the whole file
into the browser's RAM.  It works on my laptop with files up to a few
hundred megabytes, though.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Before this commit, JavaScript Puzzles loaded a save file by pushing the
entire file onto the Emscripten stack and then reading it from there.
This worked tolerably for typical save files, but Emscripten's stack
defaults to only having 64 kiB of space.  That meant that trying to load
something that wasn't a real save file tended to cause a stack overflow.
I expect that at least some real save files would suffer from the same
problem.

The stack overflow would generally cause a JavaScript exception and then
leave the stack pointer outside the stack, so that any future attempt to
call into C would fail as well.

To fix this, arrange that the C function for reading data from the save
file calls out to JavaScript.  The JavaScript can then copy just the
requested data into the caller's buffer.  We can't pass a JavaScript
function pointer to C, but since only one file can be loaded at a time,
we can just have a global variable that's the current loading callback.

There might still be a problem if you try to load a stupendously large
file, since I think FileReader.readAsArrayBuffer() reads the whole file
into the browser's RAM.  It works on my laptop with files up to a few
hundred megabytes, though.
</pre>
</div>
</content>
</entry>
<entry>
<title>js: load games using FileReader.readAsArrayBuffer()</title>
<updated>2023-04-02T20:17:11+00:00</updated>
<author>
<name>Ben Harris</name>
<email>bjh21@bjh21.me.uk</email>
</author>
<published>2023-04-02T19:58:30+00:00</published>
<link rel='alternate' type='text/html' href='https://www.franklinwei.com/cgit/puzzles/commit/?id=8d3a93ce47237114a88d8bed81ab175994eb9a6b'/>
<id>8d3a93ce47237114a88d8bed81ab175994eb9a6b</id>
<content type='text'>
Using .readAsText() meant that trying to load a non-text file (for
instance something that's not a save file at all) would generate an
"RuntimeError: index out of bounds".  This would then leave the
Emscripten runtime in a broken state.

It might even be possible for a real save file not to be valid UTF-8,
for instance if it came from a platform that used a different character
encoding for random seeds.

There's still a problem with opening very large files, apparently
because Emscripten tries to stuff the entire file onto the C stack.
That will probably have to be fixed by properly exposing the incremental
file-loading API to JavaScript.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Using .readAsText() meant that trying to load a non-text file (for
instance something that's not a save file at all) would generate an
"RuntimeError: index out of bounds".  This would then leave the
Emscripten runtime in a broken state.

It might even be possible for a real save file not to be valid UTF-8,
for instance if it came from a platform that used a different character
encoding for random seeds.

There's still a problem with opening very large files, apparently
because Emscripten tries to stuff the entire file onto the C stack.
That will probably have to be fixed by properly exposing the incremental
file-loading API to JavaScript.
</pre>
</div>
</content>
</entry>
<entry>
<title>js: Use the Pointer Events API, but only to capture the pointer</title>
<updated>2023-03-01T22:17:04+00:00</updated>
<author>
<name>Ben Harris</name>
<email>bjh21@bjh21.me.uk</email>
</author>
<published>2023-03-01T21:55:07+00:00</published>
<link rel='alternate' type='text/html' href='https://www.franklinwei.com/cgit/puzzles/commit/?id=5a74693b329eadb69153b150754eb099a0c87e9a'/>
<id>5a74693b329eadb69153b150754eb099a0c87e9a</id>
<content type='text'>
Element.setPointerCapture() captures both pointer and mouse events, so
we can use our existing mouse handlers and just have a minimal
pointerdown handler that calls setPointerCapture().  This saves (or at
least postpones) all the tedious rewriting referred to in ecd868ac.

This means that now drags beyond the puzzle area work in WebKit-based
browsers, and we don't get deprecation warnings in current Gecko-based
ones.  Older Gecko-based browsers continue to use Element.setCapture()
and hence still work correctly.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Element.setPointerCapture() captures both pointer and mouse events, so
we can use our existing mouse handlers and just have a minimal
pointerdown handler that calls setPointerCapture().  This saves (or at
least postpones) all the tedious rewriting referred to in ecd868ac.

This means that now drags beyond the puzzle area work in WebKit-based
browsers, and we don't get deprecation warnings in current Gecko-based
ones.  Older Gecko-based browsers continue to use Element.setCapture()
and hence still work correctly.
</pre>
</div>
</content>
</entry>
<entry>
<title>Revert "JS puzzles: use the PointerEvent API if available."</title>
<updated>2023-02-23T08:52:17+00:00</updated>
<author>
<name>Simon Tatham</name>
<email>anakin@pobox.com</email>
</author>
<published>2023-02-23T08:46:56+00:00</published>
<link rel='alternate' type='text/html' href='https://www.franklinwei.com/cgit/puzzles/commit/?id=ecd868ac6e7ab3df4984ff29a16c7158339611a3'/>
<id>ecd868ac6e7ab3df4984ff29a16c7158339611a3</id>
<content type='text'>
This reverts commit 9d7c2b8c83506c1f239c840e372058fac603b255.

I thought that switching from the JS 'mousedown', 'mousemove' and
'mouseup' events to the corresponding 'pointer*' events would make
essentially no difference except that the pointer events would come
with more information. But in fact it turns out that there's a
fundamental change of semantics.

If you press one mouse button down and then, without releasing it,
press a second one, then the mouse API will send you this information
in the form of two 'mousedown' events, one for each button. But the
pointer API will only send you a 'pointerdown' for the first event,
when the state of the pointer changes from 'no buttons down' to 'at
least one button down'. The second button press will be delivered as a
'pointermove', in which the 'buttons' field is different from its
previous value.

I'm backing out the migration to PointerEvent for the moment, because
that's too complicated for a trivial fix. In simple cases we could
easily detect the changed buttons field in the pointermove handler and
generate a call to the C side of this front end's mousedown()
function, effectively converting the changed JS representation to the
one the C was already expecting. But this also has to interact with
our one-button support (converting Ctrl and Shift clicks into a
different logical button) _and_ with the ad-hoc mechanism we use to
avoid delivering buttonless mouse movements to the C side. So getting
it right in all cases at once isn't trivial, and I'd rather revert the
attempt now and think about it later than commit to getting it all
perfect on short notice.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This reverts commit 9d7c2b8c83506c1f239c840e372058fac603b255.

I thought that switching from the JS 'mousedown', 'mousemove' and
'mouseup' events to the corresponding 'pointer*' events would make
essentially no difference except that the pointer events would come
with more information. But in fact it turns out that there's a
fundamental change of semantics.

If you press one mouse button down and then, without releasing it,
press a second one, then the mouse API will send you this information
in the form of two 'mousedown' events, one for each button. But the
pointer API will only send you a 'pointerdown' for the first event,
when the state of the pointer changes from 'no buttons down' to 'at
least one button down'. The second button press will be delivered as a
'pointermove', in which the 'buttons' field is different from its
previous value.

I'm backing out the migration to PointerEvent for the moment, because
that's too complicated for a trivial fix. In simple cases we could
easily detect the changed buttons field in the pointermove handler and
generate a call to the C side of this front end's mousedown()
function, effectively converting the changed JS representation to the
one the C was already expecting. But this also has to interact with
our one-button support (converting Ctrl and Shift clicks into a
different logical button) _and_ with the ad-hoc mechanism we use to
avoid delivering buttonless mouse movements to the C side. So getting
it right in all cases at once isn't trivial, and I'd rather revert the
attempt now and think about it later than commit to getting it all
perfect on short notice.
</pre>
</div>
</content>
</entry>
</feed>
