/* * Copyright © 2020 Ebrahim Byagowi * * 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. */ #ifndef HB_DRAW_HH #define HB_DRAW_HH #include "hb.hh" /* * hb_draw_funcs_t */ #define HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS \ HB_DRAW_FUNC_IMPLEMENT (move_to) \ HB_DRAW_FUNC_IMPLEMENT (line_to) \ HB_DRAW_FUNC_IMPLEMENT (quadratic_to) \ HB_DRAW_FUNC_IMPLEMENT (cubic_to) \ HB_DRAW_FUNC_IMPLEMENT (close_path) \ /* ^--- Add new callbacks here */ struct hb_draw_funcs_t { hb_object_header_t header; struct { #define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_func_t name; HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS #undef HB_DRAW_FUNC_IMPLEMENT } func; struct { #define HB_DRAW_FUNC_IMPLEMENT(name) void *name; HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS #undef HB_DRAW_FUNC_IMPLEMENT } *user_data; struct { #define HB_DRAW_FUNC_IMPLEMENT(name) hb_destroy_func_t name; HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS #undef HB_DRAW_FUNC_IMPLEMENT } *destroy; void emit_move_to (void *draw_data, hb_draw_state_t &st, float to_x, float to_y) { func.move_to (this, draw_data, &st, to_x, to_y, !user_data ? nullptr : user_data->move_to); } void emit_line_to (void *draw_data, hb_draw_state_t &st, float to_x, float to_y) { func.line_to (this, draw_data, &st, to_x, to_y, !user_data ? nullptr : user_data->line_to); } void emit_quadratic_to (void *draw_data, hb_draw_state_t &st, float control_x, float control_y, float to_x, float to_y) { func.quadratic_to (this, draw_data, &st, control_x, control_y, to_x, to_y, !user_data ? nullptr : user_data->quadratic_to); } void emit_cubic_to (void *draw_data, hb_draw_state_t &st, float control1_x, float control1_y, float control2_x, float control2_y, float to_x, float to_y) { func.cubic_to (this, draw_data, &st, control1_x, control1_y, control2_x, control2_y, to_x, to_y, !user_data ? nullptr : user_data->cubic_to); } void emit_close_path (void *draw_data, hb_draw_state_t &st) { func.close_path (this, draw_data, &st, !user_data ? nullptr : user_data->close_path); } void move_to (void *draw_data, hb_draw_state_t &st, float to_x, float to_y) { if (st.path_open) close_path (draw_data, st); st.current_x = to_x; st.current_y = to_y; } void line_to (void *draw_data, hb_draw_state_t &st, float to_x, float to_y) { if (!st.path_open) start_path (draw_data, st); emit_line_to (draw_data, st, to_x, to_y); st.current_x = to_x; st.current_y = to_y; } void quadratic_to (void *draw_data, hb_draw_state_t &st, float control_x, float control_y, float to_x, float to_y) { if (!st.path_open) start_path (draw_data, st); emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y); st.current_x = to_x; st.current_y = to_y; } void cubic_to (void *draw_data, hb_draw_state_t &st, float control1_x, float control1_y, float control2_x, float control2_y, float to_x, float to_y) { if (!st.path_open) start_path (draw_data, st); emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y); st.current_x = to_x; st.current_y = to_y; } void close_path (void *draw_data, hb_draw_state_t &st) { if (st.path_open) { if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y)) emit_line_to (draw_data, st, st.path_start_x, st.path_start_y); emit_close_path (draw_data, st); } st.path_open = false; st.path_start_x = st.current_x = st.path_start_y = st.current_y = 0; } protected: void start_path (void *draw_data, hb_draw_state_t &st) { assert (!st.path_open); emit_move_to (draw_data, st, st.current_x, st.current_y); st.path_open = true; st.path_start_x = st.current_x; st.path_start_y = st.current_y; } }; DECLARE_NULL_INSTANCE (hb_draw_funcs_t); struct hb_draw_session_t { hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f) : slant {slant_}, not_slanted {slant == 0.f}, funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT {} ~hb_draw_session_t () { close_path (); } void move_to (float to_x, float to_y) { if (likely (not_slanted)) funcs->move_to (draw_data, st, to_x, to_y); else funcs->move_to (draw_data, st, to_x + to_y * slant, to_y); } void line_to (float to_x, float to_y) { if (likely (not_slanted)) funcs->line_to (draw_data, st, to_x, to_y); else funcs->line_to (draw_data, st, to_x + to_y * slant, to_y); } void quadratic_to (float control_x, float control_y, float to_x, float to_y) { if (likely (not_slanted)) funcs->quadratic_to (draw_data, st, control_x, control_y, to_x, to_y); else funcs->quadratic_to (draw_data, st, control_x + control_y * slant, control_y, to_x + to_y * slant, to_y); } void cubic_to (float control1_x, float control1_y, float control2_x, float control2_y, float to_x, float to_y) { if (likely (not_slanted)) funcs->cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y); else funcs->cubic_to (draw_data, st, control1_x + control1_y * slant, control1_y, control2_x + control2_y * slant, control2_y, to_x + to_y * slant, to_y); } void close_path () { funcs->close_path (draw_data, st); } protected: float slant; bool not_slanted; hb_draw_funcs_t *funcs; void *draw_data; hb_draw_state_t st; }; #endif /* HB_DRAW_HH */