232 lines
6.5 KiB
C++
232 lines
6.5 KiB
C++
/*
|
|
* 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 */
|