2 * Copyright © 2022 Behdad Esfahbod
4 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
25 #ifndef HB_PAINT_EXTENTS_HH
26 #define HB_PAINT_EXTENTS_HH
32 typedef struct hb_extents_t
35 hb_extents_t (float xmin
, float ymin
, float xmax
, float ymax
) :
36 xmin (xmin
), ymin (ymin
), xmax (xmax
), ymax (ymax
) {}
38 bool is_empty () const { return xmin
>= xmax
|| ymin
>= ymax
; }
39 bool is_void () const { return xmin
> xmax
; }
41 void union_ (const hb_extents_t
&o
)
43 xmin
= hb_min (xmin
, o
.xmin
);
44 ymin
= hb_min (ymin
, o
.ymin
);
45 xmax
= hb_max (xmax
, o
.xmax
);
46 ymax
= hb_max (ymax
, o
.ymax
);
49 void intersect (const hb_extents_t
&o
)
51 xmin
= hb_max (xmin
, o
.xmin
);
52 ymin
= hb_max (ymin
, o
.ymin
);
53 xmax
= hb_min (xmax
, o
.xmax
);
54 ymax
= hb_min (ymax
, o
.ymax
);
58 add_point (float x
, float y
)
60 if (unlikely (is_void ()))
67 xmin
= hb_min (xmin
, x
);
68 ymin
= hb_min (ymin
, y
);
69 xmax
= hb_max (xmax
, x
);
70 ymax
= hb_max (ymax
, y
);
80 typedef struct hb_transform_t
83 hb_transform_t (float xx
, float yx
,
86 xx (xx
), yx (yx
), xy (xy
), yy (yy
), x0 (x0
), y0 (y0
) {}
88 void multiply (const hb_transform_t
&o
)
90 /* Copied from cairo, with "o" being "a" there and "this" being "b" there. */
93 r
.xx
= o
.xx
* xx
+ o
.yx
* xy
;
94 r
.yx
= o
.xx
* yx
+ o
.yx
* yy
;
96 r
.xy
= o
.xy
* xx
+ o
.yy
* xy
;
97 r
.yy
= o
.xy
* yx
+ o
.yy
* yy
;
99 r
.x0
= o
.x0
* xx
+ o
.y0
* xy
+ x0
;
100 r
.y0
= o
.x0
* yx
+ o
.y0
* yy
+ y0
;
105 void transform_distance (float &dx
, float &dy
) const
107 float new_x
= xx
* dx
+ xy
* dy
;
108 float new_y
= yx
* dx
+ yy
* dy
;
113 void transform_point (float &x
, float &y
) const
115 transform_distance (x
, y
);
120 void transform_extents (hb_extents_t
&extents
) const
122 float quad_x
[4], quad_y
[4];
124 quad_x
[0] = extents
.xmin
;
125 quad_y
[0] = extents
.ymin
;
126 quad_x
[1] = extents
.xmin
;
127 quad_y
[1] = extents
.ymax
;
128 quad_x
[2] = extents
.xmax
;
129 quad_y
[2] = extents
.ymin
;
130 quad_x
[3] = extents
.xmax
;
131 quad_y
[3] = extents
.ymax
;
133 extents
= hb_extents_t
{};
134 for (unsigned i
= 0; i
< 4; i
++)
136 transform_point (quad_x
[i
], quad_y
[i
]);
137 extents
.add_point (quad_x
[i
], quad_y
[i
]);
149 typedef struct hb_bounds_t
157 hb_bounds_t (status_t status
) : status (status
) {}
158 hb_bounds_t (const hb_extents_t
&extents
) :
159 status (extents
.is_empty () ? EMPTY
: BOUNDED
), extents (extents
) {}
161 void union_ (const hb_bounds_t
&o
)
163 if (o
.status
== UNBOUNDED
)
165 else if (o
.status
== BOUNDED
)
169 else if (status
== BOUNDED
)
170 extents
.union_ (o
.extents
);
174 void intersect (const hb_bounds_t
&o
)
176 if (o
.status
== EMPTY
)
178 else if (o
.status
== BOUNDED
)
180 if (status
== UNBOUNDED
)
182 else if (status
== BOUNDED
)
184 extents
.intersect (o
.extents
);
185 if (extents
.is_empty ())
192 hb_extents_t extents
;
195 typedef struct hb_paint_extents_context_t hb_paint_extents_context_t
;
197 struct hb_paint_extents_context_t
199 hb_paint_extents_context_t ()
201 transforms
.push (hb_transform_t
{});
202 clips
.push (hb_bounds_t
{hb_bounds_t::UNBOUNDED
});
203 groups
.push (hb_bounds_t
{hb_bounds_t::EMPTY
});
206 hb_extents_t
get_extents ()
208 return groups
.tail().extents
;
213 return groups
.tail().status
!= hb_bounds_t::UNBOUNDED
;
216 void push_transform (const hb_transform_t
&trans
)
218 hb_transform_t t
= transforms
.tail ();
223 void pop_transform ()
228 void push_clip (hb_extents_t extents
)
230 /* Transform extents and push a new clip. */
231 const hb_transform_t
&t
= transforms
.tail ();
232 t
.transform_extents (extents
);
234 clips
.push (hb_bounds_t
{extents
});
244 groups
.push (hb_bounds_t
{hb_bounds_t::EMPTY
});
247 void pop_group (hb_paint_composite_mode_t mode
)
249 const hb_bounds_t src_bounds
= groups
.pop ();
250 hb_bounds_t
&backdrop_bounds
= groups
.tail ();
252 // https://learn.microsoft.com/en-us/typography/opentype/spec/colr#format-32-paintcomposite
255 case HB_PAINT_COMPOSITE_MODE_CLEAR
:
256 backdrop_bounds
.status
= hb_bounds_t::EMPTY
;
258 case HB_PAINT_COMPOSITE_MODE_SRC
:
259 case HB_PAINT_COMPOSITE_MODE_SRC_OUT
:
260 backdrop_bounds
= src_bounds
;
262 case HB_PAINT_COMPOSITE_MODE_DEST
:
263 case HB_PAINT_COMPOSITE_MODE_DEST_OUT
:
265 case HB_PAINT_COMPOSITE_MODE_SRC_IN
:
266 case HB_PAINT_COMPOSITE_MODE_DEST_IN
:
267 backdrop_bounds
.intersect (src_bounds
);
270 backdrop_bounds
.union_ (src_bounds
);
277 const hb_bounds_t
&clip
= clips
.tail ();
278 hb_bounds_t
&group
= groups
.tail ();
284 hb_vector_t
<hb_transform_t
> transforms
;
285 hb_vector_t
<hb_bounds_t
> clips
;
286 hb_vector_t
<hb_bounds_t
> groups
;
289 HB_INTERNAL hb_paint_funcs_t
*
290 hb_paint_extents_get_funcs ();
293 #endif /* HB_PAINT_EXTENTS_HH */