 Welcome to my Multi-Page Floating Table in Writer Talk. In this talk, we will cover a new Writer feature, which is a combination of Multi-Page tables, which was already available in Writer, combined with floating tables, which was already available in Writer. This feature is a combination of floating objects, floating frames, floating fly frames, containing a single, exactly a single table. If you don't know me, I'm around the LibreOffice and Colobora Online Committee for a while. I used to work on Writer for a while now, and this year I mostly worked on this feature. Here is a screenshot showing you what we tried to achieve here. What you see is a two-page document. It has a single floating table, but the floating table has a large enough height that it does not fit page 1, so it has to also flow to page 2. It's spanning over two pages. You can see that it's very hard to get this setup with two explicitly created frames and just chaining them, because the number of tables created will depend on the content inside the frames. They are created on demand. You can see that they're not just a simple multi-page table. Also, there is an encore text wrapping around the table on the last page. By the last page only, because we want to be compatible with the matching word feature, and that has this default behavior. You can also see that inside the table, it is possible to split the various text frames like paragraphs. Inside a single cell frame, they are okay to split. We can also have multiple columns. This is meant to be a true combination of multi-page tables and floating tables, like tables inside floating frames. That looks simple, but the complexity also comes from how this feature is interacting with the various other features or the existing writer. We want to provide some consistent experience. What you will see now is a selection of features where multi-page floating tables are interacting with those things and how we try to make something consistent. The first thing is you can click on these frames and you can get selection handles. Really, just the first page position is controlled by the user. The later frames are calculated by the layout. For the horizontal position, we will copy the positioning attributes. For the vertical position, we will just continue from the top of the page. This means that it doesn't make sense to allow the user to click on the follow frame, like a second frame. We want the user to click on the master frame, the frame on the first page, and then it makes sense to drag the frame around. Otherwise, it would look like you can drag the frame around, but once you release the frame, it will again jump up to the top of the page and that would be annoying. We have explicit code in place to make sure that whenever you try to drag such a multi-page table, we always drag the first page frame. The second sample where we are interacting with something or the existing is floating tables inside footers. These are, by definition, have to be one page because the footer is repeating on each and every page, so you won't get more space by splitting the table and moving it to the next page because you can only have a subset of a one-page area for the footer. The layout logic knows this and it will explicitly try to not split when the anchor position is inside the footer. Another interesting area is when we position the anchor, it can be either directly inside the body text that was visible in the very first sample, but it can be also inside the section. In case it's inside the section, then we create a new page and we want to split the anchor so that there is an anchor point on the first page and the second page, then we want to make sure that the second page also has some split section frame and only done inside that we have our second anchor frame. So that needed explicit pairing the floating frame feature with the section one. Another corner case is what happens in case the table has some page break before. In case the table moves inside some fly frame, then we typically ignore this request because it does not make sense to have a fly frame containing a page break. Now in this case, we need to move that page break to the anchor point and make sure that as we duplicate the anchor point to have an anchor on the first page and the second page, only the first page has this page break before behavior. So this again needed explicit fixing. Then it's an interesting question what happens in case you have a multi-column section. It turns out that we don't want to have the table flow across multiple columns because this gives us a compatible word behavior and also it's a very rare combination and it would be a lot of work to make sure that this works because equally distributing content across multiple columns is quite complex. So increasing that complexity with this multi-page floating table would just cause a lot of trouble. Then we want to have some UI for this. You can right-click on the frame and get this frame properties dialog and now there is a new checkbox there if the frame is allowed to split across pages or not. Now allowing this, so going from the disabled to enable state was something I added quite early so that was perhaps the easier part but we also want the other way around in case it's already split then you want to be able to master fly to join the flow fly. So that's no possible and it's working. We have the necessary fly frame format to fly frame notification in place so that this works as is intended. Now another related feature is this explicit pairing between two fly frames in the document model. We have this feature that if you explicitly create these frames you can chain them and this doesn't make sense in case the first frame is allowed to split because then it's not clear what happens when you have typed enough content that it does not fit the page anymore. Should it flow to the next frame? Should it explicitly create a frame in the chain or should it split? So we don't allow this chaining on the UI to avoid trouble. The users now have a hard time to create this confusing document model and this means that either you chain your frames but then we don't split or you split but then you don't chain. Another kind of hidden feature is that you can have a per document setting where you say that you don't want to split these frames in any case you might have multiple floating tables perhaps splitting is allowed for one table but not for the other and still with one setting you want to disable the split for everything. This is again important for older documents because for example in the original RTF format this was not allowed so now we have two levels one is a per document setting which is disabling this split at a layout level and also we have this per frame setting. Keeping the per frame setting is still useful in case the per frame setting says that it's okay to split and the fly frame contains a single table then on export to word formats we can map this to a floating table otherwise we will just create a shape and that will contain that table but then it won't span over multiple pages. Another case is when you have a section break in word formats between two tables we need to decide how we map these two writers sometimes we map it to a writer section sometimes it's a page break in this case the type of the section break is next page so we map it to a next page section break and in this case we need to make sure that by default you will just get the two tables and there is no text node in between that would have the page break before attribute so we need to arrange things suitably that there is one anchor on the first page there is one anchor on the second page and still we can have a model where the first page has no page break before but the second page has then there is trouble with nasty tables now this is not fully solved but there is one case which is the easier part and that's already working the case is that you have some multi-page floating table in the outdoor case and the inner case is a floating table but there we don't allow splitting between multiple pages and that allows rendering a document similar to the one on the screenshot properly because in this case it's important that it's a floating table even for the inner one in this case it would be an inline table then it would require more space and possibly that image on the inside the outdoor table would shift to the next page and it would lead to incorrect layout then another complexity is the negative vertical offsets for these floating tables the offsets determine what will be the position of the table so you have some starting position which is the top left corner of the paragraph that's serving as an anchor point and then you typically have some positive vertical and positive horizontal offset there now let's ignore the horizontal part let's say that it's 0 you can have a vertical offset in case the vertical offset is positive then it will shift the table down and in case it's negative then it will shift the table up now the question is what happens in case we have two pages we have these three tables and the third table has an anchor on the second page and it has a negative offset so one option is that it's shifted up and it will intersect with the header area of the page another option is that we say that there is space on the previous page so perhaps we can have the table there and it's a conflict you need to solve it in some way and whatever is the decision somebody will be unhappy so the decision I took is that it turns out that word has an answer for this it always shifts the table to the previous page so in the word compact mode we do the same so that we provide the matching layout so this is a bit confusing so you have a table then you have some tags after the table that paragraph will serve as an anchor for the first table you do the same for the second table and its anchor but then there is another paragraph after the second table and then there is the anchor for the third table and this third table is positioned in a way so that in the layout the third table appears first then comes some content which is like before the third table in the document model and the nominal anchor point is already on the next page so that's quite complicated and now we provide a layout which is matching the expectations with existing word format documents then another complexity was what happens in case the anchor text is starting with some content which nominally does not have any width like a new line character the trouble there is that when you start your paragraph with a new line character then you will have two lines the first line width will have some height but no width and the second line will actually have some content now the trouble is that the layout can easily figure out that you have some line which has a width which means that it's okay to move it up to some previous page but then later we figure out that we want to wrap this content only on the last page so we will move the new line down to the second page and then move up again, move it down again and it's a layout limit we needed explicit checking that even in case the very first part of the anchor text would fit some previous pages then we don't move that content up and this way we have a stable layout result another complexity is what happens in case you anchor your floating table in some paragraph and that paragraph would be hidden in that case in Warn the table is still visible just the paragraph that's serving as an anchor point like the next paragraph is hidden in our case in case we hide the paragraph then all the objects which are anchored inside that paragraph are also hidden so what you see here is three screenshots the one on the left is some odd behavior you can see that it has some image and some text content the center one is the new behavior in writer but you see there is some image and then there is some table followed by that it's basically used to create some two column layout and on the right you see the word result which is more or less matching our new behavior so what we do is that in case this is something that we handle at import time in case the anchor would be hidden but it's hosting some floating tables then we ignore the hidden request for that anchor paragraph so that it doesn't look like your content would be lost ten another setting is there is some setting on each and every floating table in case overlap with other tables is allowed or not in our case we map the floating tables to a text frame which has exactly one table so we already had these settings for shapes to control if overlap is allowed or not but that was not hooked up with the split frames layout mechanism so what you see on the left is how the document requested that no overlap happens but we ignore that and just by like reading the positioning attributes we had an overlap on the left side that was the odd writer behavior the center one is the new writer behavior we figure out that once the table one is positioned then table two has to be shifted down otherwise an overlap would happen and on the right side you see what word is doing the new writer one and the word behavior is now matching then another problem was what happens with table borders what we had before is we have some table we split it to two we move the second part to the next page which means that the bottom of the first page and the top of the second page will have incorrect table borders now what we can do is that we can infer that in case it has a top border then it has to have a matching bottom border on the first page and similarly on the second page in case it has a bottom border then we can infer that it has to have a top border on the second page so again on the left side you see the odd writer behavior on the center you see the new writer behavior and on the right hand side you see that this is no matching one in all these cases I try to do this carefully so that you only get the new in case it would be an incompatible change then we keep the odd behavior for existing audio documents but we do the new behavior for word documents and when the behavior looks like it makes sense then let's have it also for new documents then another complexity is what happens with footnotes inside tables footnotes inside tables is okay but you can't have footnotes inside fly frames which means that in case we put the table to a fly frame so that it's a floating table we lose the footnotes the previous answer for this was that okay, in case it has footnotes we won't convert it to a floating frame but then the floating table will have incorrect layout left hand side is showing some document which has a footnote and also some text below the table the right hand side is the word one you can see that the footnote is there but because the table is floating the next space where the normal inline paragraph text can appear is at the top of the table and now in the center you can see the new writer behavior we now support footnotes inside floating tables which gives you both the footnote and the text at the right position marked with the rad rectangle so now you might wonder how this is implemented so let's go through how this is working from the source code point of view what we do and the document model level is that we have this fly frame format which is hosting the attributes for the floating frame and that has this container for the properties the item set and there is no new pool items subclass there which is determining if the fly frame is okay to split or not and there is a matching key constant which allows you to look this up then at the UNO API there is no new property called is split allowed on the text frame if this is true and it contains exactly one table then that's a floating frame floating table now the layout is quite exciting that's where all the complexity is and so the design started basically what Michal suggested like six years ago why not extend fly frames so that they are also flow frames which already know this logic how to span over multiple pages and it's easier to say that than do that but that's more or less what I did so what you see on the screenshot is we have these text frames which are anchored at paragraph and the anchor point then the frame height is also is always automatic so that it will span over multiple pages as the content needs it then we always have an anchor point and we also have a point which is the top left of the position frame then the last page we do this wrapping so that the text frames which are the anchors always have some offset which basically is the character position inside the paragraph that is the starting point on that page so in all pages this is zero which means that on the last page we start from the start of the anchor text and we float that around the floating table and as mentioned one complexity is that even in case the user configures the first page in a way that the floating table is shifted down we only consider this on the first page on in later pages we always start from the top of the page another problem is that even word itself has different behaviors for older versions and today in older versions it's okay to overlap the floating table with the footer area and the newer version it's a bit more sane this is not allowed we support both cases to have correct rendering for all of these documents then for filters in the oddity case it's a new optional attribute on the draw frame element to decide if this frame is okay to break across pages or not in the docax case there was an explicit markup for this position tables or table positioning properties and doc and rtf had again something similar also this document model per document don't split tables in any case something needed explicit support in the filters and also the frame level don't overlap something needed explicit support so all this feature is created so far it looks nice and works in some sensible way we want to have testing so that it stays this way I have some tasks which load word documents and we assert the layout so that you can manually also open it in Word and you can compare that we do a correct job we also sometimes build document models from C++ code and assert what the layout does we do some UI testing for the UI dialogs I'm also monitoring crash testing watching the tinderboxes in case they find any problems and like for example the tinderbox that's building the code with sanitizers is very helpful to point out memory problems this is how the UI looks like it's really just one check both there so the UI part is easy it's far from true where to how to far from trivial to decide how to represent this in ODEA there was a discussion about that on the developer mail list and the conclusion is that similar to the z-order of these frames we will have an attribute there to decide if it's okay to split or not for the no overlapping per shape or per frame setting there is already a markup for shapes we can reuse that and the per document setting to completely disable this splitting behavior is going to the settings similar to the other compatibility settings so that's not part of the SPAC we can just add new values there so this is where we are this feature was requested like 10 years ago I'm very happy that a funding known was available to actually create this feature its first part is shipping in LibreOffice 7.6 also in Colabor Online that was the main motivation on our side but it's really at the core of writer so the intention is that everyone is benefit both desktop LibreOffice and Colabor Online users it feels like more than half of the work is done but there are missing bits like full support for nesting this floating tables is one thing and there are many many cases like how this interacts with change tracking the various compatibility modes mini-marrow, hide, and soon and soon I still have a list of what small things to check how this new feature is interactive with the existing one to provide some consistent experience and by default we do what today's work does for the splitting behavior but also we care about older documents which should hopefully give users an experience which is what they expect thanks for watching that was it and thanks for the ones who funded this feature so that we could add it to LibreOffice thanks for watching bye