hb-ot-cff2-table.cc (7193B)
1 /* 2 * Copyright © 2018 Adobe 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 * Adobe Author(s): Michiharu Ariza 25 */ 26 27 #include "hb.hh" 28 29 #ifndef HB_NO_OT_FONT_CFF 30 31 #include "hb-ot-cff2-table.hh" 32 #include "hb-cff2-interp-cs.hh" 33 #include "hb-draw.hh" 34 35 using namespace CFF; 36 37 struct cff2_extents_param_t 38 { 39 cff2_extents_param_t () 40 { 41 min_x.set_int (INT_MAX); 42 min_y.set_int (INT_MAX); 43 max_x.set_int (INT_MIN); 44 max_y.set_int (INT_MIN); 45 } 46 47 void start_path () { path_open = true; } 48 void end_path () { path_open = false; } 49 bool is_path_open () const { return path_open; } 50 51 void update_bounds (const point_t &pt) 52 { 53 if (pt.x < min_x) min_x = pt.x; 54 if (pt.x > max_x) max_x = pt.x; 55 if (pt.y < min_y) min_y = pt.y; 56 if (pt.y > max_y) max_y = pt.y; 57 } 58 59 bool path_open = false; 60 number_t min_x; 61 number_t min_y; 62 number_t max_x; 63 number_t max_y; 64 }; 65 66 struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t<number_t>, cff2_extents_param_t> 67 { 68 static void moveto (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt) 69 { 70 param.end_path (); 71 env.moveto (pt); 72 } 73 74 static void line (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt1) 75 { 76 if (!param.is_path_open ()) 77 { 78 param.start_path (); 79 param.update_bounds (env.get_pt ()); 80 } 81 env.moveto (pt1); 82 param.update_bounds (env.get_pt ()); 83 } 84 85 static void curve (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) 86 { 87 if (!param.is_path_open ()) 88 { 89 param.start_path (); 90 param.update_bounds (env.get_pt ()); 91 } 92 /* include control points */ 93 param.update_bounds (pt1); 94 param.update_bounds (pt2); 95 env.moveto (pt3); 96 param.update_bounds (env.get_pt ()); 97 } 98 }; 99 100 struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t, cff2_path_procs_extents_t> {}; 101 102 bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, 103 hb_codepoint_t glyph, 104 hb_glyph_extents_t *extents) const 105 { 106 return get_extents_at (font, glyph, extents, hb_array (font->coords, font->num_coords)); 107 } 108 109 bool OT::cff2::accelerator_t::get_extents_at (hb_font_t *font, 110 hb_codepoint_t glyph, 111 hb_glyph_extents_t *extents, 112 hb_array_t<const int> coords) const 113 { 114 #ifdef HB_NO_OT_FONT_CFF 115 /* XXX Remove check when this code moves to .hh file. */ 116 return true; 117 #endif 118 119 if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; 120 121 unsigned int fd = fdSelect->get_fd (glyph); 122 const hb_ubytes_t str = (*charStrings)[glyph]; 123 cff2_cs_interp_env_t<number_t> env (str, *this, fd, coords.arrayZ, coords.length); 124 cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t> interp (env); 125 cff2_extents_param_t param; 126 if (unlikely (!interp.interpret (param))) return false; 127 128 if (param.min_x >= param.max_x) 129 { 130 extents->width = 0; 131 extents->x_bearing = 0; 132 } 133 else 134 { 135 extents->x_bearing = roundf (param.min_x.to_real ()); 136 extents->width = roundf (param.max_x.to_real () - extents->x_bearing); 137 } 138 if (param.min_y >= param.max_y) 139 { 140 extents->height = 0; 141 extents->y_bearing = 0; 142 } 143 else 144 { 145 extents->y_bearing = roundf (param.max_y.to_real ()); 146 extents->height = roundf (param.min_y.to_real () - extents->y_bearing); 147 } 148 149 font->scale_glyph_extents (extents); 150 151 return true; 152 } 153 154 struct cff2_path_param_t 155 { 156 cff2_path_param_t (hb_font_t *font_, hb_draw_session_t &draw_session_) 157 { 158 draw_session = &draw_session_; 159 font = font_; 160 } 161 162 void move_to (const point_t &p) 163 { draw_session->move_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); } 164 165 void line_to (const point_t &p) 166 { draw_session->line_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); } 167 168 void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3) 169 { 170 draw_session->cubic_to (font->em_fscalef_x (p1.x.to_real ()), font->em_fscalef_y (p1.y.to_real ()), 171 font->em_fscalef_x (p2.x.to_real ()), font->em_fscalef_y (p2.y.to_real ()), 172 font->em_fscalef_x (p3.x.to_real ()), font->em_fscalef_y (p3.y.to_real ())); 173 } 174 175 protected: 176 hb_draw_session_t *draw_session; 177 hb_font_t *font; 178 }; 179 180 struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t<number_t>, cff2_path_param_t> 181 { 182 static void moveto (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt) 183 { 184 param.move_to (pt); 185 env.moveto (pt); 186 } 187 188 static void line (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt1) 189 { 190 param.line_to (pt1); 191 env.moveto (pt1); 192 } 193 194 static void curve (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) 195 { 196 param.cubic_to (pt1, pt2, pt3); 197 env.moveto (pt3); 198 } 199 }; 200 201 struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t, cff2_path_procs_path_t> {}; 202 203 bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const 204 { 205 return get_path_at (font, 206 glyph, 207 draw_session, 208 hb_array (font->coords, 209 font->has_nonzero_coords ? font->num_coords : 0)); 210 } 211 212 bool OT::cff2::accelerator_t::get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t<const int> coords) const 213 { 214 #ifdef HB_NO_OT_FONT_CFF 215 /* XXX Remove check when this code moves to .hh file. */ 216 return true; 217 #endif 218 219 if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; 220 221 unsigned int fd = fdSelect->get_fd (glyph); 222 const hb_ubytes_t str = (*charStrings)[glyph]; 223 cff2_cs_interp_env_t<number_t> env (str, *this, fd, coords.arrayZ, coords.length); 224 cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t> interp (env); 225 cff2_path_param_t param (font, draw_session); 226 if (unlikely (!interp.interpret (param))) return false; 227 return true; 228 } 229 230 #endif