Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/harfbuzz/src/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 13 kB image not shown  

Quelle  hb-gpu-paint.hh   Sprache: C

 

/*
 * Copyright (C) 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 HB_GPU_PAINT_HH
#define HB_GPU_PAINT_HH

#include "hb.hh"
#include "hb-gpu.h"
#include "hb-geometry.hh"
#include "hb-map.hh"
#include "hb-object.hh"


/*
 * hb_gpu_paint_t encoded-blob design
 * ==================================
 *
 * One blob per glyph.  One quad per glyph.  The fragment shader
 * is the interpreter: it walks a flat op stream per pixel, maintains
 * a small group stack, and composites the result.
 *
 * The encoder turns a COLRv1 paint tree (visited via hb_paint_funcs_t
 * callbacks) into a pre-order op stream plus embedded sub-payloads,
 * all packed into a single RGBA16I blob suitable for
 * hb_blob_t-style upload into the same shared atlas used by the
 * draw renderer.
 *
 * --- Top-level layout --------------------------------------------
 *
 *   [header]
 *   [op stream]          -- variable number of op records
 *   [sub-payloads]       -- clip-glyph Slug draw blobs and
 *                           gradient parameter blobs, referenced
 *                           by intra-blob offsets from the ops
 *
 * Every offset in the blob is a texel index (RGBA16I, 8 bytes per
 * texel) relative to the blob's base address.  The caller uploads
 * the blob at some atlas_base offset and adds that base to the
 * glyph's vertex attribute; the fragment shader sees one absolute
 * atlas offset per glyph and discovers everything else by walking
 * inside.
 *
 * --- Header -------------------------------------------------------
 *
 *   texel 0: (num_ops:i16, reserved:i16, reserved:i16, reserved:i16)
 *   texel 1: (ext_min_x:i16, ext_min_y:i16,
 *             ext_max_x:i16, ext_max_y:i16)   -- in HB_GPU units
 *   texel 2: (ops_offset:i16, reserved:i16,
 *             reserved:i16, reserved:i16)
 *
 * --- Op record ----------------------------------------------------
 *
 * Each op is exactly one RGBA16I texel (4 int16s):
 *
 *   (op_type:i16, op_aux:i16, payload_hi:i16, payload_lo:i16)
 *
 * op_type values:
 *
 *   0  LAYER_SOLID
 *        aux      = flags (bit 0 = is_foreground)
 *        payload  = clip_glyph_offset (texel index)
 *        followed by one extra texel:
 *          (r_q15:i16, g_q15:i16, b_q15:i16, a_q15:i16)
 *        flags bit 0: is_foreground -- use the shader's foreground
 *                     uniform/varying instead of the baked color
 *                     (so runtime foreground changes still work)
 *
 *   1  LAYER_GRADIENT
 *        aux      = gradient subtype  (0=linear, 1=radial, 2=sweep)
 *        payload  = clip_glyph_offset (texel index)
 *        followed by one extra texel:
 *          (grad_offset_hi:i16, grad_offset_lo:i16,
 *           reserved:i16, reserved:i16)
 *
 *   2  PUSH_GROUP
 *        aux      = 0
 *        payload  = 0
 *
 *   3  POP_GROUP
 *        aux      = composite mode, enumerated 0..27 matching
 *                   hb_paint_composite_mode_t
 *        payload  = 0
 *
 * The fragment shader reads the first texel, inspects op_type,
 * and knows from the type whether a trailing texel follows.  Ops
 * are therefore mixed-size but self-delimiting.
 *
 * --- Sub-payload: clip-glyph Slug draw blob ----------------------
 *
 * Exactly the format produced by hb_gpu_draw_encode().  Referenced
 * by LAYER_SOLID and LAYER_GRADIENT.
 *
 * The outline fed into the draw encoder has the enclosing paint
 * transform baked in at CPU encode time.  v1 does not dedup
 * outlines that differ only by translation; v2 may keep the outline
 * in canonical pre-translate space and store a per-op (dx, dy)
 * offset in the aux/payload slots.
 *
 * --- Sub-payload: gradient parameter blob ------------------------
 *
 *   texels 0..2  : inverse affine transform, 6 components as
 *                  q15.16 fixed point (two int16 per component,
 *                  int part then fraction)
 *   texel 3      : (grad_subtype:i16, extend_mode:i16,
 *                   reserved:i16, reserved:i16)
 *   texels 4..N  : subtype-specific params
 *                  linear: (x0, y0, px, py)  -- two texels
 *                          where p is the foot of perpendicular
 *                          from p2 onto the p0..p1 line
 *                  radial: (x0, y0, x1, y1), (r0, r1, _, _)
 *                  sweep:  (x0, y0, start_q14, end_q14)
 *                          angles in q14 fractions of pi
 *   texels ...   : color stops, each one texel:
 *                    (offset_q8<<1 | last_stop_bit,
 *                     palette_index:i16,
 *                     flags:i16,
 *                     alpha_q15:i16)
 *                  flags / alpha_q15 semantics match LAYER_SOLID.
 *                  The last stop is marked by the LSB of
 *                  offset_q8 being 1 (offsets quantized to q8 so
 *                  the bit is free for the marker).
 *
 * --- Shader entry point -----------------------------------------
 *
 *   vec4 hb_gpu_paint (vec2 renderCoord, uint glyphLoc,
 *                      vec4 foreground);
 *
 * Returns premultiplied RGBA.  The caller passes foreground in
 * explicitly; sourcing it from a uniform, a per-quad flat varying,
 * or anywhere else is the caller's decision.
 *
 * Colors are baked into the blob at encode time (as signed Q15
 * RGBA in a single texel per layer).  There is no runtime palette
 * buffer to bind or size.  Palette selection and per-run custom
 * palette overrides are set on the encoder via
 * hb_gpu_paint_set_palette() / hb_gpu_paint_set_custom_palette_color();
 * changing either invalidates previously encoded blobs and requires
 * re-encoding.  The is_foreground flag still routes through the
 * shader's foreground parameter so a dark-mode toggle does not
 * require re-encoding.
 *
 * --- Fragment-shader contract ------------------------------------
 *
 * Per pixel:
 *   acc    = vec4 (0)                    -- transparent
 *   stack  = array<vec4, HB_GPU_PAINT_GROUP_DEPTH>
 *   sp     = 0
 *
 *   for op in ops:
 *     LAYER_SOLID:
 *       cov = hb_gpu_draw (texcoord, clip_glyph_offset)
 *       col = is_foreground ? v_foreground : rgba_q15 / 32767
 *       acc = src_over (col * cov, acc)
 *     LAYER_GRADIENT:
 *       cov = hb_gpu_draw (texcoord, clip_glyph_offset)
 *       col = sample_gradient (texcoord, grad_offset, subtype)
 *       acc = src_over (col * cov, acc)
 *     PUSH_GROUP:
 *       stack[sp++] = acc
 *       acc = vec4 (0)
 *     POP_GROUP:
 *       acc = composite (stack[--sp], acc, composite_mode)
 *
 *   write acc to gl_FragColor
 *
 * HB_GPU_PAINT_GROUP_DEPTH is compile-time fixed at 4.  Encoder
 * validates nesting depth and fails encode if a paint tree exceeds
 * it.  Typical COLRv1 emoji nest 0..2 groups deep.
 *
 * --- Encoder state ----------------------------------------------
 *
 * hb_gpu_paint_t accumulates, during hb_font_paint_glyph_or_fail:
 *
 *   - transform stack (visited push/pop_transform)
 *   - current clip-glyph snapshot captured on push_clip_glyph:
 *       (font, codepoint, transform_at_push)
 *     consumed by the next color / gradient callback to emit a
 *     LAYER_SOLID or LAYER_GRADIENT op
 *   - flat op buffer
 *   - flat sub-payload buffer (bytes; offsets recorded as ops emit)
 *   - scratch hb_gpu_draw_t used to rasterize each clip-glyph
 *     outline under its baked transform
 *   - scratch int16 vector for gradient encoding
 *   - current group depth counter (for validation against
 *     HB_GPU_PAINT_GROUP_DEPTH)
 *   - recycled output blob
 *
 * To preserve palette indices across harfbuzz's paint pipeline
 * (which resolves them to hb_color_t before the color / color-stop
 * callbacks fire), the encoder registers a custom_palette_color
 * callback that returns a sentinel hb_color_t with the palette
 * index embedded.  Downstream color / color-stop callbacks decode
 * the sentinel to recover the index.  Foreground colors are
 * signalled independently by the is_foreground flag that harfbuzz
 * supplies, so the sentinel never collides with a genuine
 * foreground request.
 *
 * On hb_gpu_paint_encode:
 *   - emit header (num_ops, extents, ops_offset)
 *   - emit op stream
 *   - append accumulated sub-payload buffer
 *   - patch any ops that held byte offsets to convert to texel
 *     offsets
 *   - return blob
 *
 * --- Out of scope for v1 ----------------------------------------
 *
 *   - Clip-rectangle paints (push_clip_rectangle / pop_clip).
 *     COLRv1 allows them but they are rare; v1 emits nothing for
 *     them and the caller loses clipping precision.  v2 adds a
 *     RECT_CLIP op with four fixed-point extents.
 *   - Paint images (hb_paint_funcs_set_image_func).  Always
 *     returns unhandled.  Images are better served by a separate
 *     bitmap path.
 */


struct hb_gpu_paint_t
{
  hb_object_header_t header;

  /* Persistent configuration (survives hb_gpu_paint_clear). */
  unsigned   palette    = 0;
  hb_map_t  *custom_palette = nullptr;

  /* Current effective affine (stack is grown/shrunk by
   * push_transform / pop_transform callbacks). */

  hb_transform_t<float> cur_transform = {1, 0, 0, 1, 0, 0};
  hb_vector_t<hb_transform_t<float>> transform_stack;

  /* Font scale (set by hb_gpu_paint_glyph()). */
  int x_scale = 0;
  int y_scale = 0;

  /* Accumulator state (cleared by hb_gpu_paint_clear). */

  /* Flat int16 op stream.  Each op is a sequence of i16 words
   * whose total length is determined by the op type (see the
   * design notes at the top of this file). */

  hb_vector_t<int16_t> ops;
  unsigned num_ops = 0;

  /* Clip-glyph Slug sub-blobs collected during paint walk.
   * Referenced by sub_blob_index recorded inside ops;
   * hb_gpu_paint_encode() concatenates them after the op stream and
   * patches the recorded indices into texel offsets. */

  hb_vector_t<hb_blob_t *> sub_blobs;

  /* Nesting depth of push_group / pop_group.  We bail (set
   * `unsupported`) if it exceeds HB_GPU_PAINT_MAX_GROUP_DEPTH,
   * which matches HB_GPU_PAINT_GROUP_DEPTH in the fragment shader. */

  unsigned group_depth = 0;

  /* Stack of pending clips.  Each color/gradient op consumes the
   * current state of this stack: the layer is rendered where ALL
   * stacked clips are opaque (intersection).  Capped at depth
   * HB_GPU_PAINT_MAX_CLIP_DEPTH; deeper pushes set `unsupported`.
   * The transform is the one current at push_clip_glyph time --
   * the clip outline is defined in that coord space, a subsequent
   * gradient params callback may run under deeper transforms which
   * we use for the gradient but not the clip outline. */

  struct pending_clip_t
  {
    hb_codepoint_t        glyph;    /* HB_CODEPOINT_INVALID for path clips */
    hb_font_t            *font;     /* borrowed; nullptr for path clips */
    hb_transform_t<float> transform;
    /* Path clips are encoded into a sub-blob at push_clip_path_end
     * time; glyph clips re-encode per consuming layer.  For path
     * clips, sub_blob_index is the pre-baked index and ext_* the
     * captured design-unit extents.  For glyph clips, sub_blob_index
     * is -1 and the ext_* fields are unused. */

    int                   sub_blob_index;
    int                   ext_x0, ext_y0, ext_x1, ext_y1;
  };
  pending_clip_t clip_stack[3];
  unsigned       clip_depth = 0;

  /* Carries the cur_transform captured at push_clip_path_start
   * through to push_clip_path_end, where the encoded clip is
   * committed to clip_stack. */

  hb_transform_t<float> pending_clip_path_transform = {};
  bool                  pending_clip_path = false;

  /* Set when the paint walk emits v1-only callbacks we do not yet
   * support.  hb_gpu_paint_encode() returns NULL in that case. */

  bool unsupported = false;

  /* Extents in font design units, accumulated across layers. */
  int ext_min_x =  0x7fffffff;
  int ext_min_y =  0x7fffffff;
  int ext_max_x = -0x7fffffff;
  int ext_max_y = -0x7fffffff;

  /* Scratch: used to rasterize each clip-glyph outline. */
  hb_gpu_draw_t *scratch_draw = nullptr;

  /* Scratch: color stops fetched per gradient callback. */
  hb_vector_t<hb_color_stop_t> color_stops_scratch;

  /* Recycled output blob. */
  hb_blob_t *recycled_blob = nullptr;

  bool fetch_color_stops (hb_color_line_t *color_line)
  {
    unsigned count = hb_color_line_get_color_stops (color_line, 0, nullptr, nullptr);
    if (unlikely (!count || !color_stops_scratch.resize (count)))
    {
      color_stops_scratch.resize (0);
      return false;
    }
    hb_color_line_get_color_stops (color_line, 0, &count, color_stops_scratch.arrayZ);
    return true;
  }
};


#endif /* HB_GPU_PAINT_HH */

Messung V0.5 in Prozent
C=95 H=100 G=97

¤ Dauer der Verarbeitung: 0.24 Sekunden  (vorverarbeitet am  2026-09-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.