1 /* 2 * Copyright © 2020 Ebrahim Byagowi 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 25 #ifndef HB_DRAW_HH 26 #define HB_DRAW_HH 27 28 #include "hb.hh" 29 30 31 /* 32 * hb_draw_funcs_t 33 */ 34 35 #define HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS \ 36 HB_DRAW_FUNC_IMPLEMENT (move_to) \ 37 HB_DRAW_FUNC_IMPLEMENT (line_to) \ 38 HB_DRAW_FUNC_IMPLEMENT (quadratic_to) \ 39 HB_DRAW_FUNC_IMPLEMENT (cubic_to) \ 40 HB_DRAW_FUNC_IMPLEMENT (close_path) \ 41 /* ^--- Add new callbacks here */ 42 43 struct hb_draw_funcs_t 44 { 45 hb_object_header_t header; 46 47 struct { 48 #define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_func_t name; 49 HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS 50 #undef HB_DRAW_FUNC_IMPLEMENT 51 } func; 52 53 struct { 54 #define HB_DRAW_FUNC_IMPLEMENT(name) void *name; 55 HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS 56 #undef HB_DRAW_FUNC_IMPLEMENT 57 } *user_data; 58 59 struct { 60 #define HB_DRAW_FUNC_IMPLEMENT(name) hb_destroy_func_t name; 61 HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS 62 #undef HB_DRAW_FUNC_IMPLEMENT 63 } *destroy; 64 emit_move_tohb_draw_funcs_t65 void emit_move_to (void *draw_data, hb_draw_state_t &st, 66 float to_x, float to_y) 67 { func.move_to (this, draw_data, &st, 68 to_x, to_y, 69 !user_data ? nullptr : user_data->move_to); } emit_line_tohb_draw_funcs_t70 void emit_line_to (void *draw_data, hb_draw_state_t &st, 71 float to_x, float to_y) 72 { func.line_to (this, draw_data, &st, 73 to_x, to_y, 74 !user_data ? nullptr : user_data->line_to); } emit_quadratic_tohb_draw_funcs_t75 void emit_quadratic_to (void *draw_data, hb_draw_state_t &st, 76 float control_x, float control_y, 77 float to_x, float to_y) 78 { func.quadratic_to (this, draw_data, &st, 79 control_x, control_y, 80 to_x, to_y, 81 !user_data ? nullptr : user_data->quadratic_to); } emit_cubic_tohb_draw_funcs_t82 void emit_cubic_to (void *draw_data, hb_draw_state_t &st, 83 float control1_x, float control1_y, 84 float control2_x, float control2_y, 85 float to_x, float to_y) 86 { func.cubic_to (this, draw_data, &st, 87 control1_x, control1_y, 88 control2_x, control2_y, 89 to_x, to_y, 90 !user_data ? nullptr : user_data->cubic_to); } emit_close_pathhb_draw_funcs_t91 void emit_close_path (void *draw_data, hb_draw_state_t &st) 92 { func.close_path (this, draw_data, &st, 93 !user_data ? nullptr : user_data->close_path); } 94 95 96 void 97 HB_ALWAYS_INLINE move_tohb_draw_funcs_t98 move_to (void *draw_data, hb_draw_state_t &st, 99 float to_x, float to_y) 100 { 101 if (unlikely (st.path_open)) close_path (draw_data, st); 102 st.current_x = to_x; 103 st.current_y = to_y; 104 } 105 106 void 107 HB_ALWAYS_INLINE line_tohb_draw_funcs_t108 line_to (void *draw_data, hb_draw_state_t &st, 109 float to_x, float to_y) 110 { 111 if (unlikely (!st.path_open)) start_path (draw_data, st); 112 emit_line_to (draw_data, st, to_x, to_y); 113 st.current_x = to_x; 114 st.current_y = to_y; 115 } 116 117 void 118 HB_ALWAYS_INLINE quadratic_tohb_draw_funcs_t119 quadratic_to (void *draw_data, hb_draw_state_t &st, 120 float control_x, float control_y, 121 float to_x, float to_y) 122 { 123 if (unlikely (!st.path_open)) start_path (draw_data, st); 124 emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y); 125 st.current_x = to_x; 126 st.current_y = to_y; 127 } 128 129 void 130 HB_ALWAYS_INLINE cubic_tohb_draw_funcs_t131 cubic_to (void *draw_data, hb_draw_state_t &st, 132 float control1_x, float control1_y, 133 float control2_x, float control2_y, 134 float to_x, float to_y) 135 { 136 if (unlikely (!st.path_open)) start_path (draw_data, st); 137 emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y); 138 st.current_x = to_x; 139 st.current_y = to_y; 140 } 141 142 void 143 HB_ALWAYS_INLINE close_pathhb_draw_funcs_t144 close_path (void *draw_data, hb_draw_state_t &st) 145 { 146 if (likely (st.path_open)) 147 { 148 if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y)) 149 emit_line_to (draw_data, st, st.path_start_x, st.path_start_y); 150 emit_close_path (draw_data, st); 151 } 152 st.path_open = false; 153 st.path_start_x = st.current_x = st.path_start_y = st.current_y = 0; 154 } 155 156 protected: 157 start_pathhb_draw_funcs_t158 void start_path (void *draw_data, hb_draw_state_t &st) 159 { 160 assert (!st.path_open); 161 emit_move_to (draw_data, st, st.current_x, st.current_y); 162 st.path_open = true; 163 st.path_start_x = st.current_x; 164 st.path_start_y = st.current_y; 165 } 166 }; 167 DECLARE_NULL_INSTANCE (hb_draw_funcs_t); 168 169 struct hb_draw_session_t 170 { hb_draw_session_thb_draw_session_t171 hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f) 172 : slant {slant_}, not_slanted {slant == 0.f}, 173 funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT 174 {} 175 ~hb_draw_session_thb_draw_session_t176 ~hb_draw_session_t () { close_path (); } 177 178 HB_ALWAYS_INLINE move_tohb_draw_session_t179 void move_to (float to_x, float to_y) 180 { 181 if (likely (not_slanted)) 182 funcs->move_to (draw_data, st, 183 to_x, to_y); 184 else 185 funcs->move_to (draw_data, st, 186 to_x + to_y * slant, to_y); 187 } 188 HB_ALWAYS_INLINE line_tohb_draw_session_t189 void line_to (float to_x, float to_y) 190 { 191 if (likely (not_slanted)) 192 funcs->line_to (draw_data, st, 193 to_x, to_y); 194 else 195 funcs->line_to (draw_data, st, 196 to_x + to_y * slant, to_y); 197 } 198 void 199 HB_ALWAYS_INLINE quadratic_tohb_draw_session_t200 quadratic_to (float control_x, float control_y, 201 float to_x, float to_y) 202 { 203 if (likely (not_slanted)) 204 funcs->quadratic_to (draw_data, st, 205 control_x, control_y, 206 to_x, to_y); 207 else 208 funcs->quadratic_to (draw_data, st, 209 control_x + control_y * slant, control_y, 210 to_x + to_y * slant, to_y); 211 } 212 void 213 HB_ALWAYS_INLINE cubic_tohb_draw_session_t214 cubic_to (float control1_x, float control1_y, 215 float control2_x, float control2_y, 216 float to_x, float to_y) 217 { 218 if (likely (not_slanted)) 219 funcs->cubic_to (draw_data, st, 220 control1_x, control1_y, 221 control2_x, control2_y, 222 to_x, to_y); 223 else 224 funcs->cubic_to (draw_data, st, 225 control1_x + control1_y * slant, control1_y, 226 control2_x + control2_y * slant, control2_y, 227 to_x + to_y * slant, to_y); 228 } 229 HB_ALWAYS_INLINE close_pathhb_draw_session_t230 void close_path () 231 { 232 funcs->close_path (draw_data, st); 233 } 234 235 public: 236 float slant; 237 bool not_slanted; 238 hb_draw_funcs_t *funcs; 239 void *draw_data; 240 hb_draw_state_t st; 241 }; 242 243 #endif /* HB_DRAW_HH */ 244