Apache OpenOffice (AOO) Bugzilla – Issue 105655
printing files with FontWork very slowwww
Last modified: 2010-01-19 12:18:10 UTC
Report from a Dutch user: - file with fontwork objects (32 ...) takes about a quarter of an hour to get it printed, ate 100% of one of the four cores, and made a printjob of 15071 KB. Report from me: - file with fontwork takes minutes to print Both files will be attached
Created attachment 65182 [details] file with 32 fontwork objects
Created attachment 65183 [details] file with one fontwork objects
AW: Took a quick look. All FontWork objects with 3D will get converted to a BitmapEx containing the 3D scene in printer resolution. That resolution is limited to 1000000 square pixels per scene (can be adjusted in the configuration), so maybe the printer resolution uses this, but it's needed ro quality. This will explain some of the runtime and memory needs. I then broke the process in the debugger and saw, that the most time is spent in RemoveTransparenciesFromMetaFile. AW->PL: Directly breaked at RemoveTransparenciesFromMetaFile in ImplQPrinter::PrePrintPage; getting there from print needed 5 seconds, while getting over it took 5 minutes 12 seconds. You had a look at RemoveTransparenciesFromMetaFile recently, what's going on there? BTW: Printing works correctly and after the method, it's only another second to get the print output.
pl->aw: RemoveTransparenciesFromMetaFile loops over the MetaFile, finds contiguous regions that contain transparent actions and replaces those actions with plain bitmaps (by rendering the MetaActions in each region to a VirtualDevice and exchanging them in the output MetaFile with a DrawBitmap action). It also has a tiling strategy as to not produce overly large single bitmaps (as e.g. many printers have physical limits for bitmap sizes). Thorsten invented that method, so I'll set him on CC.
Now, I didn't invent it, but I was basically the last one changing substantial parts of it, yeah. Looking at the odg, it generates a metafile with 216797 actions, which seems a bit over the top for the 32 font works - given that this is ok, everything needed to significantly improve performance amounts to (another) rewrite of that method. As the comments state, the algorithm used there has a worst-case time complexity of O(n^3). There are short-cuts in place already that handle simple transparency-over-background cases already; in this case, the mtf though seems to contain gazillions of overlapping, transparent objects, which, at that point & with most of the high-level information thrown away, can only be handled the hard way. So the quick fix is to reduce the amount of meta actions (if possible), the root cause fix would mean re-thinking the transparency emulation algorithm (one could, when doing that anyway, also re-consider the split up only along axis-aligned boxes; other print engines e.g. use polygonal clips (needs level2), which tends to result in smaller bitmap areas), or, and that would be my recommendation, go for pdf-based printing & delegate transparency handling to the printer driver, where it belongs.
pl was missing from Cc, @pl: see my previous comment.
I agree 32 fontworks is a bit too much to be considered a 'normal', average document. But take the second one. Takes 35 seconds to print for me ... Also changing windows (alt-tab) shows clear delay (appr. 3 seconds) to show the document. Thanks for all you attention to this issue, Cor
@cornouws: nah, 32 font works should not be a problem; my "over the top" statement referred to the amount of meta actions this generates internally (which of course should also work, but in this case, seems to trigger the near-worst-case scenario in the algorithm).
@thb: thnx, clear now!
Reassigned.
changing target as this is an annoying problem.
AW: I have no idea what i should do with this task. I have nothing to do with printing or to do it using MetaFiles at all. I have to do with MetaFile creation, though. I can clearly state that for 3D FontWork objects, a single BitmapEx as MetaFile action gets created, nothing else. So i have no idea what might create 216797 actions all together, but i will take a look...
thb: PDF based printing is a rather CUPS centric point of view. This will not help us at all for 90% of the user base.
@pl: indeed. and xps is likely not something to bet on _yet_ ... :/
<possibly dumb remark> I was just looking at #75154 and reading the last comment could the number of colors in OOo have anything to do with performance on some areas? </possibly dumb remark>
AW: Checked the various object types which were used in the document, e.g. first line left to right, calling them (a) to (d). Check can be done by anyone by converting the object to MetaFile (context menu) and then breaking it. (a) creates 3554 polygon objects on breaking the Metafile. Reason is the fat line geometry (line width != 0). There are actions in the MetaFile for fat line, but using them will lose the edge roundings (for which we have NO actions in the MetaFile). No transparent objects created. (b) creates 2800 polygon objects. Problem is the same, but doubles with shadow. No transparent objects, though. (c) creates a single, transparent BitmapEx object. (d) creates 220 draw objects, one transparent BitmapEx for the colored shape and the rest projected polygons for the 3D shadow. That 3D shadow shapes are not merged to a single shape (ORed) since this operation isalso expensive and would slow down paint extremely. So all in all the problem is not only transparency, but also fat line geometry. Unfortunately there is no MetaFile action for edge rounding, and it's not easy to add one (problems involved here should be known). Besides all the object count, the repaint is still good when the whole page content is converted to Metafile. AW->THB: There MUST be a way to better create those transparencies, even with a lot of objects. In one line, there are only two transparent BitmapEx shapes, not overlapping each other. Creating a bitmap for each of these areas does not explain the time currently spent.
@aw: ok, let me find some time somewhere & have a deeper look ...
Ok. So right off, there's no easy way. I first noticed that the shadows for fontwork type (d) consist of quite a few separate polygons; disabling that shadow though does not help - _every_ other object on the page needs to be considered, too; so the ~200k actions really count here. And that's because calculating those axis-aligned connected components is a _wicked_ problem. It would be much easier to calculate polygonal areas, which we deliberately decided against back in the day, as this would have required bitmasks in postscript. The algorithm performs so badly in this case, because for every addition to a connected component region, it's area grows in quite ill-natured ways - it requires checking the new area against _all_ other existing connected components (which can be quite a lot, when you consider the fat line emulation and some intermediate states there). There's likely no way around this, and it's also necessary to check _every_ metaaction, since it's potentially possible that they'll, all together, somehow intersect with a transparent action. Armin, Andre & myself once spent various days pondering this problem. So I have to repeat my analysis - either reduce the input set, or use polygonal regions (would also kill two birds with one stone, in that bit-masked bitmaps would not be a "transparency"-to-be-emulated-case in the first place), or push transparency directly to the printer. I'm sorry.
AW->THB: Has the algo have to be that complicated? Wouldn't it be enough to once collect a List of Rects of transparent objects, and then paint all of them to bitmaps? Why is this magic 'growing' needed...?
@aw: because you get visible seams otherwise. one half of the object rendered in a bitmap, the other as a polygon. so you have to determine a self-contained set of objects (and the complexity of that pretty much depends on what the permissible border geometry looks like).
to print attachment http://www.openoffice.org/nonav/issues/showattachment.cgi/65183/Issue105655_nl_Promo.odt takes appr. three times as long on 3.1.1 as in 2.1/2.2/2.3.1 (some old installations I have at hand) This is known?
AW->cornouws: Yes, that's mainly because the geometry for fat lines needs to be represented as decomposed geometry to include the line joins. As said, the MetaFile does not have any possibility to handle that information. AW: To solve this, i tried to expand the MetaFile to include such action. As a start, i expanded LineInfo and it's streaming operators. Luckily, there is a version info written/read in the file, so this indeed is possible. The bad news starts when You try to use it; e.g. when saving a SVM (our own MetaFile format, also used for OLEs), the stream operators at the MetaActions are not used, but a class called SVMConverter. And guess what, there is NO version information and NO way to add LineJoin info in a compatible way. Sigh :-( All in all the MetaFile handling has VARIOUS ways to save/load them which cannot all easily been found and not all of them can be expanded. So, a MetaFile which went through a save/load cycle is NOT guaranteed the same MetaFile as before. Ahhh! Investigating further if i can in any way hack the handling of the actions META_LINE_ACTION and META_POLYLINE_ACTION in SVMConverter...
AW: Have now added a GDI_LINEJOIN_ACTION to SVMConverter whcih gets written at META_LINE_ACTION and META_POLYLINE_ACTION when line is fat and has a join != ROUNDED (the default). Building without debug to check the speed, especially for fixes like #i101491# which will be influenced by this. Looking for the number of actions created with this change... (Also changed OutputDevice::DrawPolyLine (the basegfx::B2DPolygon version) which had a missing else at the end, also figured out a way to support basegfx::B2DLINEJOIN_NONE under GDI+ without GDI+ supporting it)...
AW: It solves the printer speed problem (the amount of MetaFile actions is reduced, i'll look into it in debug mode, but just using the bugdoc is good), but the bugdoc from mentined #i101491# seems slower. I'll need to check that. I'll also have to check all usages of MetaLineAction and MetaPolyLineAction in all filters...
AW: Speed of the chart BugDoc (#i101491#) has reduced; it looks like the GDI+ FatLine paint is slower (2-3 times) than the old VCL rough polygon expansion (without LineJoin, of course). Need to get that faster, experimenting...
AW: (a) breaks to 26, (b) to 26, (c) to 1, (d) to 219 draw objects, so the problem with many objects is solved. Also converting to Metafile various EdgeRounding objects works now (the LineJoins stay), but not yet over many exports. It works for OLE now, but i have to look into various exports...
AW: I have used the bugdoc from #i101491# and looked for paint speed of fat lines. GDI+ (on WIN32) is already used, so i needed to try to optimize that. After some experimenting i found out that it's faster when giving integer coordinates to GDI+ in WinSalGraphics::drawPolyLine, but this can only be done when LineWidth is > 1.5 (else Hairlines will lose AA) and i decided to do it for complex geometries (more than 250 points). This works pretty well and makes it a little bit faster again, so changes up to now get acceptable. Looking for Printing...
AW: Unfortunately all 7-10 (unknown number) of MetaFile consumers (more or less all exporters, including SLideSHow and printing) will now no longer be able to correctly show fat lines. The worked because the decomposed line geometry was included (a dast and simple solution, but too expensive in extreme cases). So, now i will have to look for all cases. AW: SLideshow first; canvas(es) are more or less prepared for LineJoin, but the transport is not good. Also found wrong default for MiterLimit already, too...
AW: Made DXCanvas work, VCLCanvas works out-of-the box using the actions (i was astonished BTW; the fat lines get converted to polygons; they could get painted directly). Looking for other canvases and if i can see something there...
AW: Added support to cairocanvas for rendering::PathJoinType::NONE. Starting a linux build to check that (checked in code to do so). AW: Looking for printing now...
AW: Printing solved; a helper class ImplLineConverter was used in VCL which is the old version of line to fill polygon expansion. That version did not know anything about LineJoins and needed to be replaced by the basegfx methods. Thus i needed to cleanup OutputDevice::DrawLine and OutputDevice::DrawPolyLine to behave right. Need to check further usages and correctness, e.g. with the closed states involved...
AW: Corrected a curve subdivision for printing, checked and corrected PDF export. Looking for more exports...
AW: Checked, HTML, XHTML, PDF and Macromedia Flash. AW: Had to look into SWF (Macromedia Flash). The old version never took care of LineJoins and handled dashes/dots by relying on the included decomposed geometry. I had to adapt both points. AW: For the LineJoin: There is support for LineJoin starting in SWF8 using LINESTYLE2 and DefineShape4, but i did not want to go to new versions to support, so i added a fallback. When not rounded (default is rounded, this is supported), the geometry is prepared. AW: For dashes/dots: Fallback was already there, but added geometry creation. There was NO initial support for used LineInfos at the META_LINE_ACTION or the META_POLYLINE_ACTION, added this, too. AW: SWF done, too. Looking for other exports...
AW: EMF and WMFdone. I have filed #i105928# for further enhancements; up to now LineInfo was not even used in any of them. They completely relied on the MetaFile containing the decomposed LineGeometry. Looking for EPS...
AW: EPS: Added support for basegfx::B2DLINEJOIN_NONE and forwarding of JoinStyle in PSWriter::ImplWriteLineInfo. AW: Looking further...
AW: For any reason GIF looked slightly strange; found the reason in the path composition for GDI+ in WinSalGraphics::drawPolyLine where the optimization for NoLineJoin does not have to close the polygon. Checking for other ocurrences... AW: Okay, other ocurrences okay, next exporter...
AW: Ckecked MET (OS2 Metafile). In the original the LineJoins worked due to contained decomposed line geometry. In the version with FatLine actions, all linejoins get rounded. The export (eos2met.cxx) shows some support for LineInfo (used in METWriter::METSetAndPushLineInfo), but i found NO documentation about MET on the net anymore. Does someone have infos...? It may be that it supports LineJoin, so it would be nice to evtl. use it. OTOH we would also need to import that and the format is not used by anyone anymore (when looking in the web, we are the onnly app mentioned to be able to read it nowadays (!))... Leaving MET open for now, looking for others...
AW: For PBM, both (old and new) look identical, but boh lose fillings. Taking a short look... AW: Found PBMWriter::WritePBM where the 32bit bitmap gets reduced to 1bit by calling Convert( BMP_CONVERSION_1BIT_THRESHOLD ), so i assume it's by purpose. PBM checked. Looking for next...
AW: Looking for PCT. It's losing the fat lines with the new MetaFile content, looking... Looked for documentation, none found. Adding standard decomposition actions for MetaPolyLineAction and MetaLineAction. Unifying this now; adding tooling methods to LineInfo and adapting all usages so far...
AW: Okay, PCT done and working. wmf, emf and swf adapted and tested. AW: Next one...
AW: SVG was next. Neither at MetaPolyLineAction nor at MetaLineAction anything besides rgb and stroke-opacity was supported. Added support for stroke-width, stroke-dasharray and stroke-linejoin. Added support for B2DLINEJOIN_NONE. Fixed that NO curve survived the export. Looks good now, works and has a much better quality fo the exported SVG. Looking for the next one...
AW: Unfortunately SVM (our own format) loses curve information since a META_POLYLINE_ACTION is exported by using GDI_POLYLINE_ACTION which only writes/reads the polygon points. Looking for a possibility to change this (no version info written)...
Aw. Due to #i102224# where i already did changes to SVM format, i will have to do a more clever change. Thinking about it and taking a 2nd look at #i102224# changes...
AW: Have n ow included #i102224# to cvtsvm.cxx to not get problems later. For the original, the Subdivided polygon gets written. For transporting the curve, i have now added a GDI_EXTENDEDPOLYGON_ACTION which can write/read a whole PolyPolygon with curve information. The trick is to read it; a counter to the last polygon-centric input MetaFileAction is remembered (e.g. at import of GDI_POLYLINE_ACTION). On import of GDI_EXTENDEDPOLYGON_ACTION this is then matched and the action maybe replaced. To write it is necessary to create a GDI_EXTENDEDPOLYGON_ACTION directly after a GDI_POLYLINE_ACTION. Looking for other actions where curve information is lost...
AW: Have now extended META_POLYLINE_ACTION, META_CHORD_ACTION, META_POLYGON_ACTION and META_POLYPOLYGON_ACTION to export an extra-GDI_EXTENDEDPOLYGON_ACTION. All others will not work since they export some action (e.g. GDI_GRADIENTEX_COMMENT action) and directly stream the contained polygons using the polygon stream operator (which does not support curve information). No way to extend these embedded polygons when they are curves. Testing the supported actions and compatibility with older versions...
AW: Works as expected, but i need to extend the break method in svx. It needs to support the LineJoin and also the change to LineWidth 0...
AW: DashDot also not supported up to now, need to add this, too. Added another action (GDI_LINEDASHDOT_ACTION) and save/load functionality. Added support for it in ImpSdrGDIMetaFileImport (for Break MTF support). Added various stuff to ImpSdrGDIMetaFileImport for deeper LineJoin/DashDot/LineWidth support. Checking...
@aw / ... a final request: pls set the target of this issue.
AW->cornouws: Traget is on 3.x, so it will get 3.3 when finished before 3.3 deadline :-) Okay, setting to 3.3.
AW: Corrected some errors in ImpSdrGDIMetaFileImport. Added support for DashDot, too, but it's currently not used since the MetaFile creator decomposes DashDots using basegfx::tools::applyLineDashing. I opt not to change this to have a not too bad roundtrip for saving new MetaFiles and loading them with older OOo versions. The splitted line is more data than the decomposed line pattern, but by far not so much more as the filled line geometry. For SVM: RoundTrip inside new version is good now (including breaking the MetaFile). Loading with older OOo loses EdgeRoundings. Loading from older OOo is lossless since the FillGeometry is included (but Break is more bad, of course). SVM is done so far, looing for next...
AW: Back to MET (was open for now). It's only used from OOo nowadays (even when looking in the net, interestingly OOo is the ONLY app mentioned who can read/write this), so it's definitely deprecated. Nonetheless, i will add the standard expansion fron LineInfo tooling class...
AW: MET already handles LineWidth and DashDot, so i can simply let it as it is. AW: Evaluating exports again: Slideshow: Works Printing: Works HTML: Works XHTML: Does the same as the original; seems broken somehow. PDF: Works well. Note: Do NOT use FoxitReader, it has a display error with the EdgeRounding SWF: Works BMP: Works EMF: Works. Note: Is not viewable with WIN32 default viewer, needs to be inserted to a new page. Same with original. Breaking up works well, too (much better than in original) EPS: Works well, no quality lost compared to original. GIF: Works well JPEG: Works well MET: Loses LineJoin (as expected), but smaller. Maybe a todo... PBM: Works PCT: Works. Note: wrong display in PSP version 7.04 PGM: Works well PNG: Works well PPM: Works well RAS: Works well SVG: Works well. Used Inkscape for testing, quality is much improved SVM: Works well. Especially round-trip with breaking much improved. Keeps beziers, LineJoins and DashDot (last one still broken down for compatibility). Loading with old version loses LineJoins, this is not avoidable. This is the most critical one since this is the format the OLE MteaFiles are transported (e.g. Chart). TIFF: Works well WMF: Works well XPM: Works well PWP: Cannot read, but it's a pixel based format (AFAICFO), thus it should be okay. Seems not to be used. Back to SVM: It's used for OLEs, thus it's critical. This task is about reducing MetaFile size by writing LineInfo MetaFile actions instead of the decomposed line geometry which is potentially very big. In old versions all LineJoins and beziers and DashDot styles for fat lines only worked because the decomposed line goemerty was added, but this leads to various performance problems. There is no other solution: It needs to be avoided, thus LineActions including the LineJoin, LineWidth, DashDot and bezier information need to be written. This solves the performance problem, but requires that ALL users of MetaFiles learn to handle those actions correctly. This users are the listed exporters, SlideShow, Printing and breaking up a MetaFile in editview. I adapted all those users (see comments above). The result is a solution fo rthe performance problems, but there is one single caveat: Loading SVMs (e.g. contained in OLEs) with an older OOo version. There, up to now the MetaFile only exported the LineWidth, thus LineJoin will be lost. This is no pronlem with chart, where LineJoin was/is not editable up to now, so all OLE line charts use LineJoin round what is the default at import. Roundtrip is okay and loading from an older Ooo version also (since it includes the expanded geometry).
AW: All done so far. I declare MET as deprecated and leave it as it is. Checked in.
AW: Checked in installed build, works as expected.
AW->WG: Please review.
Verified in CWS.
AW: Closing.