Repository: ManimCommunity/manim

Issue:
Render MarkupText colors using <span> tags
Currently, coloring uses `<color>` tags which are Manim-specific (unsupported by Pango), and were a workaround for lack of color parsing in the SVG engine. Now that SVG parsing for fill and color has improved (#915), MarkupText can pass a foreground color to Pango, and Pango's "official" coloring tag, `<span foreground="#rrggbb">`, can be used.

As discussed later in #915, there are two parts:
1. Passing in the fill color (which fill color?) to Pango as the `AttrForeground` attribute.
2. Removing the `init_colors` override for MarkupText objects.

cc @PhilippImhof 



Discussion:
So now I have changed `MarkupText` in the following ways:

* pass `f'<span foreground="{self.color}">{self.text}</span>'` instead of just `self.text` to Pango in order to set the default color for all chars
* completely remove `def init_colors(...)` 

The SVG file is correctly created, e.g. all chars that are not in a particular `<span foreground="...">` are set in the default color (white in my case) and custom coloring of individual chars is correctly applied (gray background added manually just to make the white chars visible):
![image](https://user-images.githubusercontent.com/52650214/108620947-d291fd80-742f-11eb-91ab-5ca55da2147a.png)

However, the text does not appear in the animation:
![image](https://user-images.githubusercontent.com/52650214/108620959-e9d0eb00-742f-11eb-962f-a571ca22b041.png)



This is with the latest commits from PR #915. Is there still something on the SVG end that has to be changed?

Resolving patch:
diff --git a/manim/mobject/svg/style_utils.py b/manim/mobject/svg/style_utils.py
--- a/manim/mobject/svg/style_utils.py
+++ b/manim/mobject/svg/style_utils.py
@@ -9,15 +9,26 @@
 
 from typing import Dict, List
 
-SUPPORTED_STYLING_ATTRIBUTES: List[str] = [
+
+CASCADING_STYLING_ATTRIBUTES: List[str] = [
     "fill",
     "stroke",
-    "style",
     "fill-opacity",
     "stroke-opacity",
 ]
 
 
+# The default styling specifications for SVG images,
+# according to https://www.w3.org/TR/SVG/painting.html
+# (ctrl-F for "initial")
+SVG_DEFAULT_ATTRIBUTES: Dict[str, str] = {
+    "fill": "black",
+    "fill-opacity": "1",
+    "stroke": "none",
+    "stroke-opacity": "1",
+}
+
+
 def cascade_element_style(
     element: MinidomElement, inherited: Dict[str, str]
 ) -> Dict[str, str]:
@@ -46,11 +57,29 @@ def cascade_element_style(
 
     style = inherited.copy()
 
-    for attr in SUPPORTED_STYLING_ATTRIBUTES:
+    # cascade the regular elements.
+    for attr in CASCADING_STYLING_ATTRIBUTES:
         entry = element.getAttribute(attr)
         if entry:
             style[attr] = entry
 
+    # the style attribute should be handled separately in order to
+    # break it up nicely. furthermore, style takes priority over other
+    # attributes in the same element.
+    style_specs = element.getAttribute("style")
+    if style_specs:
+        for style_spec in style_specs.split(";"):
+            try:
+                key, value = style_spec.split(":")
+            except ValueError as e:
+                if not style_spec:
+                    # there was just a stray semicolon at the end, producing an emptystring
+                    pass
+                else:
+                    raise e
+            else:
+                style[key] = value
+
     return style
 
 
@@ -91,6 +120,26 @@ def parse_color_string(color_spec: str) -> str:
     return hex_color
 
 
+def fill_default_values(svg_style: Dict) -> None:
+    """
+    Fill in the default values for properties of SVG elements,
+    if they are not currently set in the style dictionary.
+
+    Parameters
+    ----------
+    svg_style : :class:`dict`
+        Style dictionary with SVG property names. Some may be missing.
+
+    Returns
+    -------
+    :class:`dict`
+        Style attributes; none are missing.
+    """
+    for key in SVG_DEFAULT_ATTRIBUTES:
+        if key not in svg_style:
+            svg_style[key] = SVG_DEFAULT_ATTRIBUTES[key]
+
+
 def parse_style(svg_style: Dict[str, str]) -> Dict:
     """Convert a dictionary of SVG attributes to Manim VMobject keyword arguments.
 
@@ -106,22 +155,7 @@ def parse_style(svg_style: Dict[str, str]) -> Dict:
     """
 
     manim_style = {}
-
-    # style attributes trump other element-level attributes,
-    # see https://www.w3.org/TR/SVG11/styling.html section 6.4, search "priority"
-    # so overwrite the other attribute dictionary values.
-    if "style" in svg_style:
-        for style_spec in svg_style["style"].split(";"):
-            try:
-                key, value = style_spec.split(":")
-            except ValueError as e:
-                if not style_spec:
-                    # there was just a stray semicolon at the end, producing an emptystring
-                    pass
-                else:
-                    raise e
-            else:
-                svg_style[key] = value
+    fill_default_values(svg_style)
 
     if "fill-opacity" in svg_style:
         manim_style["fill_opacity"] = float(svg_style["fill-opacity"])
@@ -138,7 +172,12 @@ def parse_style(svg_style: Dict[str, str]) -> Dict:
 
     if "stroke" in svg_style:
         if svg_style["stroke"] == "none":
-            manim_style["stroke_opacity"] = 0
+            # In order to not break animations.creation.Write,
+            # we interpret no stroke as stroke-width of zero and
+            # color the same as the fill color, if it exists.
+            manim_style["stroke_width"] = 0
+            if "fill_color" in manim_style:
+                manim_style["stroke_color"] = manim_style["fill_color"]
         else:
             manim_style["stroke_color"] = parse_color_string(svg_style["stroke"])
 
diff --git a/manim/mobject/svg/svg_mobject.py b/manim/mobject/svg/svg_mobject.py
--- a/manim/mobject/svg/svg_mobject.py
+++ b/manim/mobject/svg/svg_mobject.py
@@ -77,7 +77,7 @@ def __init__(
         fill_opacity=1.0,
         **kwargs,
     ):
-        self.def_id_to_mobject = {}
+        self.def_map = {}
         self.file_name = file_name or self.file_name
         self.ensure_valid_file()
         self.should_center = should_center
@@ -125,17 +125,7 @@ def generate_points(self):
         """
         doc = minidom_parse(self.file_path)
         for svg in doc.getElementsByTagName("svg"):
-            mobjects = self.get_mobjects_from(
-                svg,
-                # these are the default styling specifications for SVG images,
-                # according to https://www.w3.org/TR/SVG/painting.html, ctrl-F for "initial"
-                {
-                    "fill": "black",
-                    "fill-opacity": "1",
-                    "stroke": "none",
-                    "stroke-opacity": "1",
-                },
-            )
+            mobjects = self.get_mobjects_from(svg, {})
             if self.unpack_groups:
                 self.add(*mobjects)
             else:
@@ -182,7 +172,9 @@ def get_mobjects_from(
         elif element.tagName in ["g", "svg", "symbol", "defs"]:
             result += it.chain(
                 *[
-                    self.get_mobjects_from(child, style, within_defs or is_defs)
+                    self.get_mobjects_from(
+                        child, style, within_defs=within_defs or is_defs
+                    )
                     for child in element.childNodes
                 ]
             )
@@ -191,8 +183,8 @@ def get_mobjects_from(
             if temp != "":
                 result.append(self.path_string_to_mobject(temp, style))
         elif element.tagName == "use":
-            # note, style is not passed down to "use" elements
-            result += self.use_to_mobjects(element)
+            # note, style is calcuated in a different way for `use` elements.
+            result += self.use_to_mobjects(element, style)
         elif element.tagName == "rect":
             result.append(self.rect_to_mobject(element, style))
         elif element.tagName == "circle":
@@ -210,7 +202,9 @@ def get_mobjects_from(
             result = [VGroup(*result)]
 
         if within_defs and element.hasAttribute("id"):
-            self.def_id_to_mobject[element.getAttribute("id")] = result
+            # it seems wasteful to throw away the actual element,
+            # but I'd like the parsing to be as similar as possible
+            self.def_map[element.getAttribute("id")] = (style, element)
         if is_defs:
             # defs shouldn't be part of the result tree, only the id dictionary.
             return []
@@ -235,7 +229,9 @@ def path_string_to_mobject(self, path_string: str, style: dict):
         """
         return SVGPathMobject(path_string, **parse_style(style))
 
-    def use_to_mobjects(self, use_element: MinidomElement) -> List[VMobject]:
+    def use_to_mobjects(
+        self, use_element: MinidomElement, local_style: Dict
+    ) -> List[VMobject]:
         """Converts a SVG <use> element to a collection of VMobjects.
 
         Parameters
@@ -244,22 +240,34 @@ def use_to_mobjects(self, use_element: MinidomElement) -> List[VMobject]:
             An SVG <use> element which represents nodes that should be
             duplicated elsewhere.
 
+        local_style : :class:`Dict`
+            The styling using SVG property names at the point the element is `<use>`d.
+            Not all values are applied; styles defined when the element is specified in
+            the `<def>` tag cannot be overriden here.
+
         Returns
         -------
         List[VMobject]
-            A collection of VMobjects that are copies of the defined objects
+            A collection of VMobjects that are a copy of the defined object
         """
 
         # Remove initial "#" character
         ref = use_element.getAttribute("xlink:href")[1:]
 
         try:
-            return [i.copy() for i in self.def_id_to_mobject[ref]]
+            def_style, def_element = self.def_map[ref]
         except KeyError:
             warning_text = f"{self.file_name} contains a reference to id #{ref}, which is not recognized"
             warnings.warn(warning_text)
             return []
 
+        # In short, the def-ed style overrides the new style,
+        # in cases when the def-ed styled is defined.
+        style = local_style.copy()
+        style.update(def_style)
+
+        return self.get_mobjects_from(def_element, style)
+
     def attribute_to_float(self, attr):
         """A helper method which converts the attribute to float.
 
@@ -385,20 +393,21 @@ def rect_to_mobject(self, rect_element: MinidomElement, style: dict):
 
         corner_radius = float(corner_radius)
 
+        parsed_style = parse_style(style)
+        parsed_style["stroke_width"] = stroke_width
+
         if corner_radius == 0:
             mob = Rectangle(
                 width=self.attribute_to_float(rect_element.getAttribute("width")),
                 height=self.attribute_to_float(rect_element.getAttribute("height")),
-                stroke_width=stroke_width,
-                **parse_style(style),
+                **parsed_style,
             )
         else:
             mob = RoundedRectangle(
                 width=self.attribute_to_float(rect_element.getAttribute("width")),
                 height=self.attribute_to_float(rect_element.getAttribute("height")),
-                stroke_width=stroke_width,
                 corner_radius=corner_radius,
-                **parse_style(style),
+                **parsed_style,
             )
 
         mob.shift(mob.get_center() - mob.get_corner(UP + LEFT))
diff --git a/manim/mobject/svg/text_mobject.py b/manim/mobject/svg/text_mobject.py
--- a/manim/mobject/svg/text_mobject.py
+++ b/manim/mobject/svg/text_mobject.py
@@ -979,28 +979,39 @@ class MarkupText(SVGMobject):
     - ``<tt>typewriter font</tt>``
     - ``<big>bigger font</big>`` and ``<small>smaller font</small>``
     - ``<sup>superscript</sup>`` and ``<sub>subscript</sub>``
-    - ``<span underline="double">double underline</span>``
+    - ``<span underline="double" underline_color="green">double underline</span>``
     - ``<span underline="error">error underline</span>``
+    - ``<span overline="single" overline_color="green">overline</span>``
+    - ``<span strikethrough="true" strikethrough_color="red">strikethrough</span>``
     - ``<span font_family="sans">temporary change of font</span>``
-    - ``<color col="RED">temporary change of color</color>``; colors can be specified as Manim constants like ``RED`` or ``YELLOW`` or as hex triples like ``#aabbaa``
-    - ``<gradient from="YELLOW" to="RED">temporary gradient</gradient>``; colors specified as above
+    - ``<span foreground="red">temporary change of color</span>``
+    - ``<span fgcolor="red">temporary change of color</span>``
+    - ``<gradient from="YELLOW" to="RED">temporary gradient</gradient>``
+
+    For ``<span>`` markup, colors can be specified either as hex triples like ``#aabbcc`` or as named CSS colors like ``AliceBlue``.
+    The ``<gradient>`` tag being handled by Manim rather than Pango, supports hex triplets or Manim constants like ``RED`` or ``RED_A``.
+    If you want to use Manim constants like ``RED_A`` together with ``<span>``,
+    you will need to use Python's f-String syntax as follows:
+    ``f'<span foreground="{RED_A}">here you go</span>'``
 
     If your text contains ligatures, the :class:`MarkupText` class may incorrectly determine
-    the first and last letter to be colored. This is due to the fact that e.g. ``fl``
+    the first and last letter when creating the gradient. This is due to the fact that e.g. ``fl``
     are two characters, but might be set as one single glyph, a ligature. If your language does
-    not depend on ligatures, consider setting ``disable_ligatures=True``. If you cannot
-    or do not want to do without ligatures, the ``gradient`` and ``color`` tag support
-    an optional attribute ``offset`` which can be used to compensate for that error.
-    Usage is as follows:
+    not depend on ligatures, consider setting ``disable_ligatures=True``. If you cannot or do
+    not want to do without ligatures, the ``gradient`` tag supports an optional attribute ``offset``
+    which can be used to compensate for that error. Usage is as follows:
 
-    - ``<color col="RED" offset="1">red text</color>`` to *start* coloring one letter earlier
-    - ``<color col="RED" offset=",1">red text</color>`` to *end* coloring one letter earlier
-    - ``<color col="RED" offset="2,1">red text</color>`` to *start* coloring two letters earlier and *end* one letter earlier
+    - ``<gradient from="RED" to="YELLOW" offset="1">example</gradient>`` to *start* the gradient one letter earlier
+    - ``<gradient from="RED" to="YELLOW" offset=",1">example</gradient>`` to *end* the gradient one letter earlier
+    - ``<gradient from="RED" to="YELLOW" offset="2,1">example</gradient>`` to *start* the gradient two letters earlier and *end* it one letter earlier
 
     Specifying a second offset may be necessary if the text to be colored does
     itself contain ligatures. The same can happen when using HTML entities for
     special chars.
 
+    When using ``underline``, ``overline`` or ``strikethrough`` together with ``<gradient>`` tags, you will also need to use the offset, because
+    underlines are additional paths in the final :class:`SVGMobject`, check out the corresponding example.
+
     Escaping of special characters: ``>`` *should* be written as ``&gt;`` whereas ``<`` and
     ``&`` *must* be written as ``&lt;`` and ``&amp;``.
 
@@ -1008,7 +1019,7 @@ class MarkupText(SVGMobject):
     corresponding documentation page:
     `Pango Markup <https://developer.gnome.org/pango/stable/pango-Markup.html>`_.
     Please be aware that not all features are supported by this class and that
-    the ``<color>`` and ``<gradient>`` tags mentioned above are not supported by Pango.
+    the ``<gradient>`` tag mentioned above is not supported by Pango.
 
     Parameters
     ----------
@@ -1063,7 +1074,7 @@ def construct(self):
         class ColorExample(Scene):
             def construct(self):
                 text1 = MarkupText(
-                    'all in red <color col="YELLOW">except this</color>', color=RED
+                    f'all in red <span fgcolor="{YELLOW}">except this</span>', color=RED
                 )
                 text2 = MarkupText("nice gradient", gradient=(BLUE, GREEN))
                 text3 = MarkupText(
@@ -1071,20 +1082,43 @@ def construct(self):
                     gradient=(BLUE, GREEN),
                 )
                 text4 = MarkupText(
-                    'fl ligature <color col="#00ff00">causing trouble</color> here'
+                    'fl ligature <gradient from="RED" to="YELLOW">causing trouble</gradient> here'
                 )
                 text5 = MarkupText(
-                    'fl ligature <color col="#00ff00" offset="1">defeated</color> with offset'
+                    'fl ligature <gradient from="RED" to="YELLOW" offset="1">defeated</gradient> with offset'
                 )
                 text6 = MarkupText(
-                    'fl ligature <color col="GREEN" offset="1">floating</color> inside'
+                    'fl ligature <gradient from="RED" to="YELLOW" offset="1">floating</gradient> inside'
                 )
                 text7 = MarkupText(
-                    'fl ligature <color col="GREEN" offset="1,1">floating</color> inside'
+                    'fl ligature <gradient from="RED" to="YELLOW" offset="1,1">floating</gradient> inside'
                 )
                 group = VGroup(text1, text2, text3, text4, text5, text6, text7).arrange(DOWN)
                 self.add(group)
 
+    .. manim:: UnderlineExample
+        :save_last_frame:
+
+        class UnderlineExample(Scene):
+            def construct(self):
+                text1 = MarkupText(
+                    '<span underline="double" underline_color="green">bla</span>'
+                )
+                text2 = MarkupText(
+                    '<span underline="single" underline_color="green">xxx</span><gradient from="#ffff00" to="RED">aabb</gradient>y'
+                )
+                text3 = MarkupText(
+                    '<span underline="single" underline_color="green">xxx</span><gradient from="#ffff00" to="RED" offset="-1">aabb</gradient>y'
+                )
+                text4 = MarkupText(
+                    '<span underline="double" underline_color="green">xxx</span><gradient from="#ffff00" to="RED">aabb</gradient>y'
+                )
+                text5 = MarkupText(
+                    '<span underline="double" underline_color="green">xxx</span><gradient from="#ffff00" to="RED" offset="-2">aabb</gradient>y'
+                )
+                group = VGroup(text1, text2, text3, text4, text5).arrange(DOWN)
+                self.add(group)
+
     .. manim:: FontExample
         :save_last_frame:
 
@@ -1106,7 +1140,7 @@ def construct(self):
 
         class NewlineExample(Scene):
             def construct(self):
-                text = MarkupText('foooo<color col="RED">oo\nbaa</color>aar')
+                text = MarkupText('foooo<span foreground="red">oo\nbaa</span>aar')
                 self.add(text)
 
     .. manim:: NoLigaturesExample
@@ -1114,8 +1148,8 @@ def construct(self):
 
         class NoLigaturesExample(Scene):
             def construct(self):
-                text1 = MarkupText('fl<color col="RED">oat</color>ing')
-                text2 = MarkupText('fl<color col="RED">oat</color>ing', disable_ligatures=True)
+                text1 = MarkupText('fl<gradient from="RED" to="GREEN">oat</gradient>ing')
+                text2 = MarkupText('fl<gradient from="RED" to="GREEN">oat</gradient>ing', disable_ligatures=True)
                 group = VGroup(text1, text2).arrange(DOWN)
                 self.add(group)
 
@@ -1130,7 +1164,7 @@ class MultiLanguage(Scene):
             def construct(self):
                 morning = MarkupText("வணக்கம்", font="sans-serif")
                 chin = MarkupText(
-                    '見 角 言 谷  辛 <color col="BLUE">辰 辵 邑</color> 酉 釆 里!'
+                    '見 角 言 谷  辛 <span fgcolor="blue">辰 辵 邑</span> 酉 釆 里!'
                 )  # works as in ``Text``.
                 mess = MarkupText("Multi-Language", style=BOLD)
                 russ = MarkupText("Здравствуйте मस नम म ", font="sans-serif")
@@ -1171,6 +1205,7 @@ def __init__(
         **kwargs,
     ):
         self.text = text
+        self.color = color
         self.size = size
         self.line_spacing = line_spacing
         self.font = font
@@ -1186,6 +1221,10 @@ def __init__(
             text_without_tabs = text.replace("\t", " " * self.tab_width)
 
         colormap = self.extract_color_tags()
+        if len(colormap) > 0:
+            logger.warning(
+                f'Using <color> tags in MarkupText is deprecated. Please use <span foreground="..."> instead.'
+            )
         gradientmap = self.extract_gradient_tags()
 
         if not MarkupUtils.validate(self.text):
@@ -1205,7 +1244,6 @@ def __init__(
         SVGMobject.__init__(
             self,
             file_name,
-            color=color,
             fill_opacity=fill_opacity,
             stroke_width=stroke_width,
             height=height,
@@ -1260,7 +1298,7 @@ def __init__(
     def text2hash(self):
         """Generates ``sha256`` hash for file name."""
         settings = (
-            "MARKUPPANGO" + self.font + self.slant + self.weight
+            "MARKUPPANGO" + self.font + self.slant + self.weight + self.color
         )  # to differentiate from classical Pango Text
         settings += str(self.line_spacing) + str(self.size)
         settings += str(self.disable_ligatures)
@@ -1284,7 +1322,7 @@ def text2svg(self):
 
         logger.debug(f"Setting Text {self.text}")
         return MarkupUtils.text2svg(
-            self.text,
+            f'<span foreground="{self.color}">{self.text}</span>',
             self.font,
             self.slant,
             self.weight,
@@ -1360,6 +1398,9 @@ def extract_color_tags(self):
         with a custom color.
 
         Removes the ``<color>`` tag, as it is not part of Pango's markup and would cause an error.
+
+        Note: Using the ``<color>`` tags is deprecated. As soon as the legacy syntax is gone, this function
+        will be removed.
         """
         tags = re.finditer(
             '<color\s+col="([^"]+)"(\s+offset="([^"]+)")?>(.+?)</color>',
@@ -1387,9 +1428,6 @@ def extract_color_tags(self):
         self.text = re.sub("<color[^>]+>(.+?)</color>", r"\1", self.text, 0, re.S)
         return colormap
 
-    def init_colors(self, propagate_colors=True):
-        SVGMobject.init_colors(self, propagate_colors=propagate_colors)
-
     def __repr__(self):
         return f"MarkupText({repr(self.original_text)})"
 


Test patch:
diff --git a/tests/control_data/graphical_units_data/img_and_svg/UseTagInheritanceTest.npz b/tests/control_data/graphical_units_data/img_and_svg/UseTagInheritanceTest.npz
new file mode 100644
Binary files /dev/null and b/tests/control_data/graphical_units_data/img_and_svg/UseTagInheritanceTest.npz differ
diff --git a/tests/test_graphical_units/img_svg_resources/aabbb.svg b/tests/test_graphical_units/img_svg_resources/aabbb.svg
new file mode 100644
--- /dev/null
+++ b/tests/test_graphical_units/img_svg_resources/aabbb.svg
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="600pt" height="400pt" viewBox="0 0 600 400" version="1.1">
+<defs>
+<g>
+<symbol overflow="visible" id="glyph0-0">
+<path style="stroke:none;" d="M 0.65625 2.359375 L 0.65625 -9.390625 L 7.328125 -9.390625 L 7.328125 2.359375 Z M 1.40625 1.609375 L 6.59375 1.609375 L 6.59375 -8.65625 L 1.40625 -8.65625 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-1">
+<path style="stroke:none;" d="M 5.296875 -2.171875 L 5.296875 -3.640625 L 3.765625 -3.640625 C 3.171875 -3.640625 2.726562 -3.507812 2.4375 -3.25 C 2.144531 -3 2 -2.609375 2 -2.078125 C 2 -1.597656 2.144531 -1.210938 2.4375 -0.921875 C 2.738281 -0.640625 3.140625 -0.5 3.640625 -0.5 C 4.140625 -0.5 4.539062 -0.65625 4.84375 -0.96875 C 5.144531 -1.28125 5.296875 -1.679688 5.296875 -2.171875 Z M 6.5 -4.328125 L 6.5 -0.6875 L 7.5625 -0.6875 L 7.5625 0 L 5.296875 0 L 5.296875 -0.75 C 5.035156 -0.425781 4.726562 -0.1875 4.375 -0.03125 C 4.03125 0.113281 3.628906 0.1875 3.171875 0.1875 C 2.398438 0.1875 1.785156 -0.015625 1.328125 -0.421875 C 0.878906 -0.828125 0.65625 -1.378906 0.65625 -2.078125 C 0.65625 -2.796875 0.914062 -3.347656 1.4375 -3.734375 C 1.957031 -4.128906 2.6875 -4.328125 3.625 -4.328125 L 5.296875 -4.328125 L 5.296875 -4.8125 C 5.296875 -5.332031 5.132812 -5.738281 4.8125 -6.03125 C 4.5 -6.320312 4.054688 -6.46875 3.484375 -6.46875 C 3.003906 -6.46875 2.625 -6.359375 2.34375 -6.140625 C 2.0625 -5.921875 1.882812 -5.597656 1.8125 -5.171875 L 1.203125 -5.171875 L 1.203125 -6.578125 C 1.617188 -6.753906 2.019531 -6.882812 2.40625 -6.96875 C 2.800781 -7.0625 3.1875 -7.109375 3.5625 -7.109375 C 4.519531 -7.109375 5.25 -6.867188 5.75 -6.390625 C 6.25 -5.921875 6.5 -5.234375 6.5 -4.328125 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-2">
+<path style="stroke:none;" d="M 1.53125 -0.6875 L 1.53125 -9.4375 L 0.390625 -9.4375 L 0.390625 -10.125 L 2.734375 -10.125 L 2.734375 -5.84375 C 2.960938 -6.269531 3.257812 -6.585938 3.625 -6.796875 C 3.988281 -7.003906 4.4375 -7.109375 4.96875 -7.109375 C 5.820312 -7.109375 6.515625 -6.769531 7.046875 -6.09375 C 7.585938 -5.425781 7.859375 -4.550781 7.859375 -3.46875 C 7.859375 -2.375 7.585938 -1.488281 7.046875 -0.8125 C 6.515625 -0.144531 5.820312 0.1875 4.96875 0.1875 C 4.4375 0.1875 3.988281 0.0859375 3.625 -0.109375 C 3.257812 -0.316406 2.960938 -0.640625 2.734375 -1.078125 L 2.734375 0 L 0.390625 0 L 0.390625 -0.6875 Z M 2.734375 -3.125 C 2.734375 -2.289062 2.890625 -1.65625 3.203125 -1.21875 C 3.523438 -0.78125 3.988281 -0.5625 4.59375 -0.5625 C 5.207031 -0.5625 5.671875 -0.804688 5.984375 -1.296875 C 6.304688 -1.785156 6.46875 -2.507812 6.46875 -3.46875 C 6.46875 -4.425781 6.304688 -5.144531 5.984375 -5.625 C 5.671875 -6.113281 5.207031 -6.359375 4.59375 -6.359375 C 3.988281 -6.359375 3.523438 -6.140625 3.203125 -5.703125 C 2.890625 -5.265625 2.734375 -4.628906 2.734375 -3.796875 Z "/>
+</symbol>
+<symbol overflow="visible" id="glyph0-3">
+<path style="stroke:none;fill:#1529b2" d="M 1.53125 -0.6875 L 1.53125 -9.4375 L 0.390625 -9.4375 L 0.390625 -10.125 L 2.734375 -10.125 L 2.734375 -5.84375 C 2.960938 -6.269531 3.257812 -6.585938 3.625 -6.796875 C 3.988281 -7.003906 4.4375 -7.109375 4.96875 -7.109375 C 5.820312 -7.109375 6.515625 -6.769531 7.046875 -6.09375 C 7.585938 -5.425781 7.859375 -4.550781 7.859375 -3.46875 C 7.859375 -2.375 7.585938 -1.488281 7.046875 -0.8125 C 6.515625 -0.144531 5.820312 0.1875 4.96875 0.1875 C 4.4375 0.1875 3.988281 0.0859375 3.625 -0.109375 C 3.257812 -0.316406 2.960938 -0.640625 2.734375 -1.078125 L 2.734375 0 L 0.390625 0 L 0.390625 -0.6875 Z M 2.734375 -3.125 C 2.734375 -2.289062 2.890625 -1.65625 3.203125 -1.21875 C 3.523438 -0.78125 3.988281 -0.5625 4.59375 -0.5625 C 5.207031 -0.5625 5.671875 -0.804688 5.984375 -1.296875 C 6.304688 -1.785156 6.46875 -2.507812 6.46875 -3.46875 C 6.46875 -4.425781 6.304688 -5.144531 5.984375 -5.625 C 5.671875 -6.113281 5.207031 -6.359375 4.59375 -6.359375 C 3.988281 -6.359375 3.523438 -6.140625 3.203125 -5.703125 C 2.890625 -5.265625 2.734375 -4.628906 2.734375 -3.796875 Z "/>
+</symbol>
+</g>
+</defs>
+<g id="surface1">
+<g style="fill:rgb(100%,100%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-1" x="30" y="32.375977"/>
+  <use xlink:href="#glyph0-1" x="38" y="32.375977"/>
+</g>
+<g style="fill:rgb(0%,50.196078%,0%);fill-opacity:1;">
+  <use xlink:href="#glyph0-2" x="46" y="32.375977" style="fill:rgb(50%,0%,0%)"/>
+  <use xlink:href="#glyph0-2" x="55" y="32.375977"/>
+  <use xlink:href="#glyph0-2" x="64" y="32.375977"/>
+  <use xlink:href="#glyph0-3" x="73" y="32.375977"/>
+  <use xlink:href="#glyph0-3" x="82" y="32.375977" style="fill:#ffffff"/>
+</g>
+</g>
+</svg>
diff --git a/tests/test_graphical_units/test_img_and_svg.py b/tests/test_graphical_units/test_img_and_svg.py
--- a/tests/test_graphical_units/test_img_and_svg.py
+++ b/tests/test_graphical_units/test_img_and_svg.py
@@ -85,6 +85,13 @@ def construct(self):
         self.wait()
 
 
+class UseTagInheritanceTest(Scene):
+    def construct(self):
+        aabbb = SVGMobject(get_test_resource("aabbb.svg"))
+        self.add(aabbb)
+        self.wait()
+
+
 # Second are the visual tests - these are probably too complex to verify step-by-step, so
 # these are really more of a spot-check