From KDE Community Wiki
< GSoC‎ | 2023‎ | StatusReports

Improve Okular For Android

Okular has an Android version, but it has some issues. PDFs without embedded fonts don’t display properly due to the lack of an Android-specific font API in the Poppler backend. Icons also do not render, due to problems in KDE Frameworks or the Kirigami UI framework.

This project aims to implement an Android-specific font API in the Poppler backend, as well as solving the issue of icon rendering in Okular’s Android version.

Project Mentor: Albert Astals Cid <[email protected]>

Project Size: 175 Hours (medium)

Links to Blogs and other writing


I will be writing about my progress on my blog. It can be found at:

The blog posts in chronological order:

  1. First blog: First blog for GSoC '23
  2. Second blog detailing work done during the first coding period: GSoC '23: Summary of work done over first coding period
  3. Third and final blog, wrapping up GSoC'23: GSoC '23: Wrapping Up

Merge Requests

  1. Main merge request for font-matching functionality in Poppler
  2. Fix icon rendering in Okular on Android
  3. Package the Okular icon when building for Android
  4. Replace Kirigami.AboutPage with MobileForm.AboutPage for mobile build
  5. Port to the newer FormCard API from the MobileForm API
  6. Cherry picked commit from Qt6 in order to fix black screen issue in Okular Android

Work Reports

Week 1 and 2

  • Work begins on font-matching functionality for Android version of Poppler
  • Understood what is to be done
    • Implement GlobalParams::findSystemFontFile() and GlobalParams::findBase14FontFile() for Android version of Poppler
  • Set up development environment
    • Use kde-android docker image for building Poppler
    • Use CMake script incliuded in the android build for Poppler project CI
    • Use docker image for building Okular
    • To test changes in Poppler:
      • First make necessary changes to poppler
      • Build poppler in kde-android docker container
      • replace the poppler library in the android-qt515 docker container
      • Build okular again so that it gets built with the new poppler library
      • Package Okular and install it on android device/emulator to test changes

Week 2

  • Added conditional compilation for Android version of Poppler, to get the correct libraries and set the correct environment variables
  • Environment variables included pre-processor variables which would compile the Android specific implementation of Poppler's font-matching backend when building for Android.
  • THe android libraries included the android library and the log library provided by the Android NDK.

Week 3

  • Forked Poppler's repository hosted at after acquiring the relevant permissions
  • Successfully implemented a crude version of GlobalParams::findSystemFontFile() using AFontMatcher functionality which only returns sans-serif fonts.
    • Accomplished this by adding the android library in the CMake
    • Still needs implementation for:
      • Fetching the correct style of the required font (bold, italic, bold + italic, etc.)
      • Fetching the font having the correct font weight
      • Getting other generic font styles such as serif, fixed-width

Week 4

  • Since AFontMatcher uses the pre-installed fonts found on Android, and only matches fonts based on the generic font-family (sans-serif, serif, fixed-width, fantasy, etc.). It was inadequate for matching the base 14 fonts.
  • The base 14 fonts are a set of 14 fonts that are expected to be supported by every PDF reader. These include:
    • Times (v3) (in regular, italic, bold, and bold italic)
    • Courier (in regular, oblique, bold and bold oblique)
    • Helvetica (v3) (in regular, oblique, bold and bold oblique)
    • Symbol
    • Zapf Dingbats
  • However, these fonts have proprietary licenses, so instead we use some substitute fonts that closely match the base-14 fonts in appearance. In Poppler's case, these fonts are:
    • NimbusMonoPS-Regular.otf
    • NimbusMonoPS-Bold.otf
    • NimbusMonoPS-BoldItalic.otf
    • NimbusMonoPS-Italic.otf
    • NimbusSans-Regular.otf
    • NimbusSans-Bold.otf
    • NimbusSans-BoldItalic.otf
    • NimbusSans-Italic.otf
    • StandardSymbolsPS.otf
    • NimbusRoman-Bold.otf
    • NimbusRoman-BoldItalic.otf
    • NimbusRoman-Italic.otf
    • NimbusRoman-Regular.otf
    • D050000L.otf
  • However, Android devices do not come with these base-14 fonts installed by default, so we must provide our own.
  • Luckily, OKular already packages these fonts inside the assets folder of its apk. To access and use these files, we first transfer them to the internal storage of the app (Okular in this case) and then set the path where the font files can be found, so that Poppler can load and use the font files.
  • However, as a sanity test, I first placed the font files in a directory inside the /data/local/tmp folder of android, which is read/write and has execute permissions, and specified the path in myself. It worked, so I got to work on implementing a mechanism for copying the font files and setting the font file path.

Week 5

  • I implemented a mechanism to copy all the font files contained in the assets/share/fonts folder of the Okular APK.
  • This code uses the QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) functionality of Qt to quickly find the internal storage directory of the app.
  • Within this folder, another folder called fonts is created, and the font files in the assets/share/fonts folder of the APK are copied over to the fonts folder one-by-one
  • This code was originally written in the mobile/app/main.cpp file of Okular, however I could not call GlobalParams functions, since they are private to Poppler. This presented a blocker to setting the path for the font directory in GlobalParams.
  • I later shifted the code to the qt backend of Poppler, as I could access QStandardPaths and other Qt functions, while also being able to call GlobalParams functions. More specifically, the code was added in the DocumentData::init() method.
  • I then created a static method in GlobalParams, GlobalParams::setFontDir(), which takes a file path as a string input, and sets it as the path where font files should be searched.

Week 6

  • The midterm deadline was fast approaching, so I got to work on finalizing my work and created a Merge Request on Poppler's gitlab.
  • I cleaned up the code by removing several print debugging statements, organising the code properly, and adding comments to detail what a piece of code does.
  • I then created the MR, and fixed any issues that were found in my code by my mentor, and also fixed the code so that all the CI jobs for Poppler would pass. For example, I forgot to add some conditional compilation statements, which resulted in every CI besides clang-format and android failing to build. I also fixed some memory leak issues with AFontMatcher and AFont objects using unique_ptrs (thanks to Sune Vuorela for suggesting unique_ptrs!).
  • I also wrote my blog entry detailing the work done in the first coding period: Link to blog

Week 7 - 9

  • This week marked the start of the second coding period.
  • I began work on the second problem that had to be fixed - Okular's icons not being rendered.
  • During this time, I explored the source code of other KDE Android apps to figure out what the problem might be.
  • I also disassembled the APK, and decompiled the .qrc file inside it. I discovered that they were getting packaged properly, and specifying their full path using the qrc://path/to/icon path worked properly. This meant that the issue was with Kirigami not finding the proper icons.
  • I had also requested a deadline as I thought that debugging this issue would take weeks of breaking down and building up Okular piece-by-piece to find the troublesome part of the codebase.
  • But before taking Okular apart piece-by-piece, I sought help from the KDE Android matrix room to diagnose the issue.
  • Thanks to their help it was discovered that Okular was packaging KIconThemes as a dependency and thus was automatically setting Okular's fallback theme to "breeze". This interfered with Kirigami's icon-finding logic, and it was not able to find the icons properly. This is the line of code that was causing this issue.
  • I placed a conditional compilation guard to prevent KIconThemes from doing this when built for Android.
  • Relevant merge request: frameworks/kiconthemes!101

Week 10 - 11

  • I added the Okular icon to be packaged in the apk, so that it would display in the global drawer and Okular's about page.
  • Relevant merge request: graphics/okular!801
  • During this time, I also noticed that Craft would not package any new icons unless I used the command:
 craft --compile --install --qmerge okular

instead of just

 craft --compile okular

Due to this, I wasted some time thinking that Kirigami's icon packaging was having some issues, when in fact it was working properly and the icons just needed an extra step to be packaged using Craft.

Week 12-13

  • While running Okular on my android device, I noticed that opening a PDF would result in a black screen that persisted until Okular would close or crash by itself.
  • After some testing, it seemed to be the result of a regression in the qtbase component of Qt 5.15.9. The regressive commit ID is - 513fcf0d2ad3328830dbf73dc2a55ad1487393c0.
  • It was fixed in a later commit in the Qt6 branch of qtbase - ac984bd8768b3d7e6439e0ffd98fd8b53e16b922
  • To apply this fix to Okular, my mentor advised me to backport this patch to the kde/5.15 branch of qtbase, using the process detailed in this KDE wiki page:
  • I followed the directions and cherry-picked the commit ac984bd8768b3d7e6439e0ffd98fd8b53e16b922 to the kde/5.15 branch and opened a merge request at the KDE Invent qtbase repository.
  • Relevant merge request : qt/qt/qtbase!278

Week 14-15

  • All the tasks for my GSoC project were completed at this point.
  • So I started working on creating my final report and a blog post wrapping up my GSoC journey.