1from __future__ import (
2    print_function, division, absolute_import, unicode_literals)
3
4from ufo2ft.filters import BaseFilter
5from cu2qu.ufo import DEFAULT_MAX_ERR, CURVE_TYPE_LIB_KEY
6from cu2qu.pens import Cu2QuPointPen
7
8import logging
9
10
11logger = logging.getLogger(__name__)
12
13
14class CubicToQuadraticFilter(BaseFilter):
15
16    _kwargs = {
17        'conversionError': None,
18        'reverseDirection': True,
19        'rememberCurveType': False,
20    }
21
22    def set_context(self, font, glyphSet):
23        ctx = super(CubicToQuadraticFilter, self).set_context(font, glyphSet)
24
25        relativeError = self.options.conversionError or DEFAULT_MAX_ERR
26        ctx.absoluteError = relativeError * font.info.unitsPerEm
27
28        ctx.stats = {}
29
30        return ctx
31
32    def __call__(self, font, glyphSet=None):
33        if self.options.rememberCurveType:
34            curve_type = font.lib.get(CURVE_TYPE_LIB_KEY, "cubic")
35            if curve_type == "quadratic":
36                logger.info("Curves already converted to quadratic")
37                return set()
38            elif curve_type == "cubic":
39                pass  # keep converting
40            else:
41                raise NotImplementedError(curve_type)
42
43        modified = super(CubicToQuadraticFilter, self).__call__(font, glyphSet)
44        if modified:
45            stats = self.context.stats
46            logger.info('New spline lengths: %s' % (', '.join(
47                '%s: %d' % (l, stats[l]) for l in sorted(stats.keys()))))
48
49        if self.options.rememberCurveType:
50            curve_type = font.lib.get(CURVE_TYPE_LIB_KEY, "cubic")
51            if curve_type != "quadratic":
52                font.lib[CURVE_TYPE_LIB_KEY] = "quadratic"
53
54        return modified
55
56    def filter(self, glyph):
57        if not len(glyph):
58            return False
59
60        pen = Cu2QuPointPen(
61            glyph.getPointPen(),
62            self.context.absoluteError,
63            reverse_direction=self.options.reverseDirection,
64            stats=self.context.stats)
65        contours = list(glyph)
66        glyph.clearContours()
67        for contour in contours:
68            contour.drawPoints(pen)
69        return True
70