About Me
Michael Zucchi
B.E. (Comp. Sys. Eng.)
also known as Zed
to his mates & enemies!
< notzed at gmail >
< fosstodon.org/@notzed >
e-reader, epub
Had a mini hack-fest today, and whipped up an e-pub backend for ReaderZ based on CSZ.
I added very basic img tag support as well, as is obvious.
Apart from the code to parse the content.opf file from the .epub archive which was fairly small, I spent the most time trying to work out a URL handler for a made-up 'epub:' protocol. I copied the way the jar: protocol handler distinguises between the base archive and the filename using "!/" - this is so that the normal url resolution mechanism work. But I also wanted to resolve by the manifest ID and I use the url fragment for that (although in hindsight I probably don't need it). But anyway in the end it wasn't much code, and having it there made everything 'just work', which was nice.
I also had to deal with all the crap XML brings along: i.e. dtd resolution.
The actual viewer is a bit unwieldy as it works as a set of html pages. So you need to pan around to read each 'page' (i.e. chapter, or whole book), and changing pages flips between the items in the spine (i.e. chapters or whole book). To do better than that I really need a paginating layout engine: which is something for later.
I have no svg support not surprisingly, so title pages which are pure svg come up a re-assuring blank.
Still a bit slow opening new chapters, but what can you do eh?
It's all been checked in to ReaderZ and CSZ.
floats n stuff
I made some more progress on CSZ. The latest thing I have sort-of working are floats.
I think i'm interpreting the bits i've implemented correctly: floats are quite limited so the layout logic isn't terribly complex. I still have no borders or padding (and I removed the fudge factor I had in before) so it looks a bit cramped.
It's still sad just how much crap you need to get to even this point ...
I just got a call from work and they want me back in a couple of weeks, so I might turn down the effort a bit so I can psych myself up for that. Maybe i'll finally use that kobo as a reader of books too ...
CSZ
Well I kept poking away at the XHTML/CSS stuff, for want of something better to do. I had a couple of wins along the way.
The cascading and inheritance is working somewhat better now, and I added a few more properties. Given that I'm not very familiar with all the various rules, I think I have a fairly efficient resolution mechanism by indexing various bits and pieces. The layout system is still crap, and very very incomplete, but at least I have baselines aligned now.
This is a totally contrived example, everything apart from the text layout and typefaces are hacked in one way or another.
I tried it on the kobo ... it's still fairly slow, but it's better (I think: TBH i can't remember what I tried the other stuff on). Still hampered by the text layout though.
For a 200k file (which is mostly just <p> elements), scanning the file, resolving the properties and generating the box list takes only a fraction of a second. I'm not trying to resolve or use very many properties though. About all i'm using `in anger' are some of the font-* properties.
But then performing the layout (as a single page) takes about 7s (once the jvm is warmed up), which is mostly due to TextLayout. I will have to try it with a simpler font than the one the JVM comes with.
Rendering is fairly ok (relative to the e-ink anyway) and all i'm doing is painting every textlayout in the whole tree ...
I uploaded it to MediaZ anyway, in the new CSZ module.
Hmmm, I should really take a break from hacking for a bit. But i'll believe that when I see it.
xhtml, css, boxes n shit
For some stupid reason I delved into CSS and XHTML and rendering thereof.
CSS is so deceptively simple: a few boxes, layouts in lines, and a few properties to set. Saying the devil is in the details here isn't doing the term justice. It's all in the details. And they're ugly.
From the fairly complex cascading rules, to the number of properties. The layout merging. The badly written documentation: filled with "x inline y box" "a block b box c" to such specificity, and no with definitions it is quite difficult to decipher what it's even talking about. It's also quite hard to debug, since it needs a fair bit of data structure to represent it.
CSZ
Anyway, after some mucking about, I have a relatively complete CSS lexer and parser, a fairly incomplete cascade resolver, a fairly incomplete layout engine, and a very incomplete style system. It's just enough to show paragraphs of text with some basic formatting. For a book reader I don't want the document to control the text too much anyway.
I'm attempting to do it while streaming the input, and (obviously thus) in a single pass using the pull parser from XMLStreamReader. Therefore initial parsing is quite quick, but it's still taking a relatively long time to lay out the boxes ...
TextLayout
And the problem here is TextLayout. It's just quite slow. I tried my own version of layout using FontMetrics.getCharsWidth(), but inside that just creates a TextLayout anyway, so it's even slower (or maybe not, now it's a bit faster?).
I know why it's so complicated; for laying out complex scripts and handling all the special cases. Anyway, that is the primary factor of constraint on performance at the moment, although as the implementation is so far from finished, i'm sure it wont be the last one.
(I played some more, and the font used plays a big part in the speed taken, so there's hope yet).
I suppose I should try it on the kobo to see how it goes there.
Dead end?
It's taken a lot of effort to get this far, and i'm not really happy with the result. So i'm not sure if i'll keep plugging away at it or throw it away (and if i need such a functionality, use cssbox). There's a lot left to get it to be useful for anything.
ReaderZ
I finally got around to checking in ReaderZ to mediaz.
I also tweaked a few things before I did:
- Added timer and timeout functionality to the GagdetZ event thread. Using a ScheduledExecutionService made this an absolute doddle, and infact the 'event thread' is now just the service.
- Changed the update mechanisms to try to speed up panning. It now pans using black and white updates and then does a full 'invert' refresh once you stop - after a 700ms timeout of inactivity. It is still a bit slow updating, but that might be because i'm rendering the content on the fly. I can't seem to get the e-ink to go any faster, although I did speed that up a bit over what it was.
- I took out the HTML backend for now. I'm using a very slightly modified build of CSSBox (to remove the logging dependencies) and just can't be bothered to work that all out. It's a bit slow anyway.
- For fun I added a picture viewer backend to the DocumentReader.
The README has all the other gory details.
I also had a good look at the text layout mechanism in Java ... boy what a nightmare of code that is. No wonder it's so slow. I tried to work out how it was doing it when it came down to it, but I couldn't fathom it before losing interest. The kobo html reader is about 10x faster at pagination; which just makes it all the more puzzling as to why the text reader is so slow.
Which has me thinking about C again, and using mupdf's stuff to format and render text instead ... well it would work for latin scripts anyway.
A browser ... ?
Ahh, so I totally didn't think I was going to even try to do this ...But epub needs HTML, and I found CSSBox, and well one thing lead to another ...
So I've basically ported the SimpleBrowser example from CSSBox to ReaderZ - all it can do is render the page, and it lets you pan and zoom as with PDF files. No links or anything.
I tried rendering on the fly, and into an image - the former is a little slow to scroll (but not far off the e-ink speed), but I don't think it's clipping the drawing regions properly and so doing a lot more work than necessary anyway. Using an image scrolls fast but can't be zoomed very well, and takes more memory (I blew it with boycottnovell) ... so trade-offs.
It's pretty slow and clunky, but what can one expect when XML is involved?
Reader Shell
So I kept poking away at the browser code and my gadget toolkit.
It's getting fairly sophisticated now: I improved the StackLayout gadget to add filling and relative sizing glue. I added a list gadget - which works by pages, and is similar to JList, including a cell renderer, list model and selection model and I played around with a whole lot of other stuff as well.
So I have enough to finally create a reader shell: it presents a list of the files on the device, and lets you open them up with a pdf reader or a text reader, depending on the file type. Once inside it has a full-screen viewer with no visible buttons - but without buttons you can zoom, pan, change pages one at a time or flip through many a time. A popup menu (single short press in the middle of the screen) lets you quit back to the shell.
I cache the pagination for text files, so they open very quickly after the first visit, assuming the font settings haven't changed. The pagination descriptor is small, about 7k for a 500 page document. On a re-visit of the same file (i.e. once the jvm is warmed up), it's loading 500k text file in about 1/2 a second but even from a cold-start it's only about a second. PDF files also open fast, about the same speed. i.e. not much slower than the e-ink can refresh a single greyscale page. Closing a file and returning to the shell is similarly speedy.
And whilst the interface isn't very complicated, everything is still quite responsive, with no missed finger presses or long unexplained delays (although the first time you open a 500k text file, it still takes about 25s to re-paginate).
My panning is still a bit slow, although I am rendering the bitmap on the fly as well.
But ... i've pretty much done what I want for now: prove that the kobo touch e-reader is a zippy little unit, capable of much more performance than the included software lets it deliver.
I'll drop the code in MediaZ sometime in the next few days, and continue working on it for at least a while.
PDFZ
Checked in the first cut of PDFZ to the MediaZ project.
It's a simple binding to muPDF - i.e. a PDF renderer for Java that builds on arm and x64/x86 cpus.
Copyright (C) 2019 Michael Zucchi, All Rights Reserved.
Powered by gcc & me!