Yesterday Novell Hungary organized
SUSE Conference 2013 here at
Budapest. As you can see above Andras held a LibreOffice-related presentation
there -- and we also ran a LibreOffice booth. As it was requested, we set up
quite some
(publicly
available) Android demos:
Impress remote
LibreOffice4Android (document viewer) on my phone (I needed a
fix
to get it running on a non-tablet, though)
The desktop app on a tablet -- thanks goes to the organizers who provided that for us!
About 200 visitors attended the conference, which counts as a great success in
this category. :-)
This year, LibreOffice's Hamburg hackfest happened last weekend, with more than
20 attendees. Thanks to the
sponsors, we
had free drink and food during the whole hackfest. ;-)
My original plan was to add support for tables inside text frames
in Writer, when importing from RTF. At the end I managed to do that, though not
the way I originally wanted to implement that feature. :-)
Here is how this looked with the RTF importer we inherited from OpenOffice.org (LO 3.4),
and then with the new RTF import filter (LO 3.6):
The Free Software Conference and Exhibition 2013 -- organized by FSF.hu -- was held yesterday @
Budapest. I gave a talk about hacking on Writer file format problems
(slides), this time in Hungarian.
After the talk I also held a one-hour workshop, showing how to start hacking on LO in practice:
first we did a build (using package manager to install dependencies, git clone, autogen, make, make dev-install)
mso-dumper is a
project that creates some -- more or less human-readable -- dump from binary
files. Initially Kohei Yoshida developed it to dump XLS, then Thorsten Behrens
added support for PPT files, finally during last November I started to add DOC
support.
You may ask: why that is useful? My answer is that I spend quite some time on
the import/export filters of LibreOffice Writer, and to be able to improve or
fix such filters, some knowledge of the file format in question and Writer
internals is needed. Regarding the file format knowledge, I find it much easier
to read the specification once and implement some simple dumper based on that
-- than reading the specification again and again, and just trying to
understand what's going on inside a binary file using a hex editor.
To my knowledge, such a dumper for the DOC format (in particular the WW8
version of it) did not exist previously.
WW8Dumper was the closest match, but that was
far from complete and I found extending mso-dumper easier.
To stress-test the parser, I used
get-bugzilla-attachments-by-mimetype
to get all DOC attachements from the Freedesktop bugzilla, and during the last
days I fixed the remaining crashes (actually this is why I write this post now
;-) ). If you want to try it out you can do so by:
git clone git://anongit.freedesktop.org/libreoffice/contrib/mso-dumper
cd mso-dumper
./doc-dump.py /path/to/doc/file.doc
The idea is that on any input the dumper should not crash: instead either it
should give you usable result, or in case some unhandled structure is reached,
it should print a <todo> XML tag. Other than that, of course patches welcome
-- that said, Maxime de Roucy already contributed a patch to the DOC part of
mso-dumper, thanks! :-)
I did some experiments with using lcov on the LibreOffice codebase. The goal is
to have a quick iteration, so you can see the current coverage of a file or a
directory, select a method that is not yet tested, add a test for it, and
"test" the test by checking if the coverage indeed got improved. As a first
step, I tried this out on the Writer RTF import:
<3> extract coverage information to a single .info file
<4> generate some nice HTML output from the .info file
NOTE: lcov
had
problems with gcc-4.7, fully updated openSUSE 12.2 or 12.3 is known to work.
There is a
script
available to make the above a bit more automated.
The speed of the above depends on the amount of code needing a rebuild + the
number of tests, but it should not take more than a minute.
E.g. I noticed the bookmark import code isn't tested, added a
test
for it, and that indeed improved the line coverage of rtfdocumentimpl.cxx:
84.1% -> 85.0%.
A next area I wanted to test is the Writer RTF export. Let's pick something in
rtfattributeoutput.cxx... StartURL() is not tested, so a
hyperlink
testcase should help. Indeed it did: 50.2% -> 52.0%.
Last, but not at least, thanks to Norbert Thiebaud, who added gb_GCOV to
gbuild.
Then I experimented with improving our Writer gdb Python pretty-printers. One
annoying shortcoming was the lack of handling uno::Reference.
Imagine one searches for a bug related to table import for DOCX or RTF. One
idea is to check the arguments of the convertToTable() method call. The first
argument is a 2D array of XTextRange pairs, that describe what will be the
input for cell contents. So if you want to check the first cell, you do
something like this:
(gdb) b DomainMapperTableHandler.cxx:798
(gdb) r
(gdb) print (*m_pTableSeq)[0][0]
$1 = uno::Sequence of length 2 = {uno::Reference to (XInterface) 0x1a73648, uno::Reference to (XInterface) 0x1a77f68}
(gdb) print (*m_pTableSeq)[0][0][0]
$2 = uno::Reference to (XInterface) 0x1a73648
(gdb) print (*m_pTableSeq)[0][0][1]
$3 = uno::Reference to (XInterface) 0x1a77f68
Not that helpful. Here is how one could work it around:
Technically, it would be possible to make print (*m_pTableSeq)[0][0][0] work
as well, but for a larger class without a pretty-printer that would result in
multiple pages of output. Anyway, _pInterface is the same for all UNO
objects, so something that is not too hard to remember.
An other improvement is the XTextCursor pretty-printer. Example usage:
debugging of the commented text range ODF import. Before:
Finally, I experimented with reworking the textframe code in the RTF filter. In
short, the motivation is to bring the RTF filter in sync with the OOXML one,
which can nicely import and export text box gradients. To get there, there are
3 different problems to solve:
The RTF import filter currently imports rectangle and textbox shapes as
drawinglayer rectangles, even if they have some text inside. Just like the
OOXML import filter, we would better import these shapes as Writer textframes,
as long as they contain some text.
The RTF export writes Writer textframes as old-style Word frames, not as text
box shapes. This should be changed, as the old syntax doesn't support
gradients, and in general both the DOC and DOCX export filters already export
new-style Word frames, so there is no reason why the RTF filter would not do
the same.
Once all the above is done, add support for gradients in the RTF filter, in a
similar way OOXML filters were already improved to handle gradients.
Once this all is done, add new testcases to cover the new code.
First I had hacked on #1, sadly Writer textframes and drawinglayer rectangles
don't share the exactly same UNO API, like drawinglayer has TextWritingMode
and a Name property, Writer textframes have a WritingMode property instead,
and additionally they implement the XNamed UNO interface, etc.
Then I switched to #3 -- there I managed to reuse our existing VML import to do
the hard work: the RTF tokenizer reads the RTF shape properties, then
constructs the same VML model what is normally built from v:fill and v:shadow
XML elements inside DOCX files, finally the VML import does the mapping of
Word's gradient concept to the Writer gradient concept.
At the end of the week I also hacked on #2 and #4 -- and while I did so, I
noticed two more interesting details of Word's new-style RTF textframe markup:
The bad news: Writer supports having different top/left/bottom/right borders,
RTF still just supports the concept of a single line around the textframe.
The good news: old-style RTF frames didn't support different left/right or
top/bottom external margins, but Writer does -- so now using the new syntax,
this is exported properly.
Unrelated to the above, I
fixed
an annoying git bug, when one tried to cherry-pick multiple commits at the same
time, and copy&paste went wrong, the "unrecognized" arguments were just
silently ignored. Now one gets an error instead.
In parallel to the above, Thorsten was kind enough to explain how to update
docs.libreoffice.org: The new output is generated
using doxygen 1.8, it contains a bit more eye-candy. E.g. notice the new
foldable subsections
here. ;-)
If you ever tried to use graphical bullets in Writer (Format -> Bullets and
Numbering -> Graphics), you may have noticed that only the ODF filter can load
and save such a numbering. This is now improved a lot. Motivated by seeing this
is now handled in the binary DOC filter, I now added support for this also to
the DOCX and RTF import and export filters. If you want to play with this
feature, core.git also contains a
DOCX
and an
RTF
sample as well.
LibreOffice started to use Gerrit for code
review, and while occasional contributors
can submit
patches manually, in case one does many reviews, it's handy to use a dedicated
tool. In core.git, we have
logerrit, but
that's not advised for regular reviewers, either,
git-review is recommended
instead.
So I looked into git-review. The good news is that it's packaged already for most distributions, e.g. a simple
zypper in python-git-review
on openSUSE installs it.
I wanted to use this tool for two tasks:
Submitting changes to Gerrit: git review -R could do that. -R prevents
automatic rebase, so a test build won't fail because your patch is based on
an already broken commit. The other good thing is that you don't have to
remember where to submit: both the master and libreoffice-4-0 branches contain
a .gitreview file that contains the necessary server / branch information.
Cherry-picking changes from Gerrit: I found no option for this. A cherry-pick
command is generated on the web interface, but it's more complicated than a
simple <some command> <number of the change>. So I submitted
this change to git-review itself, the next
release will be able to do git review -x <number of the change>.
Probably the browser interface is still the best to comment (especially inline
comment) and approve changes, though David even submitted a
proof of concept patch for that as well.
Finally, let me just clear two myths:
If you use Google for OpenID login, you can have multiple OpenID accounts
associated with your Gerrit login, so it's not a problem (first I thought it
is) if you use one email for Gerrit and an other one for accessing other
Google services.
Somewhere I read that the stock LibreOffice hooks conflict with git-review:
nope, git-review didn't touch the hooks, you can use the tool without
corrupting them in any way.
When you create a rectangle or text frame in Writer, you have two choices. You
can use the draw toolbar to create a drawinglayer rectangle, and you can also
insert a text frame. The drawinglayer shapes are shared between the LibreOffice
applications, and already supported having not only a bitmap or a color but a
gradient or a hatch as a background. The benefit of Writer text frames is that
they can contain anything a normal Writer document can -- think of columns,
tables, etc. These features are not supported by drawinglayer rectangles.
So till now you had to decide what to pick, but it wasn't possible to have
both. LibreOffice 4.1 makes this situation better. Now it's possible to have
gradient backgrounds in Writer text frames as well:
The nice thing is that this feature was already supported by ODF, just not by
Writer, so no such paperwork was needed this time. Also the OOXML filters are
updated. As I already stated in
this comment, the binary
DOC and RTF filters are not yet touched regarding this feature -- though I
already looked into the RTF one, and have some idea what rework is needed there
first.
We spent the last weekend in Brussels, at FOSDEM 2013. Outside attending great
talks, I most enjoyed meeting people I haven't met in person before, in no particual order:
There are multiple strategies how to add testcases for code that sort of works,
but has no or too few tests. One approach (that works quite well in
LibreOffice, for example) is to just add tests for new code, and there the test
is "good", if it passes, but it fails if you revert the corresponding real
change.
An other approach to avoid duplicated tests is to use a tool like lcov, that
can perform line or function coverage analysis for you, so a test is "good" if
it increases the coverage. I wanted to look into this later approach for
LibreOffice, but I decided it's more fun to try this out for a smaller project
first. That's when adding testcases for BitlBee's Skype plugin came into my
mind.
The problem there is that manual testing typically includes multiple online
Skype clients and an IRC client as well, and such tests are extremely
unreliable. So I thought: if I'm able to
mock both the interactive IRC and
Skype clients, then it'll be easy to test the C Skype plugin itself, even for
very special scenarios (like changing a groupchat topic in the middle of
inviting somebody to a groupchat or similar).
For skyped, the exact traffic is recorded and played back later; for BitlBee,
only the outgoing traffic is exact, for the incoming traffic pyexpect allows
just patterns (to allow tolerance for not interesting changes). Once the
framework was available, it was quite easy to add testcases: I already have
70%+ coverage, and I think approaching the 100% function coverage is realistic.
:-)
What was also interesting is that it turned out the latest upstream lcov
release is
not
compatible with gcc-4.7, but the necessary patches are
nowintegrated, and the next
upstream release will work out of the box.
The BitlBee mock files can be found
here. Given
that there are now instructions to do similar analysis for
LibreOffice as well, I
hope to look into increasing test coverage for the classes I maintain as well.