def _apply_gradient_common_parts( gradient: etree.Element, paint: _GradientPaint, transform: Affine2D = Affine2D.identity(), ): gradient.attrib["gradientUnits"] = "userSpaceOnUse" for stop in paint.stops: stop_el = etree.SubElement(gradient, "stop") stop_el.attrib["offset"] = _ntos(stop.stopOffset) stop_el.attrib["stop-color"] = stop.color.opaque().to_string() if stop.color.alpha != 1.0: stop_el.attrib["stop-opacity"] = _ntos(stop.color.alpha) if paint.extend != Extend.PAD: gradient.attrib["spreadMethod"] = paint.extend.name.lower() transform = transform.round(_DEFAULT_ROUND_NDIGITS) if transform != Affine2D.identity(): # Safari has a bug which makes it reject a gradient if gradientTransform # contains an 'involutory matrix' (i.e. matrix whose inverse equals itself, # such that M @ M == Identity, e.g. reflection), hence the following hack: # https://github.com/googlefonts/nanoemoji/issues/268 # https://en.wikipedia.org/wiki/Involutory_matrix # TODO: Remove once the bug gets fixed if transform @ transform == Affine2D.identity(): transform = transform._replace(a=transform.a + 0.00001) assert transform.inverse() != transform gradient.attrib["gradientTransform"] = transform.tostring()
def _svg_matrix(transform: Affine2D) -> str: return transform.round(_DEFAULT_ROUND_NDIGITS).tostring()