def text(self, text, x, y, width, height, color, font):
        """
        See the Processing function text():
        https://processing.org/reference/text_.html

        Consider using Pango in addition to Cairo here.
        """
        # Helper function.
        def chop(word):
            """
            Take a word longer than the bounding box's width and chop off as many
            letters in the beginning as fit, followed by an ellipsis.
            """
            total_str = ""
            for c in word:
                _, _, total_width, _, _, _ = self.context.text_extents(total_str + c + "…")
                if total_width >= width:
                    return total_str + "…"
                total_str += c
            assert not "Should not be here, else 'word' fit into the bounding box"
        # Prepare the context for text rendering.
        self.context.set_source_rgb(*color)
        font_name, (font_size, font_slant, font_weight) = (font)
        self.context.select_font_face(font_name, font_slant, font_weight)
        self.context.set_font_size(font_size)
        self.context.set_antialias(cairo.ANTIALIAS_DEFAULT)
        # Get some font metrics.
        font_asc, _, font_height, _, _ = self.context.font_extents()
        # Initialize text cursor to the baseline of the font.
        width, height = self.tx(width), self.ty(height)
        w_x, w_y = self.tx(x), font_asc + self.ty(y)
        # Draw the text one line at a time and ensure the bounding box.
        line = ""
        nlines = 1
        for word in text.split(" "):
            _, _, line_width, _, _, _ = self.context.text_extents(_join(line, word))
            if line_width < width:
                line = _join(line, word)
            else:
                if not line:
                    # First word of the line extends beyond the line: chop and done.
                    self.context.move_to(w_x, w_y)
                    self.context.show_text(chop(word))
                    return nlines, font_height
                else:
                    # Filled a line, render it, and move on to the next line.
                    self.context.move_to(w_x, w_y)
                    self.context.show_text(line)
                    line = word
                    w_y += font_height

                    if w_y > height:
                        return nlines, font_height
                    nlines += 1
        self.context.move_to(w_x, w_y)
        self.context.show_text(line)
        return nlines, font_height
def text ( self , text , x , y , width , height , color , font ) : def chop ( word ) : total_str = "" for c in word : _ , _ , total_width , _ , _ , _ = self . context . text_extents ( total_str + c + "…" ) if total_width >= width : return total_str + "…" total_str += c assert not "Should not be here, else 'word' fit into the bounding box" self . context . set_source_rgb ( * color ) font_name , ( font_size , font_slant , font_weight ) = ( font ) self . context . select_font_face ( font_name , font_slant , font_weight ) self . context . set_font_size ( font_size ) self . context . set_antialias ( cairo . ANTIALIAS_DEFAULT ) font_asc , _ , font_height , _ , _ = self . context . font_extents ( ) width , height = self . tx ( width ) , self . ty ( height ) w_x , w_y = self . tx ( x ) , font_asc + self . ty ( y ) line = "" nlines = 1 for word in text . split ( " " ) : _ , _ , line_width , _ , _ , _ = self . context . text_extents ( _join ( line , word ) ) if line_width < width : line = _join ( line , word ) else : if not line : self . context . move_to ( w_x , w_y ) self . context . show_text ( chop ( word ) ) return nlines , font_height else : self . context . move_to ( w_x , w_y ) self . context . show_text ( line ) line = word w_y += font_height if w_y > height : return nlines , font_height nlines += 1 self . context . move_to ( w_x , w_y ) self . context . show_text ( line ) return nlines , font_height
See the Processing function text():
        https://processing.org/reference/text_.html

        Consider using Pango in addition to Cairo here.