Repository: ManimCommunity/manim

Issue:
Removing CairoText
It's long that Pango is working with no or very few bugs and it's time to remove `CairoText`. We have deprecated it long back and it should be fine to remove it in the next release. See https://github.com/ManimCommunity/manim/projects/9#card-56126541

## Additional comments
Marking it as a good first issue.



Discussion:
I can take this if it hasn't been addressed yet. I'm assuming this is referring to the `CairoText` class inside `manim.mobject.svg.text_mobject`?
Yes. I'm assigning you!

Resolving patch:
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
@@ -42,7 +42,7 @@ def construct(self):
 
 """
 
-__all__ = ["Text", "Paragraph", "CairoText", "MarkupText", "register_font"]
+__all__ = ["Text", "Paragraph", "MarkupText", "register_font"]
 
 
 import copy
@@ -104,307 +104,6 @@ def remove_invisible_chars(mobject):
     return mobject_without_dots
 
 
-class CairoText(SVGMobject):
-    """Display (non-LaTeX) text.
-
-    Text objects behave like a :class:`.VGroup`-like iterable of all characters
-    in the given text. In particular, slicing is possible.
-
-
-    Tests
-    -----
-
-    Check whether writing text works::
-
-        >>> Text('The horse does not eat cucumber salad.')
-        Text('The horse does not eat cucumber salad.')
-
-    """
-
-    def __init__(
-        self,
-        text,
-        # Mobject
-        color=WHITE,
-        height=None,
-        width=None,
-        fill_opacity=1,
-        stroke_width=0,
-        should_center=True,
-        unpack_groups=True,
-        # Text
-        font="",
-        gradient=None,
-        line_spacing=-1,
-        size=1,
-        slant: str = NORMAL,
-        weight: str = NORMAL,
-        t2c=None,
-        t2f=None,
-        t2g=None,
-        t2s=None,
-        t2w=None,
-        tab_width=4,
-        **kwargs,
-    ):
-        # self.full2short(config)
-        if t2c is None:
-            t2c = {}
-        if t2f is None:
-            t2f = {}
-        if t2g is None:
-            t2g = {}
-        if t2s is None:
-            t2s = {}
-        if t2w is None:
-            t2w = {}
-        # If long form arguments are present, they take precedence
-        t2c = kwargs.pop("text2color", t2c)
-        t2f = kwargs.pop("text2font", t2f)
-        t2g = kwargs.pop("text2gradient", t2g)
-        t2s = kwargs.pop("text2slant", t2s)
-        t2w = kwargs.pop("text2weight", t2w)
-        self.t2c = t2c
-        self.t2f = t2f
-        self.t2g = t2g
-        self.t2s = t2s
-        self.t2w = t2w
-        self.font = font
-        self.gradient = gradient
-        self.line_spacing = line_spacing
-        self.size = size
-        self.slant = slant
-        self.weight = weight
-        self.tab_width = tab_width
-        self.original_text = text
-        text_without_tabs = text
-        if text.find("\t") != -1:
-            text_without_tabs = text.replace("\t", " " * self.tab_width)
-        self.text = text_without_tabs
-        if self.line_spacing == -1:
-            self.line_spacing = self.size + self.size * 0.3
-        else:
-            self.line_spacing = self.size + self.size * self.line_spacing
-        file_name = self.text2svg()
-        PangoUtils.remove_last_M(file_name)
-        SVGMobject.__init__(
-            self,
-            file_name,
-            height=height,
-            width=width,
-            unpack_groups=unpack_groups,
-            color=color,
-            fill_opacity=fill_opacity,
-            stroke_width=stroke_width,
-            should_center=should_center,
-            **kwargs,
-        )
-        self.text = text
-        self.submobjects = [*self.gen_chars()]
-        self.chars = VGroup(*self.submobjects)
-        self.text = text_without_tabs.replace(" ", "").replace("\n", "")
-        nppc = self.n_points_per_cubic_curve
-        for each in self:
-            if len(each.points) == 0:
-                continue
-            points = each.points
-            last = points[0]
-            each.clear_points()
-            for index, point in enumerate(points):
-                each.append_points([point])
-                if (
-                    index != len(points) - 1
-                    and (index + 1) % nppc == 0
-                    and any(point != points[index + 1])
-                ):
-                    each.add_line_to(last)
-                    last = points[index + 1]
-            each.add_line_to(last)
-        if self.t2c:
-            self.set_color_by_t2c()
-        if self.gradient:
-            self.set_color_by_gradient(*self.gradient)
-        if self.t2g:
-            self.set_color_by_t2g()
-        # anti-aliasing
-        if height is None and width is None:
-            self.scale(TEXT_MOB_SCALE_FACTOR)
-
-    def __repr__(self):
-        return f"Text({repr(self.original_text)})"
-
-    def gen_chars(self):
-        chars = VGroup()
-        submobjects_char_index = 0
-        for char_index in range(self.text.__len__()):
-            if (
-                self.text[char_index] == " "
-                or self.text[char_index] == "\t"
-                or self.text[char_index] == "\n"
-            ):
-                space = Dot(radius=0, fill_opacity=0, stroke_opacity=0)
-                if char_index == 0:
-                    space.move_to(self.submobjects[submobjects_char_index].get_center())
-                else:
-                    space.move_to(
-                        self.submobjects[submobjects_char_index - 1].get_center()
-                    )
-                chars.add(space)
-            else:
-                chars.add(self.submobjects[submobjects_char_index])
-                submobjects_char_index += 1
-        return chars
-
-    def find_indexes(self, word, text):
-        m = re.match(r"\[([0-9\-]{0,}):([0-9\-]{0,})\]", word)
-        if m:
-            start = int(m.group(1)) if m.group(1) != "" else 0
-            end = int(m.group(2)) if m.group(2) != "" else len(text)
-            start = len(text) + start if start < 0 else start
-            end = len(text) + end if end < 0 else end
-            return [(start, end)]
-        indexes = []
-        index = text.find(word)
-        while index != -1:
-            indexes.append((index, index + len(word)))
-            index = text.find(word, index + len(word))
-        return indexes
-
-    # def full2short(self, config_args):
-    #     for kwargs in [config_args]:
-    #         if kwargs.__contains__("text2color"):
-    #             kwargs["t2c"] = kwargs.pop("text2color")
-    #         if kwargs.__contains__("text2font"):
-    #             kwargs["t2f"] = kwargs.pop("text2font")
-    #         if kwargs.__contains__("text2gradient"):
-    #             kwargs["t2g"] = kwargs.pop("text2gradient")
-    #         if kwargs.__contains__("text2slant"):
-    #             kwargs["t2s"] = kwargs.pop("text2slant")
-    #         if kwargs.__contains__("text2weight"):
-    #             kwargs["t2w"] = kwargs.pop("text2weight")
-
-    def set_color_by_t2c(self, t2c=None):
-        t2c = t2c if t2c else self.t2c
-        for word, color in list(t2c.items()):
-            for start, end in self.find_indexes(word, self.original_text):
-                self.chars[start:end].set_color(color)
-
-    def set_color_by_t2g(self, t2g=None):
-        t2g = t2g if t2g else self.t2g
-        for word, gradient in list(t2g.items()):
-            for start, end in self.find_indexes(word, self.original_text):
-                self.chars[start:end].set_color_by_gradient(*gradient)
-
-    def str2slant(self, string):
-        if string == NORMAL:
-            return cairo.FontSlant.NORMAL
-        if string == ITALIC:
-            return cairo.FontSlant.ITALIC
-        if string == OBLIQUE:
-            return cairo.FontSlant.OBLIQUE
-
-    def str2weight(self, string):
-        if string == NORMAL:
-            return cairo.FontWeight.NORMAL
-        if string == BOLD:
-            return cairo.FontWeight.BOLD
-
-    def text2hash(self):
-        settings = self.font + self.slant + self.weight
-        settings += str(self.t2f) + str(self.t2s) + str(self.t2w)
-        settings += str(self.line_spacing) + str(self.size)
-        id_str = self.text + settings
-        hasher = hashlib.sha256()
-        hasher.update(id_str.encode())
-        return hasher.hexdigest()[:16]
-
-    def text2settings(self):
-        settings = []
-        t2x = [self.t2f, self.t2s, self.t2w]
-        for i in range(len(t2x)):
-            fsw = [self.font, self.slant, self.weight]
-            if t2x[i]:
-                for word, x in list(t2x[i].items()):
-                    for start, end in self.find_indexes(word, self.text):
-                        fsw[i] = x
-                        settings.append(TextSetting(start, end, *fsw))
-        # Set All text settings(default font slant weight)
-        fsw = [self.font, self.slant, self.weight]
-        settings.sort(key=lambda setting: setting.start)
-        temp_settings = settings.copy()
-        start = 0
-        for setting in settings:
-            if setting.start != start:
-                temp_settings.append(TextSetting(start, setting.start, *fsw))
-            start = setting.end
-        if start != len(self.text):
-            temp_settings.append(TextSetting(start, len(self.text), *fsw))
-        settings = sorted(temp_settings, key=lambda setting: setting.start)
-
-        if re.search(r"\n", self.text):
-            line_num = 0
-            for start, end in self.find_indexes("\n", self.text):
-                for setting in settings:
-                    if setting.line_num == -1:
-                        setting.line_num = line_num
-                    if start < setting.end:
-                        line_num += 1
-                        new_setting = copy.copy(setting)
-                        setting.end = end
-                        new_setting.start = end
-                        new_setting.line_num = line_num
-                        settings.append(new_setting)
-                        settings.sort(key=lambda setting: setting.start)
-                        break
-        for setting in settings:
-            if setting.line_num == -1:
-                setting.line_num = 0
-        return settings
-
-    def text2svg(self):
-        # anti-aliasing
-        size = self.size * 10
-        line_spacing = self.line_spacing * 10
-
-        if self.font == "":
-            if NOT_SETTING_FONT_MSG:
-                logger.warning(NOT_SETTING_FONT_MSG)
-
-        dir_name = config.get_dir("text_dir")
-        if not os.path.exists(dir_name):
-            os.makedirs(dir_name)
-
-        hash_name = self.text2hash()
-        file_name = os.path.join(dir_name, hash_name) + ".svg"
-        if os.path.exists(file_name):
-            return file_name
-        surface = cairo.SVGSurface(file_name, 600, 400)
-        context = cairo.Context(surface)
-        context.set_font_size(size)
-        context.move_to(START_X, START_Y)
-
-        settings = self.text2settings()
-        offset_x = 0
-        last_line_num = 0
-        for setting in settings:
-            font = setting.font.decode("utf-8")
-            slant = self.str2slant(setting.slant)
-            weight = self.str2weight(setting.weight)
-            text = self.text[setting.start : setting.end].replace("\n", " ")
-
-            context.select_font_face(font, slant, weight)
-            if setting.line_num != last_line_num:
-                offset_x = 0
-                last_line_num = setting.line_num
-            context.move_to(
-                START_X + offset_x, START_Y + line_spacing * setting.line_num
-            )
-            context.show_text(text)
-            offset_x += context.text_extents(text)[4]
-        surface.finish()
-        return file_name
-
-
 class Paragraph(VGroup):
     r"""Display a paragraph of text.
 
@@ -1466,10 +1165,6 @@ def register_font(font_file: typing.Union[str, Path]):
     AttributeError:
         If this method is used on macOS.
 
-    Notes
-    -----
-    This method of adding font files also works with :class:`CairoText`.
-
     .. important ::
 
         This method is available for macOS for ``ManimPango>=v0.2.3``. Using this


Test patch: