2 * Copyright 2012 Google, Inc. All Rights Reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 * Google Author(s): Behdad Esfahbod, Maysum Panju, Wojciech Baranowski
23 // Glyphy is written using C style casts
24 #pragma GCC diagnostic push
25 #pragma GCC diagnostic ignored "-Wold-style-cast"
27 #include "glyphy-common.hh"
28 #include "glyphy-geometry.hh"
29 #include "glyphy-arcs-bezier.hh"
31 using namespace GLyphy::Geometry;
32 using namespace GLyphy::ArcsBezier;
37 * Approximate outlines with multiple arcs
41 struct glyphy_arc_accumulator_t {
42 unsigned int refcount;
46 glyphy_arc_endpoint_accumulator_callback_t callback;
49 glyphy_point_t start_point;
50 glyphy_point_t current_point;
52 unsigned int num_endpoints;
54 glyphy_bool_t success;
58 glyphy_arc_accumulator_t *
59 glyphy_arc_accumulator_create (void)
61 glyphy_arc_accumulator_t *acc = (glyphy_arc_accumulator_t *) calloc (1, sizeof (glyphy_arc_accumulator_t));
64 * In the original file, a pointer 'acc' returned from 'calloc' may be NULL, and it is dereferenced.
65 * To prevent Null Pointer Dereference, we add to check NULL value here.
71 acc->tolerance = 5e-4;
74 acc->user_data = NULL;
76 glyphy_arc_accumulator_reset (acc);
83 glyphy_arc_accumulator_reset (glyphy_arc_accumulator_t *acc)
85 acc->start_point = acc->current_point = Point (0, 0);
86 acc->need_moveto = true;
87 acc->num_endpoints = 0;
93 glyphy_arc_accumulator_destroy (glyphy_arc_accumulator_t *acc)
95 if (!acc || --acc->refcount)
104 glyphy_arc_accumulator_set_tolerance (glyphy_arc_accumulator_t *acc,
107 acc->tolerance = tolerance;
111 glyphy_arc_accumulator_get_tolerance (glyphy_arc_accumulator_t *acc)
113 return acc->tolerance;
117 glyphy_arc_accumulator_set_callback (glyphy_arc_accumulator_t *acc,
118 glyphy_arc_endpoint_accumulator_callback_t callback,
121 acc->callback = callback;
122 acc->user_data = user_data;
126 glyphy_arc_accumulator_get_callback (glyphy_arc_accumulator_t *acc,
127 glyphy_arc_endpoint_accumulator_callback_t *callback,
130 *callback = acc->callback;
131 *user_data = acc->user_data;
134 /* Accumulation results */
137 glyphy_arc_accumulator_get_error (glyphy_arc_accumulator_t *acc)
139 return acc->max_error;
143 glyphy_arc_accumulator_successful (glyphy_arc_accumulator_t *acc)
152 emit (glyphy_arc_accumulator_t *acc, const Point &p, double d)
154 glyphy_arc_endpoint_t endpoint = {p, d};
155 acc->success = acc->success && acc->callback (&endpoint, acc->user_data);
157 acc->num_endpoints++;
158 acc->current_point = p;
163 accumulate (glyphy_arc_accumulator_t *acc, const Point &p, double d)
165 if (Point (acc->current_point) == p)
167 if (d == GLYPHY_INFINITY) {
168 /* Emit moveto lazily, for cleaner outlines */
169 acc->need_moveto = true;
170 acc->current_point = p;
173 if (acc->need_moveto) {
174 emit (acc, acc->current_point, GLYPHY_INFINITY);
176 acc->start_point = acc->current_point;
177 acc->need_moveto = false;
184 move_to (glyphy_arc_accumulator_t *acc, const Point &p)
186 if (!acc->num_endpoints || p != acc->current_point)
187 accumulate (acc, p, GLYPHY_INFINITY);
191 arc_to (glyphy_arc_accumulator_t *acc, const Point &p1, double d)
193 accumulate (acc, p1, d);
197 bezier (glyphy_arc_accumulator_t *acc, const Bezier &b)
201 std::vector<Arc> arcs;
202 typedef ArcBezierApproximatorQuantizedDefault _ArcBezierApproximator;
203 _ArcBezierApproximator appx (GLYPHY_MAX_D, acc->d_bits);
204 ArcsBezierApproximatorSpringSystem<_ArcBezierApproximator>
205 ::approximate_bezier_with_arcs (b, acc->tolerance, appx, arcs, &e);
207 acc->max_error = std::max (acc->max_error, e);
210 for (unsigned int i = 0; i < arcs.size (); i++)
211 arc_to (acc, arcs[i].p1, arcs[i].d);
215 close_path (glyphy_arc_accumulator_t *acc)
217 if (!acc->need_moveto && Point (acc->current_point) != Point (acc->start_point))
218 arc_to (acc, acc->start_point, 0);
222 glyphy_arc_accumulator_move_to (glyphy_arc_accumulator_t *acc,
223 const glyphy_point_t *p0)
229 glyphy_arc_accumulator_line_to (glyphy_arc_accumulator_t *acc,
230 const glyphy_point_t *p1)
232 arc_to (acc, *p1, 0);
236 glyphy_arc_accumulator_conic_to (glyphy_arc_accumulator_t *acc,
237 const glyphy_point_t *p1,
238 const glyphy_point_t *p2)
240 bezier (acc, Bezier (acc->current_point,
241 Point (acc->current_point).lerp (2/3., *p1),
242 Point (*p2).lerp (2/3., *p1),
247 glyphy_arc_accumulator_cubic_to (glyphy_arc_accumulator_t *acc,
248 const glyphy_point_t *p1,
249 const glyphy_point_t *p2,
250 const glyphy_point_t *p3)
252 bezier (acc, Bezier (acc->current_point, *p1, *p2, *p3));
256 glyphy_arc_accumulator_arc_to (glyphy_arc_accumulator_t *acc,
257 const glyphy_point_t *p1,
260 arc_to (acc, *p1, d);
264 glyphy_arc_accumulator_close_path (glyphy_arc_accumulator_t *acc)
272 * Outline extents from arc list
277 glyphy_arc_list_extents (const glyphy_arc_endpoint_t *endpoints,
278 unsigned int num_endpoints,
279 glyphy_extents_t *extents)
282 glyphy_extents_clear (extents);
283 for (unsigned int i = 0; i < num_endpoints; i++) {
284 const glyphy_arc_endpoint_t &endpoint = endpoints[i];
285 if (endpoint.d == GLYPHY_INFINITY) {
289 Arc arc (p0, endpoint.p, endpoint.d);
292 glyphy_extents_t arc_extents;
293 arc.extents (arc_extents);
294 glyphy_extents_extend (extents, &arc_extents);
298 #pragma GCC diagnostic pop