[util] Add --draw / --paint flags to raster, vector, gpu
Move the force_draw / force_paint flags from gpu-output.hh
into the shared view-options.hh so all rendering utils
expose --draw and --paint with the same semantics: --paint
wins over --draw, otherwise auto-detect via the font's
color tables.
raster and vector previously only ran the paint pipeline
when the font had a color table; they now also honor
--paint (renders mono fonts via paint synthesis) and
--draw (forces the outline path even on color fonts).
Vector's per-glyph try-paint-then-fall-back-to-draw is
replaced with a single mode decision up front. Each
glyph then goes through hb_vector_{paint,draw}_glyph
(non-_or_fail), which handles the synthesis fallback
internally — color glyphs render in either mode (paint
synthesizes for non-color fonts; draw renders nothing for
color-only glyphs without an outline, which matches user
intent for --draw).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
diff --git a/util/gpu-output.hh b/util/gpu-output.hh
index 2e3cdb8..8576739 100644
--- a/util/gpu-output.hh
+++ b/util/gpu-output.hh
@@ -56,8 +56,6 @@
hb_bool_t use_d3d11 = false;
hb_bool_t demo = false;
hb_bool_t bench = false;
- hb_bool_t force_draw = false; /* --draw : use monochrome draw path */
- hb_bool_t force_paint = false; /* --paint : use paint path */
hb_bool_t show_extents = false; /* --show-extents */
/* Initial state for interactive toggles; each corresponds to
* a keyboard shortcut in demo_view_t. */
@@ -92,8 +90,8 @@
{"bench", 0, G_OPTION_FLAG_NO_ARG,
G_OPTION_ARG_CALLBACK, (gpointer) &parse_bench,"Demo in fullscreen benchmark mode", nullptr},
{"type", 'T', 0, G_OPTION_ARG_STRING, &this->type_text, "Type these keystrokes on start", "keys"},
- {"draw", 0, 0, G_OPTION_ARG_NONE, &this->force_draw, "Force monochrome draw path", nullptr},
- {"paint", 0, 0, G_OPTION_ARG_NONE, &this->force_paint, "Force color paint path", nullptr},
+ {"draw", 0, 0, G_OPTION_ARG_NONE, &this->view.force_draw, "Force monochrome draw path", nullptr},
+ {"paint", 0, 0, G_OPTION_ARG_NONE, &this->view.force_paint, "Force color paint path", nullptr},
{"output-file", 'o', 0, G_OPTION_ARG_STRING, &this->output_file, "Render one frame to PPM file (\"-\" for stdout) and exit","filename"},
{"show-extents", 0, 0, G_OPTION_ARG_NONE, &this->show_extents, "Draw a frame around each glyph's ink extents", nullptr},
/* Interactive-toggle defaults. Each mirrors a keybinding
@@ -153,8 +151,8 @@
* otherwise auto: fonts without color paint get the draw path
* (smaller shader, better perf). A mismatched pair of flags
* is a user error; prefer paint. */
- draw_only = force_paint ? false
- : force_draw ? true
+ draw_only = view.force_paint ? false
+ : view.force_draw ? true
: !hb_ot_color_has_paint (face);
if (use_metal)
diff --git a/util/raster-output.hh b/util/raster-output.hh
index 4d4eae8..7ada1ad 100644
--- a/util/raster-output.hh
+++ b/util/raster-output.hh
@@ -81,12 +81,18 @@
subpixel_bits = font_opts->subpixel_bits;
hb_face_t *face = hb_font_get_face (font);
- has_color = hb_ot_color_has_paint (face) ||
- hb_ot_color_has_layers (face) ||
+ bool font_has_color = hb_ot_color_has_paint (face) ||
+ hb_ot_color_has_layers (face) ||
#ifndef HB_NO_SVG
- hb_ot_color_has_svg (face) ||
+ hb_ot_color_has_svg (face) ||
#endif
- hb_ot_color_has_png (face);
+ hb_ot_color_has_png (face);
+ /* --paint wins over --draw; otherwise auto-detect.
+ * hb_raster_paint_glyph synthesizes paint from outlines
+ * for mono fonts, so --paint works even without color. */
+ has_color = force_paint ? true
+ : force_draw ? false
+ : font_has_color;
fg_color = HB_COLOR ((uint8_t) foreground_color.b,
(uint8_t) foreground_color.g,
diff --git a/util/vector-output.hh b/util/vector-output.hh
index 9abb171..10b1013 100644
--- a/util/vector-output.hh
+++ b/util/vector-output.hh
@@ -234,6 +234,21 @@
foreground_use_palette && foreground_palette && foreground_palette->len;
unsigned palette_glyph_index = 0;
+ /* Pick draw vs paint mode. --paint wins over --draw;
+ * otherwise auto-detect via the font's color tables.
+ * hb_vector_paint_glyph synthesizes paint from outlines
+ * for mono fonts, so --paint works even without color. */
+ hb_face_t *face = hb_font_get_face (font);
+ bool font_has_color = hb_ot_color_has_paint (face) ||
+ hb_ot_color_has_layers (face) ||
+#ifndef HB_NO_SVG
+ hb_ot_color_has_svg (face) ||
+#endif
+ hb_ot_color_has_png (face);
+ bool use_paint = force_paint ? true
+ : force_draw ? false
+ : font_has_color;
+
hb_direction_t dir = direction;
if (dir == HB_DIRECTION_INVALID)
dir = HB_DIRECTION_LTR;
@@ -256,7 +271,7 @@
float pen_x = g.x + off_x;
float pen_y = g.y + off_y;
- if (paint)
+ if (use_paint && paint)
{
if (use_foreground_palette)
{
@@ -267,17 +282,16 @@
}
hb_vector_paint_set_transform (paint, 1.f, 0.f, 0.f, 1.f, 0.f, 0.f);
- if (hb_vector_paint_glyph_or_fail (paint, upem_font, g.gid, pen_x, pen_y,
- extents_mode))
- {
- had_paint = true;
- continue;
- }
+ hb_vector_paint_glyph (paint, upem_font, g.gid, pen_x, pen_y,
+ extents_mode);
+ had_paint = true;
}
-
- if (hb_vector_draw_glyph_or_fail (draw, upem_font, g.gid, pen_x, pen_y,
- extents_mode))
+ else
+ {
+ hb_vector_draw_glyph (draw, upem_font, g.gid, pen_x, pen_y,
+ extents_mode);
had_draw = true;
+ }
}
}
diff --git a/util/view-options.hh b/util/view-options.hh
index 06dfce7..75d2c16 100644
--- a/util/view-options.hh
+++ b/util/view-options.hh
@@ -242,6 +242,8 @@
hb_bool_t logical = false;
hb_bool_t ink = false;
hb_bool_t show_extents = false;
+ hb_bool_t force_draw = false; /* --draw : use mono outline path */
+ hb_bool_t force_paint = false; /* --paint : use color paint path */
bool parse_custom_palette_entries (GError **error)
{
@@ -375,6 +377,8 @@
{"logical", 0, 0, G_OPTION_ARG_NONE, &this->logical, "Render to logical box instead of union of logical and ink boxes", nullptr},
{"ink", 0, 0, G_OPTION_ARG_NONE, &this->ink, "Render to ink box instead of union of logical and ink boxes", nullptr},
{"show-extents", 0, 0, G_OPTION_ARG_NONE, &this->show_extents, "Draw glyph extents", nullptr},
+ {"draw", 0, 0, G_OPTION_ARG_NONE, &this->force_draw, "Force monochrome draw path (overrides auto-detect)", nullptr},
+ {"paint", 0, 0, G_OPTION_ARG_NONE, &this->force_paint, "Force color paint path (overrides auto-detect)", nullptr},
{nullptr}
};
parser->add_group (entries,