blob: 79eee01861d9a1246cf61a0c9d14933deb6f3de2 [file] [edit]
/*
* Copyright © 2026 Behdad Esfahbod
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Author(s): Behdad Esfahbod
*/
#ifndef HELPER_EXTENTS_OVERLAY_HH
#define HELPER_EXTENTS_OVERLAY_HH
#include <hb.h>
#include <math.h>
/* --show-extents overlay helpers: a stroked rectangle around
* each glyph's ink box, plus a filled dot at the glyph's pen
* origin. Both render in the foreground color.
*
* In DRAW mode, the geometry goes straight into the glyph's
* draw context so it gets rendered/encoded alongside the
* outline in the foreground color.
*
* In PAINT mode, the same geometry feeds an arbitrary-path
* clip and the clipped region is filled with the paint's
* current foreground; the draw-mode and paint-mode emitters
* share all of the coord math. */
static inline void
util_emit_extents_overlay_into_draw (hb_draw_funcs_t *df, void *dd,
const hb_glyph_extents_t *ge,
float pen_x, float pen_y,
float stroke_width)
{
hb_draw_state_t st = HB_DRAW_STATE_DEFAULT;
/* Stroked rectangle around the ink box. Padded outward by
* stroke_width / 2 so the stroke's inner edge sits at the
* box, instead of straddling it (and the inner half
* knocking out against glyph ink under non-zero winding).
* copysignf on the padding keeps the shift outward
* regardless of glyph-extent height-sign convention. */
if (ge->width != 0 || ge->height != 0)
{
float half = 0.5f * stroke_width;
float sx = copysignf (half, ge->width ? (float) ge->width : 1.f);
float sy = copysignf (half, ge->height ? (float) ge->height : 1.f);
hb_draw_rectangle (df, dd, &st,
pen_x + (float) ge->x_bearing - sx,
pen_y + (float) ge->y_bearing - sy,
(float) ge->width + 2 * sx,
(float) ge->height + 2 * sy,
stroke_width);
}
/* Filled dot at the glyph origin (pen_x, pen_y). Radius
* scales with stroke_width so the dot stays visible at the
* same render scale the stroke does. */
hb_draw_circle (df, dd, &st,
pen_x, pen_y,
/*radius*/ 2.f * stroke_width,
/*stroke_width*/ NAN);
}
static inline void
util_emit_extents_overlay_into_paint (hb_paint_funcs_t *pf, void *pd,
const hb_glyph_extents_t *ge,
float pen_x, float pen_y,
float stroke_width)
{
void *dd = nullptr;
hb_draw_funcs_t *df = hb_paint_push_clip_path_start (pf, pd, &dd);
if (!df) return;
util_emit_extents_overlay_into_draw (df, dd, ge, pen_x, pen_y, stroke_width);
hb_paint_push_clip_path_end (pf, pd);
hb_paint_color (pf, pd, /*is_foreground*/ 1, HB_COLOR (0, 0, 0, 255));
hb_paint_pop_clip (pf, pd);
}
#endif /* HELPER_EXTENTS_OVERLAY_HH */