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 move_tohb_draw_funcs_t96 void move_to (void *draw_data, hb_draw_state_t &st, 97 float to_x, float to_y) 98 { 99 if (st.path_open) close_path (draw_data, st); 100 st.current_x = to_x; 101 st.current_y = to_y; 102 } 103 line_tohb_draw_funcs_t104 void line_to (void *draw_data, hb_draw_state_t &st, 105 float to_x, float to_y) 106 { 107 if (!st.path_open) start_path (draw_data, st); 108 emit_line_to (draw_data, st, to_x, to_y); 109 st.current_x = to_x; 110 st.current_y = to_y; 111 } 112 113 void quadratic_tohb_draw_funcs_t114 quadratic_to (void *draw_data, hb_draw_state_t &st, 115 float control_x, float control_y, 116 float to_x, float to_y) 117 { 118 if (!st.path_open) start_path (draw_data, st); 119 emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y); 120 st.current_x = to_x; 121 st.current_y = to_y; 122 } 123 124 void cubic_tohb_draw_funcs_t125 cubic_to (void *draw_data, hb_draw_state_t &st, 126 float control1_x, float control1_y, 127 float control2_x, float control2_y, 128 float to_x, float to_y) 129 { 130 if (!st.path_open) start_path (draw_data, st); 131 emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y); 132 st.current_x = to_x; 133 st.current_y = to_y; 134 } 135 136 void close_pathhb_draw_funcs_t137 close_path (void *draw_data, hb_draw_state_t &st) 138 { 139 if (st.path_open) 140 { 141 if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y)) 142 emit_line_to (draw_data, st, st.path_start_x, st.path_start_y); 143 emit_close_path (draw_data, st); 144 } 145 st.path_open = false; 146 st.path_start_x = st.current_x = st.path_start_y = st.current_y = 0; 147 } 148 149 protected: 150 start_pathhb_draw_funcs_t151 void start_path (void *draw_data, hb_draw_state_t &st) 152 { 153 assert (!st.path_open); 154 emit_move_to (draw_data, st, st.current_x, st.current_y); 155 st.path_open = true; 156 st.path_start_x = st.current_x; 157 st.path_start_y = st.current_y; 158 } 159 }; 160 DECLARE_NULL_INSTANCE (hb_draw_funcs_t); 161 162 struct hb_draw_session_t 163 { hb_draw_session_thb_draw_session_t164 hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f) 165 : slant {slant_}, not_slanted {slant == 0.f}, 166 funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT 167 {} 168 ~hb_draw_session_thb_draw_session_t169 ~hb_draw_session_t () { close_path (); } 170 move_tohb_draw_session_t171 void move_to (float to_x, float to_y) 172 { 173 if (likely (not_slanted)) 174 funcs->move_to (draw_data, st, 175 to_x, to_y); 176 else 177 funcs->move_to (draw_data, st, 178 to_x + to_y * slant, to_y); 179 } line_tohb_draw_session_t180 void line_to (float to_x, float to_y) 181 { 182 if (likely (not_slanted)) 183 funcs->line_to (draw_data, st, 184 to_x, to_y); 185 else 186 funcs->line_to (draw_data, st, 187 to_x + to_y * slant, to_y); 188 } 189 void quadratic_tohb_draw_session_t190 quadratic_to (float control_x, float control_y, 191 float to_x, float to_y) 192 { 193 if (likely (not_slanted)) 194 funcs->quadratic_to (draw_data, st, 195 control_x, control_y, 196 to_x, to_y); 197 else 198 funcs->quadratic_to (draw_data, st, 199 control_x + control_y * slant, control_y, 200 to_x + to_y * slant, to_y); 201 } 202 void cubic_tohb_draw_session_t203 cubic_to (float control1_x, float control1_y, 204 float control2_x, float control2_y, 205 float to_x, float to_y) 206 { 207 if (likely (not_slanted)) 208 funcs->cubic_to (draw_data, st, 209 control1_x, control1_y, 210 control2_x, control2_y, 211 to_x, to_y); 212 else 213 funcs->cubic_to (draw_data, st, 214 control1_x + control1_y * slant, control1_y, 215 control2_x + control2_y * slant, control2_y, 216 to_x + to_y * slant, to_y); 217 } close_pathhb_draw_session_t218 void close_path () 219 { 220 funcs->close_path (draw_data, st); 221 } 222 223 protected: 224 float slant; 225 bool not_slanted; 226 hb_draw_funcs_t *funcs; 227 void *draw_data; 228 hb_draw_state_t st; 229 }; 230 231 #endif /* HB_DRAW_HH */ 232