summaryrefslogtreecommitdiff
path: root/vcl/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/README.md')
-rw-r--r--vcl/README.md242
1 files changed, 242 insertions, 0 deletions
diff --git a/vcl/README.md b/vcl/README.md
new file mode 100644
index 000000000000..e0944688f2f3
--- /dev/null
+++ b/vcl/README.md
@@ -0,0 +1,242 @@
+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/
+ + macOS backend
+
+ios/
+ + iOS backend
+
+quartz/
+ + code common to macOS and iOS
+
+win/
+ + Windows backend
+
+qt5/
+ + Qt5 (under construction)
+
+unx/
+ + X11 backend and its sub-platforms
+ gtk3/
+ + GTK3 support
+ kf5/
+ + KF5 support (based on qt5 VCL plugin mentioned above)
+ gtk3_kde5/
+ + GTK3 support with KDE5 file pickers (alternative to native kf5 one)
+ generic/
+ + raw X11 support
+
+ plugadapt/
+ + pluggable framework to select correct unx backend
+
+ dtrans/
+ + "data transfer" - clipboard handling
+ + http://stackoverflow.com/questions/3261379/getting-html-source-or-rich-text-from-the-x-clipboard
+ 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 puts main thread into Single-threaded Apartment (STA)
+- oslWorkerWrapperFunction() puts every thread spawned via oslCreateThread()
+ into MTA (free-threaded)
+
+== GDIMetafile ==
+
+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/vcl/mtfxmldump.hxx that
+can store a GDIMetafile as XML, which makes debugging much easier
+since you can just use "diff" to see changes.
+
+== EMF+ ==
+
+emf+ is vector file format used by MSO and is successor of wmf and
+emf formats. see
+http://msdn.microsoft.com/en-us/library/cc230724.aspx 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
+
+parsing:
+
+ 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.
+
+rendering:
+
+ before
+
+ vcl --> cppcanvas metafile renderer --> vcl
+
+ now
+
+ 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
+
+export EMF_PLUS_DISABLE=1
+
+
+== 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 an env. var:
+
+export VCL_DEBUG_DISABLE_PDFCOMPRESSION=1
+
+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
+
+=== SolarMutexGuard ===
+
+The solar mutex is the "big kernel lock" of LibreOffice, a global one. It's a
+recursive mutex, so it's allowed to take the lock on the same thread multiple
+times, and only the last unlock will actually release the mutex.
+
+UNO methods on components can be called from multiple threads, while the
+majority of the codebase is not prepared for multi-threading. One way to get
+around this mismatch is to create a SolarMutexGuard instance at the start of
+each & every UNO method implementation, but only when it is necessary:
+
+- Only acquire the SolarMutex if you actually need it (e.g., not in functions
+ that return static information).
+
+- Only around the code that actually needs it (i.e., never call out with it
+ locked).
+
+This way you ensure that code (not prepared for multithreading) is still
+executed only on a single thread.
+
+In case you expect that your caller takes the solar mutex, then you can use
+the DBG_TESTSOLARMUTEX() macro to assert that in dbgutil builds.
+
+Event listeners are a special (but frequent) case of the "never call out with
+a mutex (SolarMutex or other) locked" fundamental rule:
+
+- UNO methods can be called from multiple threads, so most implementations
+ take the solar mutex as their first action when necessary.
+
+- This can be problematic if later calling out (an event handler is called),
+ where the called function may be an UNO method implementation as well and
+ may be invoked on a different thread.
+
+- So we try to not own the solar mutex, whenever we call out (invoke event
+ listeners).
+
+In short, never hold any mutex unless necessary, especially not when calling
+out.