Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/harfbuzz/util/helper-cairo-user.hh @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* | |
| 2 * Copyright © 2022 Google, Inc. | |
| 3 * | |
| 4 * This is part of HarfBuzz, a text shaping library. | |
| 5 * | |
| 6 * Permission is hereby granted, without written agreement and without | |
| 7 * license or royalty fees, to use, copy, modify, and distribute this | |
| 8 * software and its documentation for any purpose, provided that the | |
| 9 * above copyright notice and the following two paragraphs appear in | |
| 10 * all copies of this software. | |
| 11 * | |
| 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | |
| 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | |
| 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | |
| 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |
| 16 * DAMAGE. | |
| 17 * | |
| 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | |
| 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | |
| 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | |
| 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | |
| 23 * | |
| 24 * Google Author(s): Behdad Esfahbod | |
| 25 */ | |
| 26 | |
| 27 #ifndef HELPER_CAIRO_USER_HH | |
| 28 #define HELPER_CAIRO_USER_HH | |
| 29 | |
| 30 #include "font-options.hh" | |
| 31 | |
| 32 #include <cairo.h> | |
| 33 #include <hb.h> | |
| 34 | |
| 35 #include "hb-blob.hh" | |
| 36 | |
| 37 static void | |
| 38 move_to (hb_draw_funcs_t *dfuncs, | |
| 39 cairo_t *cr, | |
| 40 hb_draw_state_t *st, | |
| 41 float to_x, float to_y, | |
| 42 void *) | |
| 43 { | |
| 44 cairo_move_to (cr, | |
| 45 (double) to_x, (double) to_y); | |
| 46 } | |
| 47 | |
| 48 static void | |
| 49 line_to (hb_draw_funcs_t *dfuncs, | |
| 50 cairo_t *cr, | |
| 51 hb_draw_state_t *st, | |
| 52 float to_x, float to_y, | |
| 53 void *) | |
| 54 { | |
| 55 cairo_line_to (cr, | |
| 56 (double) to_x, (double) to_y); | |
| 57 } | |
| 58 | |
| 59 static void | |
| 60 cubic_to (hb_draw_funcs_t *dfuncs, | |
| 61 cairo_t *cr, | |
| 62 hb_draw_state_t *st, | |
| 63 float control1_x, float control1_y, | |
| 64 float control2_x, float control2_y, | |
| 65 float to_x, float to_y, | |
| 66 void *) | |
| 67 { | |
| 68 cairo_curve_to (cr, | |
| 69 (double) control1_x, (double) control1_y, | |
| 70 (double) control2_x, (double) control2_y, | |
| 71 (double) to_x, (double) to_y); | |
| 72 } | |
| 73 | |
| 74 static void | |
| 75 close_path (hb_draw_funcs_t *dfuncs, | |
| 76 cairo_t *cr, | |
| 77 hb_draw_state_t *st, | |
| 78 void *) | |
| 79 { | |
| 80 cairo_close_path (cr); | |
| 81 } | |
| 82 | |
| 83 | |
| 84 static hb_draw_funcs_t * | |
| 85 get_cairo_draw_funcs () | |
| 86 { | |
| 87 static hb_draw_funcs_t *funcs; | |
| 88 | |
| 89 if (!funcs) | |
| 90 { | |
| 91 funcs = hb_draw_funcs_create (); | |
| 92 hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to, nullptr, nullptr); | |
| 93 hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to, nullptr, nullptr); | |
| 94 hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to, nullptr, nullptr); | |
| 95 hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path, nullptr, nullptr); | |
| 96 } | |
| 97 | |
| 98 return funcs; | |
| 99 } | |
| 100 | |
| 101 static const cairo_user_data_key_t _hb_font_cairo_user_data_key = {0}; | |
| 102 | |
| 103 static cairo_status_t | |
| 104 render_glyph (cairo_scaled_font_t *scaled_font, | |
| 105 unsigned long glyph, | |
| 106 cairo_t *cr, | |
| 107 cairo_text_extents_t *extents) | |
| 108 { | |
| 109 hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), | |
| 110 &_hb_font_cairo_user_data_key)); | |
| 111 | |
| 112 hb_position_t x_scale, y_scale; | |
| 113 hb_font_get_scale (font, &x_scale, &y_scale); | |
| 114 cairo_scale (cr, +1./x_scale, -1./y_scale); | |
| 115 | |
| 116 hb_font_get_glyph_shape (font, glyph, get_cairo_draw_funcs (), cr); | |
| 117 cairo_fill (cr); | |
| 118 | |
| 119 return CAIRO_STATUS_SUCCESS; | |
| 120 } | |
| 121 | |
| 122 #ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC | |
| 123 | |
| 124 #ifdef CAIRO_HAS_PNG_FUNCTIONS | |
| 125 static inline cairo_status_t | |
| 126 _hb_bytes_read_func (hb_bytes_t *src, | |
| 127 char *data, | |
| 128 unsigned length) | |
| 129 { | |
| 130 if (unlikely (src->length < length)) | |
| 131 return CAIRO_STATUS_READ_ERROR; | |
| 132 | |
| 133 memcpy (data, src->arrayZ, length); | |
| 134 *src += length; | |
| 135 | |
| 136 return CAIRO_STATUS_SUCCESS; | |
| 137 } | |
| 138 | |
| 139 static cairo_status_t | |
| 140 render_color_glyph_png (cairo_scaled_font_t *scaled_font, | |
| 141 unsigned long glyph, | |
| 142 cairo_t *cr, | |
| 143 cairo_text_extents_t *extents) | |
| 144 { | |
| 145 hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), | |
| 146 &_hb_font_cairo_user_data_key)); | |
| 147 | |
| 148 hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, glyph); | |
| 149 if (blob == hb_blob_get_empty ()) | |
| 150 return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED; | |
| 151 | |
| 152 hb_position_t x_scale, y_scale; | |
| 153 hb_font_get_scale (font, &x_scale, &y_scale); | |
| 154 cairo_scale (cr, +1./x_scale, -1./y_scale); | |
| 155 | |
| 156 /* Draw PNG. */ | |
| 157 hb_bytes_t bytes = blob->as_bytes (); | |
| 158 cairo_surface_t *surface = cairo_image_surface_create_from_png_stream ((cairo_read_func_t) _hb_bytes_read_func, | |
| 159 std::addressof (bytes)); | |
| 160 hb_blob_destroy (blob); | |
| 161 | |
| 162 if (unlikely (cairo_surface_status (surface)) != CAIRO_STATUS_SUCCESS) | |
| 163 { | |
| 164 cairo_surface_destroy (surface); | |
| 165 return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED; | |
| 166 } | |
| 167 | |
| 168 int width = cairo_image_surface_get_width (surface); | |
| 169 int height = cairo_image_surface_get_width (surface); | |
| 170 | |
| 171 hb_glyph_extents_t hb_extents; | |
| 172 if (unlikely (!hb_font_get_glyph_extents (font, glyph, &hb_extents))) | |
| 173 { | |
| 174 cairo_surface_destroy (surface); | |
| 175 return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED; | |
| 176 } | |
| 177 | |
| 178 cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface); | |
| 179 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); | |
| 180 | |
| 181 cairo_matrix_t matrix = {(double) width, 0, 0, (double) height, 0, 0}; | |
| 182 cairo_pattern_set_matrix (pattern, &matrix); | |
| 183 | |
| 184 cairo_translate (cr, hb_extents.x_bearing, hb_extents.y_bearing); | |
| 185 cairo_scale (cr, hb_extents.width, hb_extents.height); | |
| 186 cairo_set_source (cr, pattern); | |
| 187 | |
| 188 cairo_rectangle (cr, 0, 0, 1, 1); | |
| 189 cairo_fill (cr); | |
| 190 cairo_pattern_destroy (pattern); | |
| 191 | |
| 192 cairo_surface_destroy (surface); | |
| 193 return CAIRO_STATUS_SUCCESS; | |
| 194 } | |
| 195 #endif | |
| 196 | |
| 197 static cairo_status_t | |
| 198 render_color_glyph_layers (cairo_scaled_font_t *scaled_font, | |
| 199 unsigned long glyph, | |
| 200 cairo_t *cr, | |
| 201 cairo_text_extents_t *extents) | |
| 202 { | |
| 203 hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), | |
| 204 &_hb_font_cairo_user_data_key)); | |
| 205 hb_face_t *face = hb_font_get_face (font); | |
| 206 | |
| 207 unsigned count = hb_ot_color_glyph_get_layers (face, glyph, 0, nullptr, nullptr); | |
| 208 if (!count) | |
| 209 return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED; | |
| 210 | |
| 211 hb_ot_color_layer_t layers[16]; | |
| 212 unsigned offset = 0, len; | |
| 213 do { | |
| 214 len = ARRAY_LENGTH (layers); | |
| 215 hb_ot_color_glyph_get_layers (face, glyph, | |
| 216 offset, | |
| 217 &len, | |
| 218 layers); | |
| 219 for (unsigned i = 0; i < len; i++) | |
| 220 { | |
| 221 hb_color_t color; | |
| 222 unsigned clen = 1; | |
| 223 unsigned color_index = layers[i].color_index; | |
| 224 bool is_foreground = color_index == 65535; | |
| 225 | |
| 226 if (!is_foreground) | |
| 227 { | |
| 228 hb_ot_color_palette_get_colors (face, | |
| 229 0/*palette_index*/, | |
| 230 color_index/*start_offset*/, | |
| 231 &clen/*color_count*/, | |
| 232 &color); | |
| 233 if (clen < 1) | |
| 234 continue; | |
| 235 } | |
| 236 | |
| 237 cairo_save (cr); | |
| 238 { | |
| 239 if (!is_foreground) | |
| 240 cairo_set_source_rgba (cr, | |
| 241 hb_color_get_red (color) / 255., | |
| 242 hb_color_get_green (color) / 255., | |
| 243 hb_color_get_blue (color) / 255., | |
| 244 hb_color_get_alpha (color) / 255.); | |
| 245 | |
| 246 cairo_status_t ret = render_glyph (scaled_font, layers[i].glyph, cr, extents); | |
| 247 if (ret != CAIRO_STATUS_SUCCESS) | |
| 248 return ret; | |
| 249 } | |
| 250 cairo_restore (cr); | |
| 251 } | |
| 252 } | |
| 253 while (len == ARRAY_LENGTH (layers)); | |
| 254 return CAIRO_STATUS_SUCCESS; | |
| 255 } | |
| 256 | |
| 257 static cairo_status_t | |
| 258 render_color_glyph (cairo_scaled_font_t *scaled_font, | |
| 259 unsigned long glyph, | |
| 260 cairo_t *cr, | |
| 261 cairo_text_extents_t *extents) | |
| 262 { | |
| 263 cairo_status_t ret = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED; | |
| 264 | |
| 265 #ifdef CAIRO_HAS_PNG_FUNCTIONS | |
| 266 ret = render_color_glyph_png (scaled_font, glyph, cr, extents); | |
| 267 if (ret != CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED) | |
| 268 return ret; | |
| 269 #endif | |
| 270 | |
| 271 ret = render_color_glyph_layers (scaled_font, glyph, cr, extents); | |
| 272 if (ret != CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED) | |
| 273 return ret; | |
| 274 | |
| 275 return render_glyph (scaled_font, glyph, cr, extents); | |
| 276 } | |
| 277 | |
| 278 #endif | |
| 279 | |
| 280 static inline cairo_font_face_t * | |
| 281 helper_cairo_create_user_font_face (const font_options_t *font_opts) | |
| 282 { | |
| 283 cairo_font_face_t *cairo_face = cairo_user_font_face_create (); | |
| 284 | |
| 285 cairo_font_face_set_user_data (cairo_face, | |
| 286 &_hb_font_cairo_user_data_key, | |
| 287 hb_font_reference (font_opts->font), | |
| 288 (cairo_destroy_func_t) hb_font_destroy); | |
| 289 | |
| 290 cairo_user_font_face_set_render_glyph_func (cairo_face, render_glyph); | |
| 291 #ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC | |
| 292 hb_face_t *face = hb_font_get_face (font_opts->font); | |
| 293 if (hb_ot_color_has_png (face) || hb_ot_color_has_layers (face)) | |
| 294 cairo_user_font_face_set_render_color_glyph_func (cairo_face, render_color_glyph); | |
| 295 #endif | |
| 296 | |
| 297 return cairo_face; | |
| 298 } | |
| 299 | |
| 300 static inline bool | |
| 301 helper_cairo_user_font_face_has_data (cairo_font_face_t *font_face) | |
| 302 { | |
| 303 return cairo_font_face_get_user_data (font_face, &_hb_font_cairo_user_data_key); | |
| 304 } | |
| 305 | |
| 306 static inline bool | |
| 307 helper_cairo_user_scaled_font_has_color (cairo_scaled_font_t *scaled_font) | |
| 308 { | |
| 309 /* Ignoring SVG for now, since we cannot render it. */ | |
| 310 hb_font_t *font = (hb_font_t *) (cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), | |
| 311 &_hb_font_cairo_user_data_key)); | |
| 312 hb_face_t *face = hb_font_get_face (font); | |
| 313 return hb_ot_color_has_png (face) || hb_ot_color_has_layers (face); | |
| 314 } | |
| 315 | |
| 316 #endif |
