Skip to content

Add proper svg support and try to fix the subpixel when combining 9 tiles with fractional rendering - #1615

Merged
wengxt merged 6 commits into
masterfrom
svg
Jul 27, 2026
Merged

Add proper svg support and try to fix the subpixel when combining 9 tiles with fractional rendering#1615
wengxt merged 6 commits into
masterfrom
svg

Conversation

@wengxt

@wengxt wengxt commented Jul 26, 2026

Copy link
Copy Markdown
Member
  • Add native SVG support for high resolution rendering with rsvg.
  • Make overlay also use native svg rendering path
  • Store fcitx drawn image as cairo pattern so we can achieve similar effect like svg.
  • Replace default theme image from png to svg
  • Rounding to integer when do the tile drawing to avoid having subpixel issues.

Summary by CodeRabbit

  • New Features

    • Classic themes now load and render SVG assets for icons and backgrounds (including patterned rendering).
    • Default and Default Dark themes switched to SVG-based navigation and menu indicators.
  • Bug Fixes

    • Improved rendering consistency across display backends with more reliable Cairo clearing/compositing.
    • Updated painting to use absolute region positioning and consistent device scaling for input panels, menus, tray icons, highlights, and themed backgrounds.
    • Corrected separator sizing for pattern-based backgrounds.
  • Chores

    • Build now detects the SVG rendering library when using X11/Wayland.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f11ca3de-756c-40d6-a63b-2741e0346b35

📥 Commits

Reviewing files that changed from the base of the PR and between 31ca911 and 9887799.

📒 Files selected for processing (1)
  • src/ui/classic/theme.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/ui/classic/theme.cpp

📝 Walkthrough

Walkthrough

Classic UI theme rendering now supports SVG assets, Cairo surfaces, and mesh patterns. Theme painting uses region-based rendering and device scaling, while input, menu, tray, and window paths adopt the updated painting API and composition behavior.

Changes

Classic UI SVG rendering

Layer / File(s) Summary
SVG dependency and theme assets
CMakeLists.txt, src/ui/classic/CMakeLists.txt, src/ui/classic/themes/*
librsvg is detected and linked, and the default themes collect and reference SVG assets for navigation and menu icons.
Theme image variants and loading
src/ui/classic/theme.h, src/ui/classic/theme.cpp
Theme images now represent Cairo surfaces, SVG documents, or mesh patterns, with corresponding loading, sizing, validity, and ownership logic.
Region rendering and background composition
src/ui/classic/theme.h, src/ui/classic/theme.cpp
Theme painting renders image variants into source and destination regions, including tiled backgrounds, overlays, actions, and masks.
Window and menu rendering integration
src/ui/classic/inputwindow.*, src/ui/classic/waylandinputwindow.cpp, src/ui/classic/xcb*.cpp
Input, menu, tray, and XCB paths use coordinate-based painting, device scaling, clear-and-over composition, pattern detection, and explicit ARGB32 surfaces.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ThemeConfig
  participant ThemeImage
  participant librsvg
  participant Theme
  participant ClassicWindow
  ThemeConfig->>ThemeImage: load SVG or raster asset
  ThemeImage->>librsvg: parse SVG document
  librsvg-->>ThemeImage: return SVG handle and dimensions
  ClassicWindow->>Theme: request painting for destination region
  Theme->>ThemeImage: paintRegion source into destination
  ThemeImage-->>ClassicWindow: render image through Cairo
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main changes: native SVG support and fractional tile rendering fixes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch svg

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/ui/classic/theme.cpp (1)

251-275: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

SVG parse errors are discarded.

rsvg_handle_new_from_stream_sync is passed a null GError**, so a malformed theme SVG fails silently. Passing a GError and logging via CLASSICUI_ERROR() would make theme authoring issues diagnosable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ui/classic/theme.cpp` around lines 251 - 275, Update loadSvg’s
rsvg_handle_new_from_stream_sync call to capture parse failures in a GError, and
log the error through CLASSICUI_ERROR() before returning std::nullopt when
handle creation fails. Preserve the existing successful-load and other failure
paths.
src/ui/classic/xcbmenu.cpp (1)

536-537: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant re-lookup shadows the outer separator.

separator is already bound at line 433; re-calling loadBackground per separator item inside the paint loop adds a hash lookup and shadows the outer name.

♻️ Proposed cleanup
         if (item.isSeparator_) {
-            const ThemeImage &separator =
-                theme.loadBackground(*theme.menu->separator);
             theme.paint(c, *theme.menu->separator, item.layoutX_, item.layoutY_,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ui/classic/xcbmenu.cpp` around lines 536 - 537, In the separator painting
loop, remove the inner `separator` declaration and reuse the existing outer
`separator` binding established earlier in the function. Avoid calling
`theme.loadBackground` for each separator item while preserving the current
rendering behavior.
src/ui/classic/theme.h (1)

281-287: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Drop the unused isImage_ member.

isImage_ is only declared; there are no assignments or readers left in src/ui/classic, so remove the dead state member.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ui/classic/theme.h` around lines 281 - 287, Remove the unused isImage_
member from the class declaration near currentText_ and size_. Leave the
remaining state fields and ImageVariant alias unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CMakeLists.txt`:
- Line 167: The librsvg discovery and classicui linkage use inconsistent feature
contracts. In CMakeLists.txt at lines 167-167 and src/ui/classic/CMakeLists.txt
at lines 45-45, either require librsvg whenever classicui is enabled under the
same ENABLE_X11/ENABLE_WAYLAND guard, or introduce an explicit optional-librsvg
condition and apply it consistently to both pkg_check_modules(Rsvg) and the
PkgConfig::Rsvg link.

In `@src/ui/classic/theme.cpp`:
- Around line 636-685: Update ThemeImage::paintRegion to return immediately when
sourceWidth or sourceHeight is zero or otherwise non-positive, before any branch
computes scaling or translation. Preserve the existing rendering behavior for
valid source regions across the CairoSurface, Svg, and Pattern paths.

---

Nitpick comments:
In `@src/ui/classic/theme.cpp`:
- Around line 251-275: Update loadSvg’s rsvg_handle_new_from_stream_sync call to
capture parse failures in a GError, and log the error through CLASSICUI_ERROR()
before returning std::nullopt when handle creation fails. Preserve the existing
successful-load and other failure paths.

In `@src/ui/classic/theme.h`:
- Around line 281-287: Remove the unused isImage_ member from the class
declaration near currentText_ and size_. Leave the remaining state fields and
ImageVariant alias unchanged.

In `@src/ui/classic/xcbmenu.cpp`:
- Around line 536-537: In the separator painting loop, remove the inner
`separator` declaration and reuse the existing outer `separator` binding
established earlier in the function. Avoid calling `theme.loadBackground` for
each separator item while preserving the current rendering behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2f1e4c1f-c52c-4208-9efc-213bcc3f5a11

📥 Commits

Reviewing files that changed from the base of the PR and between 16465b0 and 31ca911.

⛔ Files ignored due to path filters (16)
  • src/ui/classic/themes/default-dark/arrow.png is excluded by !**/*.png
  • src/ui/classic/themes/default-dark/arrow.svg is excluded by !**/*.svg
  • src/ui/classic/themes/default-dark/next.png is excluded by !**/*.png
  • src/ui/classic/themes/default-dark/next.svg is excluded by !**/*.svg
  • src/ui/classic/themes/default-dark/prev.png is excluded by !**/*.png
  • src/ui/classic/themes/default-dark/prev.svg is excluded by !**/*.svg
  • src/ui/classic/themes/default-dark/radio.png is excluded by !**/*.png
  • src/ui/classic/themes/default-dark/radio.svg is excluded by !**/*.svg
  • src/ui/classic/themes/default/arrow.png is excluded by !**/*.png
  • src/ui/classic/themes/default/arrow.svg is excluded by !**/*.svg
  • src/ui/classic/themes/default/next.png is excluded by !**/*.png
  • src/ui/classic/themes/default/next.svg is excluded by !**/*.svg
  • src/ui/classic/themes/default/prev.png is excluded by !**/*.png
  • src/ui/classic/themes/default/prev.svg is excluded by !**/*.svg
  • src/ui/classic/themes/default/radio.png is excluded by !**/*.png
  • src/ui/classic/themes/default/radio.svg is excluded by !**/*.svg
📒 Files selected for processing (15)
  • CMakeLists.txt
  • src/ui/classic/CMakeLists.txt
  • src/ui/classic/inputwindow.cpp
  • src/ui/classic/inputwindow.h
  • src/ui/classic/theme.cpp
  • src/ui/classic/theme.h
  • src/ui/classic/themes/default-dark/CMakeLists.txt
  • src/ui/classic/themes/default-dark/theme-dark.conf.in
  • src/ui/classic/themes/default/CMakeLists.txt
  • src/ui/classic/themes/default/theme.conf.in
  • src/ui/classic/waylandinputwindow.cpp
  • src/ui/classic/xcbinputwindow.cpp
  • src/ui/classic/xcbmenu.cpp
  • src/ui/classic/xcbtraywindow.cpp
  • src/ui/classic/xcbwindow.cpp

Comment thread CMakeLists.txt
pkg_check_modules(Cairo IMPORTED_TARGET cairo)
pkg_check_modules(Pango IMPORTED_TARGET pango pangocairo)
pkg_check_modules(GdkPixbuf IMPORTED_TARGET gdk-pixbuf-2.0)
pkg_check_modules(Rsvg IMPORTED_TARGET librsvg-2.0)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)(CMakeLists.txt)$' | sed -n '1,200p'

echo "== root CMake snippets =="
if [ -f CMakeLists.txt ]; then
  wc -l CMakeLists.txt
  sed -n '130,190p' CMakeLists.txt
fi

echo "== classic CMake snippets =="
if [ -f src/ui/classic/CMakeLists.txt ]; then
  wc -l src/ui/classic/CMakeLists.txt
  sed -n '1,90p' src/ui/classic/CMakeLists.txt
fi

echo "== occurrences of Rsvg/Rsvg targets and feature guards =="
rg -n "librsvg|PkgConfig::Rsvg|ENABLE_WAYLAND|Classic|classicui|add_fcitx5_addon\\(" .

Repository: fcitx/fcitx5

Length of output: 42558


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== src/ui/CMake.txt context =="
if [ -f src/ui/CMakeLists.txt ]; then
  wc -l src/ui/CMakeLists.txt
  sed -n '1,120p' src/ui/CMakeLists.txt
fi

echo "== classicui guarded source/config sections =="
rg -n "ENABLE_CLASSICUI|CLASSICUI|classicui|ENABLE_WAYLAND|ENABLE_X11" src/ui src/ui/classic CMakeLists.txt test -g '*.cmake' -g 'CMakeLists.txt' | sed -n '1,220p'

echo "== deterministic CMake-like behavior probe =="
python3 - <<'PY'
# Model the relevant CMake dependency-discovery/linking behavior described by the files.
cases = [
    {"name": "ENABLE_WAYLAND=On, librsvg absent", "ENABLE_WAYLAND": 1, "ENABLE_X11": 0, "libs_availability": {"Rsvg": False}},
    {"name": "ENABLE_X11=On only, librsvg absent", "ENABLE_WAYLAND": 0, "ENABLE_X11": 1, "libs_availability": {"Rsvg": False}},
    {"name": "both enabled, librsvg present", "ENABLE_WAYLAND": 1, "ENABLE_X11": 1, "libs_availability": {"Rsvg": True}},
]
for c in cases:
    discovery_guard = c["ENABLE_X11"] or c["ENABLE_WAYLAND"]
    has_pkg_cfg_target = discovery_guard and c["libs_availability"]["Rsvg"]
    build_block_guard = discovery_guard
    link_has_target = build_block_guard
    status = "FAIL at config/link" if (build_block_guard and not has_pkg_cfg_target and link_has_target) else "OK"
    print(f"{c['name']}: discovery_guard={discovery_guard}, pkg_target_available={has_pkg_cfg_target}, classicui_block_added={build_block_guard}, link_targets_resolved={link_has_target} -> {status}")
PY

Repository: fcitx/fcitx5

Length of output: 5131


Keep librsvg discovery and classicui linking on the same feature contract.

pkg_check_modules(Rsvg IMPORTED_TARGET librsvg-2.0) is guarded only by ENABLE_X11 OR ENABLE_WAYLAND, but classicui still links PkgConfig::Rsvg unconditionally. Builds with Wayland enabled but without librsvg will fail configuration/connection. Either make this dependency required under the same guard as classicui, or gate both discovery and the PkgConfig::Rsvg link step behind an explicit optional-librsvg path.

📍 Affects 2 files
  • CMakeLists.txt#L167-L167 (this comment)
  • src/ui/classic/CMakeLists.txt#L45-L45
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CMakeLists.txt` at line 167, The librsvg discovery and classicui linkage use
inconsistent feature contracts. In CMakeLists.txt at lines 167-167 and
src/ui/classic/CMakeLists.txt at lines 45-45, either require librsvg whenever
classicui is enabled under the same ENABLE_X11/ENABLE_WAYLAND guard, or
introduce an explicit optional-librsvg condition and apply it consistently to
both pkg_check_modules(Rsvg) and the PkgConfig::Rsvg link.

Source: Coding guidelines

Comment thread src/ui/classic/theme.cpp
@wengxt
wengxt merged commit 08deef0 into master Jul 27, 2026
6 checks passed
@wengxt
wengxt deleted the svg branch July 27, 2026 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant