[00:00.000 --> 00:17.000] It's easy, you know, because my laptop doesn't really like how it's being disconnected from the laptop. [00:30.000 --> 00:48.000] Hello, my name is Paris and my talk is about supporting old proprietary graphic formats. [00:48.000 --> 00:55.000] Specifically, we're going to be talking about the WMF and the EMF formats from Windows. [00:55.000 --> 01:03.000] So what is a WMF? And this also applies to the EMFs, but the WMF is a Windows metafile. [01:03.000 --> 01:09.000] It is a graphics format that supports vector and raster operations, mostly vector. [01:09.000 --> 01:13.000] It was introduced in the early 1990s in comparison. [01:13.000 --> 01:18.000] A different vector format like the SVG was released in 2001. [01:18.000 --> 01:23.000] It is composed of a set of GDI drawing commands and structures. [01:23.000 --> 01:31.000] These drawing commands are played back in order to render the graphic within what is known as the playback device context. [01:31.000 --> 01:35.000] And it is not as widely supported as SVGs. [01:35.000 --> 01:43.000] Essentially, this means that you can code this format into existence by writing some GDI functions. [01:43.000 --> 01:48.000] What are the difficulties in supporting this format? [01:48.000 --> 01:53.000] So the WMF files are application and device dependent. [01:53.000 --> 02:04.000] The EMF files later, that were later introduced, try to solve this issue, but the WMF files are more difficult in that way. [02:04.000 --> 02:09.000] The device context that is associated with a WMF file cannot be queried. [02:09.000 --> 02:15.000] That is, an application cannot retrieve the device resolution data, font metrics, and so on. [02:15.000 --> 02:21.000] So if you made a WMF file for a specific device, you cannot really know. [02:21.000 --> 02:27.000] If you tried running on a different device, you don't really know the device it was built for. [02:27.000 --> 02:32.000] There is a format specification for this, but a lot of things are missing. [02:32.000 --> 02:36.000] And there is some edge cases with undefined behavior. [02:36.000 --> 02:41.000] And pinpointing the root cause of a buggy file can be tricky. [02:42.000 --> 02:44.000] So how do you debug a WMF? [02:44.000 --> 02:51.000] Well, there's a lot of ways. I'm going to present the way that I do it, usually. [02:51.000 --> 02:55.000] So you would want to get the drawing commands, the GDI drawing commands, [02:55.000 --> 02:58.000] and there is multiple ways of doing so, more than I listed. [02:58.000 --> 03:00.000] One is MSO Dumper. [03:00.000 --> 03:06.000] It is created and used by LibreOffice developers, and it dumps the drawing commands. [03:06.000 --> 03:09.000] Another one is the Metafile Explorer. [03:09.000 --> 03:13.000] It allows for viewing and stepping through the drawing commands, [03:13.000 --> 03:17.000] so you can easily understand which command does what. [03:17.000 --> 03:22.000] And then there is the Metafile GDI function, which is defined in the GDI header, [03:22.000 --> 03:27.000] which allows to enumerate the drawing commands in WMF file and call a callback function. [03:27.000 --> 03:32.000] A similar function also exists for EMF files. [03:32.000 --> 03:35.000] This is an example of an WMF drawing command. [03:35.000 --> 03:37.000] WMF drawing commands look very similar, of course. [03:37.000 --> 03:40.000] It's the function signature. It takes some parameters, [03:40.000 --> 03:48.000] and this is what the record looks within the file if you open it in the aforementioned debugger. [03:48.000 --> 03:54.000] So it's very similar to the function signature itself. [03:54.000 --> 03:59.000] After you obtain the drawing commands, well, you want to debug. [03:59.000 --> 04:04.000] Because WMF is such a platform-dependent graphic format, [04:04.000 --> 04:12.000] sometimes it's good to compare with other WMF reader implementations like PowerPoint [04:12.000 --> 04:20.000] to understand exactly what the graphic looks like in other implementations. [04:20.000 --> 04:25.000] Then you would want to identify which drawing commands cause the bug. [04:25.000 --> 04:28.000] You would, you know, the drawing commands that you obtained, [04:28.000 --> 04:35.000] you would step through them and try to pinpoint what exactly causes the bug. [04:35.000 --> 04:40.000] It is important to also reduce the relevant commands as much as possible. [04:40.000 --> 04:44.000] WMF files can contain thousands of drawing commands, [04:44.000 --> 04:48.000] and stepping through all of them is very tricky. [04:48.000 --> 04:51.000] A way to do this is to simplify the problematic file [04:51.000 --> 04:56.000] or make a new one that reproduces the bug in LibreOffice. [04:56.000 --> 05:02.000] And then you work around these buggy commands to find out what is wrong. [05:02.000 --> 05:06.000] Easier said than done, but yeah. [05:06.000 --> 05:10.000] Finally, you want to make sure you didn't break something. [05:10.000 --> 05:16.000] It is good to create a unit test for your fix using the minimally reproducible example you created before. [05:16.000 --> 05:18.000] You run the appropriate test suits. [05:18.000 --> 05:21.000] You probably broke something, so you go back to step one. [05:21.000 --> 05:25.000] And then you confirm that round-tripping works as expected. [05:25.000 --> 05:30.000] And you also, I should mention, monitor the WMF file, [05:30.000 --> 05:36.000] the fix you made for WMF file to make sure it doesn't break something in the future. [05:36.000 --> 05:39.000] And that is all. Thank you.