View module in:   cgit   Doxygen


Visual Class Library is responsible for the widgets (windowing, buttons, controls, file-pickers etc.), operating system abstraction, including basic rendering (e.g. the output device).

It should not be confused with Borland's Visual Component Library, which is entirely unrelated.

VCL provides a graphical toolkit similar to gtk+, Qt, SWING etc.

source/ + the main cross-platform chunk of source

inc/ + cross-platform abstraction headers

headless/ + a backend renderer that draws to bitmaps

android/ + Android backend

osx/ + OS X backend

ios/ + iOS backend

quartz/ + code common to OS X and iOS

win/ + Windows backend

qt5/ + Qt5 (under construction)

unx/ + X11 backend and its sub-platforms

gtk/ + GTK2 support gtk3/ + GTK3 support kde4/ + KDE4 support kde5/ + KDE5 support (under construction) gtk3_kde5/ + GTK3 support with KDE5 file pickers (until kde5 is finished) generic/ + raw X11 support

plugadapt/ + pluggable framework to select correct unx backend

dtrans/ + "data transfer" - clipboard handling + for tips how to show the current content of the clipboard

How the platform abstraction works

+ InitVCL calls 'CreateSalInstance' + this is implemented by the compiled-in platform backend + it stores various bits of global state in the 'SalData' (inc/saldatabasic.hxx) structure but: + the SalInstance vtable is the primary outward facing gateway API for platform backends + It is a factory for: SalFrames, SalVirtualDevices, SalPrinters, Timers, the SolarMutex, Drag&Drop and other objects, as well as the primary event loop wrapper.

Note: references to "SV" in the code mean StarView, which was a portable C++ class library for GUIs, with very old roots, that was developed by StarDivision. Nowadays it is not used by anything except LibreOffice (and OpenOffice).

"svp" stands for "StarView Plugin".

COM threading

The way COM is used in LO generally: - vcl InitSalData() puts main thread into Single-threaded Apartment (STA) - oslWorkerWrapperFunction() puts every thread spawned via oslCreateThread() into MTA (free-threaded)


GDIMetafile is a vector drawing representation that corresponds directly to the SVM (StarView Metafile) format; it is extremely important as an intermediate format in all sorts of drawing and printing operations.

There is a class MetafileXmlDump in include/test/mtfxmldump.hxx that can store a GDIMetafile as XML, which makes debugging much easier since you can just use "diff" to see changes.

To use it you need to link against "test" library and then (because "test" is not part of the installation) run with: LD_LIBRARY_PATH=workdir/LinkTarget/Library:workdir/UnpackedTarball/cppunit/src/cppunit/.libs instdir/program/soffice


emf+ is vector file format used by MSO and is successor of wmf and emf formats. see for documentation. note that we didn't have this documentation from start, so part of the code predates to the time when we had guessed some parts and can be enhanced today. there also still many thing not complete

emf+ is handled a bit differently compared to original emf/wmf files, because GDIMetafile is missing features we need (mostly related to transparency, argb colors, etc.)

emf/wmf is translated to GDIMetafile in import filter vcl/source/filter/wmf and so special handling ends here

emf+ is encapsulated into GDIMetafile inside comment records and parsed/rendered later, when it reaches cppcanvas. it is parsed and rendered in cppcanvas/source/mtfrenderer. also note that there are emf+-only and emf+-dual files. dual files contains both types of records (emf and emf+) for rendering the images. these can used also in applications which don't know emf+. in that case we must ignore emf records and use emf+ for rendering. for more details see documentation


wmf/emf filter --> GDI metafile with emf+ in comments --> cppcanvas metafile renderer

lately the GDIMetafile rendering path changed which also influenced emf+ rendering. now many things happen in drawing layer, where GDIMetafile is translated into drawing layer primitives. for metafiles with emf+ we let the mtfrenderer render them into bitmap (with transparency) and use this bitmap in drawinlayer. cleaner solution for current state would be to extend the drawing layer for missing features and move parsing into drawing layer (might be quite a lot of work). intermediary enhancement would be to know better the needed size/resolution of the bitmap, before we render emf+ into bitmap in drawing layer. Thorsten is working on the same problem with svg rendering, so hopefully his approach could be extended for emf+ as well. the places in drawing layer where we use canvas mtfrenderer to render into bitmaps can be found when you grep for GetUseCanvas. also look at vcl/source/gdi/gdimetafile.cxx where you can look for UseCanvas again. moving the parsing into drawinglayer might also have nice side effect for emf+-dual metafiles. in case the emf+ records are broken, it would be easier to use the duplicit emf rendering. fortunately we didn't run into such a broken emf+ file yet. but there were already few cases where we first though that the problem might be because of broken emf+ part. so far it always turned out to be another problem.



vcl --> cppcanvas metafile renderer --> vcl


drawing layer --> vcl --> cppcanvas metafile renderer --> vcl --> drawing layer

another interesting part is actual rendering into canvas bitmap and using that bitmap later in code using vcl API.

EMF+ implementation has some extensive logging, best if you do a dbgutil build, and then

export SAL_LOG=+INFO.cppcanvas.emf+INFO.vcl.emf

before running LibreOffice; it will give you lots of useful hints.

You can also fallback to EMF (from EMF+) rendering via


Printing/PDF export

Printing from Writer works like this:

1) individual pages print by passing an appropriate OutputDevice to XRenderable 2) in drawinglayer, a VclMetafileProcessor2D is used to record everything on the page (because the OutputDevice has been set up to record a GDIMetaFile) 3) the pages' GDIMetaFiles are converted to PDF by the vcl::PDFWriter in vcl/source/gdi/pdfwriter*

Creating the ODF thumbnail for the first page works as above except step 3 is:

3) the GDIMetaFile is replayed to create the thumbnail

On-screen display differs in step 1 and 2:

1) the VCL Window gets invalidated somehow and paints itself 2) in drawinglayer, a VclPixelProcessor2D is used to display the content

Debugging PDF export

Debugging the PDF export becomes much easier when compression is disabled (so the PDF file is directly readable) and the MARK function puts comments into the PDF file about which method generated the following PDF content.

The compression can be disabled even using a env. var:


To de-compress the contents of a PDF file written by a release build or other programs, use the "pdfunzip" tool:

bin/run pdfunzip input.pdf output.pdf