 So the topic of this talk will be a new writing direction in writer, writing from bottom to top, left to right, and you will learn why this is a useful thing and how, hmm, is there a typo? Aha, yeah, bottom to right, yeah. You should just spell it out and it does not feel like a typo. So for those who don't know me, I'm Miklo Shvina, I'm from Hungary, I work for Collabora, and for the purpose of this talk, I'm mostly a writer. So the way this looks like is normally for Latin texts we write, we start at the top left corner of a page and start writing to the right, and once one line is full, then we go down and again start from the left, and we write towards the right edge of the page. Now this is typical for Latin texts and for other texts, this is not so typical, one very common example is Japanese texts where you write vertically as opposed to the horizontal direction of Latin text. So you write from the top towards the bottom and once a line is full, then you go to the left and again from top to the bottom. So it's writing from top to bottom and then from right to left. Now even if vertical scripts are typically right to left, it's possible to also have a vertical script which is from left to right. This traditional Mongolian layout was already supported in Writer, which does this. It's a vertical script, but it goes from the left to the right. But always from left to right or from top to bottom, but never this odd direction than writing from the bottom to the top. You might ask what crazy language needs this writing from the bottom to the top. And of course there are languages which use this script. So if you do your research on the Internet, then you can find that in Indonesia and in the Philippines there are about three minority languages which actually use this direction. But this is not really a motivation factor to add support for this. The real motivation is that you can have a table saw or a shape, a text from your writer with Latin text, and let's just do table saws. You have some large table with Latin text and you have several rows and you want to have row headers. And that means that on the first column you want to have some text which is rotated to the left. And technically that will be exactly this bottom to the top, left to right direction. So this is why this was more interesting. And of course a word supports this direction so it makes sense to improve a writer to be on par with word in this regard. Similarly, not only for table saws, also for writer text frames, it's possible to have this rotate to the right or rotate to the left direction. A real word use case was like having some meeting and then we have these papers with printed names. And typically the name is printed on both sides. So if you are the person who are trying to find a place, then you can read your name and those are the attendees see your name. So that means that you want one document with two shapes and the same content but once rotated to the right and rotated to the left for the other shape. For this you need the support for this writing direction. So once this BTLR direction was working in table saws and frames, it looks like basically the rendering is done but there are more things to support. One is the traveling. When you reach your cursor saw which has this writing direction, then based on, for example, Japanese text, you expect that we won't interpret your arrow keyboard events literally, but there is the logical level and the physical level. Which means that in these tags, the physical arrow actually means that in the document model you logically want to move to the right and when you press the love then it should be in the document model you actually would like to move up to the previous paragraph and so on. Similarly, when you do a selection, you expect that you just create a selection that spans over two document model positions and when you create the selection then there is this cursor overlay that shows you what span in the document model you selected and you expect that just because the content, like the render text is rotated and this cursor overlay should be also rotated and match your text. But if you don't do anything explicitly then the cursor overlay will stay as is and it will look funny. Also, just because you have some document which is rendered properly and you have your cursor traveling sorted out and selection working, it does not mean that when you interactively modify the document it will behave correctly. For that to work it is necessary that whenever you edit the document, like type on the keyboard, then some part of the document will be invalidated and repainted and those repaint events have to work with the correct rectangle and you need to do the rotation from the physical level to the logical level and backwards correctly otherwise we will repaint some area which was already correct and we won't repaint some other area which will mean that your cursor will move what the actual text content won't update as you type. With this sorted out we probably want to save this file and we expect that once you load the file back to the in-memory document model then your writing direction is still there. The problem there is that ODF relies on accessible to define what are the possible writing directions and we use a very old accessible version in the ODF Spark at the moment which does not support this writing direction. So at the moment this is going to the LibreOffice extension namespace and then in some future moment it will be possible to just write it normally similar to the other directions. Once ODF was working it's also useful if the word filters are updated given that it's word that has support for this. So first the docax, the binary doc and the RTF filter is now updated both import and export to Dividus. In case of word this is mostly table saw since one thing and then we have two cases with the shapes where you have some shape and the shape text and those are the case when we have this write or text frame which is interesting from the export point of view because you can have a write or text frame with content and those will shape with some text but when we import them all of these constructs are they do have the same markup in the word formats so when we import them it's always shape with some text. That's basically what's working. I can give you some short demo I say so the way this works is that you want to have some dummy text or maybe that's too much something like this and let's say you insert table it's a bit short remote control I'm looking at that monitor too is that something so this would be the normal text and let's try this kind of Japanese direction or you say it's vertical but from top to bottom so that would be it you say this is where we start and go down to the end of the line and then right to left so we stop to bottom and down right to left and we can even leave the content there and we need to somehow get rid of spa check then we go to the vertical bottom to top saying and it works but we used to have in place was much much worse in that case no I don't want to say this what used to be the case was that you can do rotation on a character level and as long as your whole text content is a single line like no multiple paragraphs no multiple lines actually not even multiple text portions just just a few words then it looks like it's working and you can get away with that for a few years and then sooner or later somebody notices is that this is not actually working so the first thing is when working on this it was the document model it was like finding the right place where this can be stored it's like moving around with your super mario character and you try to not break an essay and just just introducing this little really little thing and actually this is not too complex what what happens is that in edit engine we have an enumeration for the possible writing directions and you can just add a new enumerator at the end and then you need to find the places where this enumeration is handled and then find out how to handle your new case when when this new direction is used there was one one tricky part there because the last enumerator is called this is the ad like this is the last one and of course there was some code which was already not using this this and when and when it iterating through the various possible writing directions which means that the code was already in some inconsistent case and you know have to touch it and then you don't know what you break so I did it in two stages first I tried to fix up these places which already did not support all the existing writing directions and once that was done then it's really just adding a new enumerator at the end also it's important that this limitation was was only inside writer so VCL itself is happy to draw text in either direction no matter if you rotate to the left or rotate to the right it just really wants an angle and it doesn't matter if this is 19 90 degrees or 270 degrees that was already working like you can have this in calc already that one that was nothing new so what was missing is the writer piece also then it was necessary to extend the UNO API for this while touching the UNO API which means that you deal with painful compatibility like this large clock which had some nice way to put it on the wall and you have the new or new clock which is actually working and then you stitch the two together and it's ugly but it's compatible this is typically our UNO API now the good news here is that this writing mode for at least for the writer case is already a set of published constants so that's something you can actually extend it's a bit painful to use but at least you can extend that without compatibility concerns and then the layout yeah so actually I started working on this already I sort back it was six years ago and it was the layout where I just gave up and I went for some short work around for that specific case because for the layout to work at least when you add one of these new writing directions it's like you need to do a lot of changes in one step you can't really break down to sub tasks and once at the very end it compiles then you start Libroface and either it works or nothing shows up on the screen and then you have to debug it but it's very hard to do it in small steps you're really just there is about like 100 lines of code or something like that that you just need to write it and it has to be bug free otherwise nothing is showing on the screen and and you can't split this to some more incremental stuffs so first what we already had we had there should be some somewhere I have a list of what's existing direction we support but basically what we have we have the normal latin script or latin direction we had this what I call the japanese direction we had this traditional mongolian direction that's it just this tree but I added was this force one for this bottom to top direction and what we have is that we have this writer rectangle function collection which means it's an abstraction you can use to describe that in in some abstracted way or logical way I want to let's say count the difference of two horizontal directions like logically horizontal and then you know the direction itself should know how to do this in a physical way so that means if I want to compare two horizontal positions in for some latin text that means that the right position is always larger than the left position which means that I need to extract the left from the right but from bottom to top that means that the bottom value will actually the horizontal position will be physically a vertical position and also between the vertical positions it will be the the left but what's logically left will be the larger value and the logical right will be the smaller value so I still need to subtract the two values but the order is different and stuff like this and there is some basically this is an array of function point or something like 60 operations or something like this and once you put all of these in and you do it correctly is just if you just count it on the paper and then based on that you you put it in then after some struggling it's actually working this is one thing the other thing is that we have lots of boolean flags in this sw frames which is the building block for pages and paragraphs and everything in writer if this is a horizontal or vertical frame if this is vertical if this is left to right or right right to left and now we have this last mode where it's not enough that it's vertical and left to right but it's not top to bottom but it's bottom to top so all in all oh yes and one more thing is that part of the code uses this abstraction and that means once once your rectangle function collection is implemented it just works but there are some other code which is using these operations directly which means that first you have to swap the rectangle like swap the height and the width and then do your work and then swap it back so we might need to do the swapping for just horizontal or vertical positions we might like the religious integers or we might work with the 2d point or we want to have a rectangle for this swapping and then we have the different writing directions and you might want to convert from physical to logical or the other way around and the rectangle might be already swapped or not so that means just for one direction it's like 12 cases and then of course the support for this new direction was needed as well so it's a bit tricky but this is the really the challenging part of this once this was sorted out then the rest is actually more like just following what the other directions already do and it's not that tricky so yeah it's working as you said what else about how this is implemented as mentioned the odf filter can't just use the the bt lr markup because this that would be too new access and the problem is that we don't really have support for this scenario in the odf filter where you have some uno property with a given enumeration they map to an xml attribute but depending on the actual value we use either a stock namespace or an extension namespace so you can't just nicely add one more item to some static array and be done with the odf filter you need to explicitly check for this direction and if that's it then you need to use the extension namespace hopefully in the long run this just goes away then updating the work format was actually quite quite easy and like we all like when you can just delete 100 lines of code and add two instead and it works better so once I was able to delete this start and and miserable hack for unsupported direction yeah that was doing this character level rotation and then on the export it tried to detect what this mangling how it was done and undo that and then write it to the file format so all of this can be just deleted and instead locate where the Japanese direction is handled and just one more case with the opposite rotation and that's it so that that was that was nice what else how to task this so the biggest candidate is the filter task so for each file format you can just manually produce some document load that assert that you have the correct writing direction do around rape and assert again but I also wanted to test this at a layout level like how how the exact rendering looks like because if I export to PDF from writer and then from from word then I can do this nice vector level the thing between the two outputs and make sure that really at the level our output for some simple rotated taxes exactly matching what word does and this actually found some some baseline positioning problem where like you just have a coordinate where to pintize but it's not not a bias if that should be the top right or the baseline or the bottom bottom top left bottom baseline or bottom left corner of the text so of course at first iteration I did not get that right but after being able to test it this way then then it was possible to track down why we have this different of some and also with with writer has this UI test cute still in the inside in in CPP unit then there you can test what invalidation rectangles we issue and based on that you can assert that we actually invalidate the correct area one type in and for the real UI dialogues then we have this nice UI testing you can do that yeah then for the user interface the table saws and this writer tax frames have totally different user interface but in both cases it was reasonably logical to where to add one more UI like one more item to UI list box and that's how the user can actually create a new table cell or or text frame or shape text or what not with this writing direction with the specifications part I just asked under ash to please send me this proposal it's it's really easy you just need to update this new or access our reference in the spark and then it will be possible to just use BTLR for the writing direction I guess we need to I guess it's I already missed the 1.3 boat so in some seven years if we've been the spark and then we can get rid of our extension namespace sign and that's about it usually at the end there is some thank you slide for the customer who paid for this but this is an exception we used to have some a quick in February bar for one week you could do something interesting and this was something that was on my to do for several years and I remember that I've failed this one so I was curious if maybe over the years you learn some experience and maybe if you attack the same problems one more time maybe this time you succeed and yeah I was more lucky this time so the takeaway is that this is working for two for headers of table rows also in tax frames and shape taxed and we have a global office a snapshot which already has this working most of this work is already shipping in Libreface 63 you can't create tax frames with this writing version that that means the that line of reach offers so it will be in the next 64 and yeah that's it if there was anything in the slide and it was too fast and they are up and they will be also on the conference side so thanks for listening I'm not really dealing great with time but if there is some question yeah one question yeah Tor it's a so the question was how RTR taxed is playing in this game that's a different level so at this level when I say Latin taxed and I say that it's love to write actually it might be right to love but because that's just at the tax portion level so we don't really worry about that we at at this level we don't have a separate writing direction for for scripts like Arabic because that's basically handled for VC and then VCR so that's not a problem for writer I did not try right to love the scripts with with this rotation so I don't know how that works if you are lucky then it works out of the mocks otherwise let's wait for the first bug report no I'm not saying I'm running out of time thanks again