def test_layout_iter_properties(): context = Context() layout = Layout(context) layout_iter = layout.get_iter() assert layout_iter.next_run() is False assert layout_iter.next_char() is False assert layout_iter.next_cluster() is False assert layout_iter.next_line() is False assert layout_iter.at_last_line() is True assert layout_iter.get_index() == 0 assert layout_iter.get_baseline() == 0 assert isinstance(layout_iter.get_char_extents(), Rectangle) cluster_ink, cluster_logical = layout_iter.get_cluster_extents() assert isinstance(cluster_ink, Rectangle) assert isinstance(cluster_logical, Rectangle) run_ink, run_logical = layout_iter.get_run_extents() assert isinstance(run_ink, Rectangle) assert isinstance(run_logical, Rectangle) y0, y1 = layout_iter.get_line_yrange() assert y0 == 0 assert y1 == 0 line_ink, line_logical = layout_iter.get_line_extents() assert isinstance(line_ink, Rectangle) assert isinstance(line_logical, Rectangle) layout_ink, layout_logical = layout_iter.get_layout_extents() assert isinstance(layout_ink, Rectangle) assert isinstance(layout_logical, Rectangle)
def test_glyph_item_iterator(self): text = 'Hi from Παν語' layout = Layout(self.pango_context) layout.set_text(text) layout_iter = layout.get_iter() glyph_item_iter = GlyphItemIter() assert isinstance(glyph_item_iter.get_pointer(), ffi.CData) assert glyph_item_iter.init_start( layout_iter.get_run(), text ) assert isinstance(glyph_item_iter.glyph_item, GlyphItem) assert glyph_item_iter.text == text # Verify first cluster assert glyph_item_iter.start_glyph == 0 assert glyph_item_iter.start_index == 0 assert glyph_item_iter.start_char == 0 assert glyph_item_iter.end_glyph == 1 assert glyph_item_iter.end_index == 1 assert glyph_item_iter.end_char == 1 assert not glyph_item_iter.prev_cluster() assert glyph_item_iter.next_cluster() # Verify second cluster assert glyph_item_iter.start_glyph == 1 assert glyph_item_iter.start_index == 1 assert glyph_item_iter.start_char == 1 assert glyph_item_iter.end_glyph == 2 assert glyph_item_iter.end_index == 2 assert glyph_item_iter.end_char == 2 assert glyph_item_iter.init_end( layout_iter.get_run(), text ) # Verify last cluster assert glyph_item_iter.start_glyph == 7 assert glyph_item_iter.start_index == 7 assert glyph_item_iter.start_char == 7 assert glyph_item_iter.end_glyph == 8 assert glyph_item_iter.end_index == 8 assert glyph_item_iter.end_char == 8 assert not glyph_item_iter.next_cluster() assert glyph_item_iter.prev_cluster() # Verify second to last cluster assert glyph_item_iter.start_glyph == 6 assert glyph_item_iter.start_index == 6 assert glyph_item_iter.start_char == 6 assert glyph_item_iter.end_glyph == 7 assert glyph_item_iter.end_index == 7 assert glyph_item_iter.end_char == 7
def test_layout_run_properties(self): layout = Layout(self.pango_context) layout.set_text('Hello World') layout_iter = layout.get_iter() layout_run = layout_iter.get_run() layout_run_item = layout_run.item assert isinstance(layout_run_item, Item)
def test_glyph_item_copies(self): text = 'Hi from Παν語' layout = Layout(self.pango_context) layout.set_text(text) layout_iter = layout.get_iter() layout_run = layout_iter.get_run() assert layout_run.copy().get_pointer() != layout_run.get_pointer()
def test_layout_run_from_pointer(self): layout = Layout(self.pango_context) layout.set_text('Hello World') layout_iter = layout.get_iter() layout_run = layout_iter.get_run() same_layout = LayoutRun.from_pointer(layout_run.get_pointer()) assert isinstance(same_layout, LayoutRun)
def test_glyph_item_get_logical_widths(self): text = 'Hi from Παν語' layout = Layout(self.pango_context) layout.set_text(text) layout_iter = layout.get_iter() layout_run = layout_iter.get_run() logical_widths = layout_run.get_logical_widths(text) assert len(logical_widths) == 8 assert isinstance(logical_widths[0], int)
def test_layout_iter_pointer(self): layout = Layout(self.pango_context) layout_iter = layout.get_iter() assert isinstance(layout_iter, LayoutIter) assert isinstance(layout_iter.get_pointer(), ffi.CData) pointer_shallow_copy = layout_iter.get_pointer() layout_iter_shallow_copy = LayoutIter.from_pointer( pointer_shallow_copy ) assert isinstance(layout_iter_shallow_copy, LayoutIter) assert isinstance(layout_iter_shallow_copy.get_pointer(), ffi.CData)
def render_cluster_glyph_items( ctx: cairocffi.Context, layout: pangocffi.Layout ): """ Renders each cluster within a layout with a unique rotation and color. Warning: Does not support bidirectional text. :param ctx: a Cairo context :param layout: a Pango layout """ layout_run_iter = layout.get_iter() layout_cluster_iter = layout.get_iter() layout_text = layout.get_text() alternate = False while True: layout_run = layout_run_iter.get_run() layout_line_baseline = layout_run_iter.get_baseline() if layout_run is None: if not layout_run_iter.next_run(): break continue clusters = get_clusters_from_glyph_item(layout_run, layout_text) for cluster in clusters: cluster_extents = layout_cluster_iter.get_cluster_extents()[1] layout_cluster_iter.next_cluster() alternate = not alternate ctx.set_source_rgba(0.5, 0, 1 if alternate else 0.5, 0.9) ctx.save() ctx.translate( pangocffi.units_to_double(cluster_extents.x), pangocffi.units_to_double(layout_line_baseline) ) ctx.rotate(-0.05 if alternate else 0.05) pangocairocffi.show_glyph_item( ctx, layout_text, cluster ) ctx.restore() if not layout_run_iter.next_run(): break
def test_glyph_item_splits(self): text = 'Hi from Παν語' layout = Layout(self.pango_context) layout.set_text(text) layout_iter = layout.get_iter() layout_run = layout_iter.get_run() layout_run_hi = layout_run.split(text, 3) # Substring "Hi " assert layout_run_hi.item.num_chars == 3 assert layout_run_hi.item.offset == 0 # Substring "from " assert layout_run.item.num_chars == 5 assert layout_run.item.offset == 3
def test_layout_setting_text(self): layout = Layout(self.pango_context) layout.set_text('Hi from Παν語') assert layout.get_text() == 'Hi from Παν語' layout.set_markup('<span font="italic 30">Hello from Παν語</span>') assert layout.get_text() == 'Hello from Παν語'
def test_layout_setting_text(): context = Context() layout = Layout(context) layout.set_width(300) layout.set_text('Hi from Pango') layout.set_markup('<span font="italic 30">Hi from Παν語</span>')
def __init__(self, line_string: LineString, layout: Layout): if layout.get_line_count() > 1: raise ValueError('layout cannot be more than one line.') self._layout = layout self._input_line_string = line_string self._layout_text = layout.get_text() self._alignment = Alignment.LEFT self._start_offset = 0 self._vertical_offset = 0 self._side = Side.LEFT self._layout_clusters = LayoutClusters(self._layout) self._layout_engine_class = SvgLayoutEngine self._layout_engine = None
def test_item_properties(self): layout = Layout(self.pango_context) layout.set_text('Hi from Παν語') layout_iter = layout.get_iter() layout_run = layout_iter.get_run() layout_run_item = layout_run.item assert layout_run_item.length == 8 assert layout_run_item.offset == 0 assert layout_run_item.num_chars == 8 assert isinstance(layout_run_item.get_pointer(), ffi.CData) assert layout_iter.next_run() layout_run = layout_iter.get_run() layout_run_item = layout_run.item assert layout_run_item.length == 6 assert layout_run_item.offset == 8 assert layout_run_item.num_chars == 3 assert isinstance(layout_run_item.get_pointer(), ffi.CData)
def render_run_glyph_items( ctx: cairocffi.Context, layout: pangocffi.Layout ) -> None: """ Renders each layout run within a layout with a unique rotation and color. :param ctx: a Cairo context :param layout: a Pango layout """ layout_iter = layout.get_iter() layout_text = layout.get_text() alternate = False while True: layout_run = layout_iter.get_run() layout_run_extents = layout_iter.get_run_extents()[1] layout_line_baseline = layout_iter.get_baseline() if layout_run is None: if not layout_iter.next_run(): break continue alternate = not alternate ctx.set_source_rgba(0, 0.5, 1 if alternate else 0.5, 0.9) ctx.save() ctx.translate( pangocffi.units_to_double(layout_run_extents.x), pangocffi.units_to_double(layout_line_baseline) ) ctx.rotate(0.05 if alternate else -0.05) pangocairocffi.show_glyph_item(ctx, layout_text, layout_run) ctx.restore() if not layout_iter.next_run(): break
def update_layout(cairo_context: cairocffi.Context, layout: pangocffi.Layout) -> None: """ Updates the private Pango ``Context`` of a Pango ``Layout`` created with :meth:`create_layout()` to match the current transformation and target surface of a Cairo context. :param cairo_context: a Cairo context :param layout: a Pango layout """ cairo_t_pointer = _get_cairo_t_from_cairo_ctx(cairo_context) pangocairo.pango_cairo_update_layout(cairo_t_pointer, layout.get_pointer())
def show_layout(cairo_context: cairocffi.Context, layout: pangocffi.Layout) -> None: """ Draws a Pango Layout in the specified cairo context. The top-left corner of the PangoLayout will be drawn at the current point of the cairo context. :param cairo_context: a Cairo context :param layout: a Pango layout """ cairo_context_pointer = _get_cairo_t_from_cairo_ctx(cairo_context) pangocairo.pango_cairo_show_layout(cairo_context_pointer, layout.get_pointer())
def test_layout_iter_properties(self): layout = Layout(self.pango_context) layout_iter = layout.get_iter() assert layout_iter.next_run() is False assert layout_iter.next_char() is False assert layout_iter.next_cluster() is False assert layout_iter.next_line() is False assert layout_iter.at_last_line() is True assert layout_iter.get_index() == 0 # Even with no text in the layout, the layout will still have a # baseline corresponding to the selected font description. assert layout_iter.get_baseline() > 0 assert isinstance(layout_iter.get_char_extents(), Rectangle) cluster_ink, cluster_logical = layout_iter.get_cluster_extents() assert isinstance(cluster_ink, Rectangle) assert isinstance(cluster_logical, Rectangle) run_ink, run_logical = layout_iter.get_run_extents() assert isinstance(run_ink, Rectangle) assert isinstance(run_logical, Rectangle) y0, y1 = layout_iter.get_line_yrange() assert y0 == 0 # Even with no text in the layout, the layout will still have a # y-range corresponding to the selected font description. assert y1 > 0 line_ink, line_logical = layout_iter.get_line_extents() assert isinstance(line_ink, Rectangle) assert isinstance(line_logical, Rectangle) layout_ink, layout_logical = layout_iter.get_layout_extents() assert isinstance(layout_ink, Rectangle) assert isinstance(layout_logical, Rectangle)
def compute_subtext_extents(layout: Layout, parsed_text, id_index: int) -> Tuple[float, float]: """ Returns the x coordinate and width of a subtext of a single line. """ assert layout.get_line_count() == 1 (start, end) = get_byte_range(parsed_text, id_index) iter = layout.get_iter() x = None width = 0 while True: byte_offset = iter.get_index() if start <= byte_offset < end: extents = from_pango_rect(iter.get_char_extents()) if x is None: assert start == byte_offset x = extents.x width += extents.width if byte_offset >= end or not iter.next_char(): break assert x is not None return (x, width)
def layout_path(cairo_context: cairocffi.Context, layout: pangocffi.Layout) -> None: """ Adds the text in a ``Pango.Layout`` to the current path in the specified cairo context. The top-left corner of the ``Pango.Layout`` will be at the current point of the cairo context. :param cairo_context: a Cairo context :param layout: a Pango layout """ cairo_context_pointer = _get_cairo_t_from_cairo_ctx(cairo_context) pangocairo.pango_cairo_layout_path(cairo_context_pointer, layout.get_pointer())
def _show_layout_baseline( context: cairocffi.Context, layout: pangocffi.Layout ): layout_iter = layout.get_iter() context.set_line_width(0.5) context.set_dash([1, 1]) while True: extents = layout_iter.get_line_extents() baseline = layout_iter.get_baseline() y_ranges = layout_iter.get_line_yrange() context.set_source_rgba(1, 0, 0, 0.9) context.move_to( pangocffi.units_to_double(extents[0].x), pangocffi.units_to_double(y_ranges[0]) ) context.line_to( pangocffi.units_to_double(extents[0].x + extents[0].width), pangocffi.units_to_double(y_ranges[0]) ) context.stroke() context.set_source_rgba(0, 1, 0, 0.9) context.stroke() context.move_to( pangocffi.units_to_double(extents[0].x), pangocffi.units_to_double(baseline) ) context.line_to( pangocffi.units_to_double(extents[0].x + extents[0].width), pangocffi.units_to_double(baseline) ) context.stroke() context.set_source_rgba(0, 0, 1, 0.9) context.move_to( pangocffi.units_to_double(extents[0].x), pangocffi.units_to_double(y_ranges[1]) ) context.line_to( pangocffi.units_to_double(extents[0].x + extents[0].width), pangocffi.units_to_double(y_ranges[1]) ) context.stroke() if not layout_iter.next_run(): break
def test_layout_setting_font_description(): context = Context() layout = Layout(context) # Assert that the font description is not set assert layout.get_font_description() is None # Creating the font description desc = FontDescription() desc.set_family('sans-serif') layout.set_font_description(desc) # Verifying the font description was set same_desc = layout.get_font_description() assert same_desc.get_family() == desc.get_family() # Changing the font description desc.set_family('serif') assert same_desc.get_family() != desc.get_family() # Resetting the font description layout.set_font_description(None) assert layout.get_font_description() is None
def _show_layout_line_logical_extents( context: cairocffi.Context, layout: pangocffi.Layout ): layout_iter = layout.get_iter() context.set_line_width(0.5) context.set_dash([1, 1]) alternate = True while True: alternate = not alternate extents = layout_iter.get_line_extents() context.set_source_rgba(0, 0, 1 if alternate else 0.5, 0.9) _rectangle_path(context, extents[1]) context.stroke() _coordinate_path(context, (extents[1].x, extents[1].y)) context.fill() if not layout_iter.next_run(): break
def _show_layout_y_ranges( context: cairocffi.Context, layout: pangocffi.Layout ): layout_iter = layout.get_iter() context.set_line_width(0.5) context.set_dash([1, 1]) alternate = True while True: alternate = not alternate extents = layout_iter.get_line_extents() y_ranges = layout_iter.get_line_yrange() context.set_source_rgba(0, 0, 1 if alternate else 0.5, 0.9) context.move_to( pangocffi.units_to_double(extents[0].x), pangocffi.units_to_double(y_ranges[0]) ) context.line_to( pangocffi.units_to_double(extents[0].x + extents[0].width), pangocffi.units_to_double(y_ranges[0]) ) context.stroke() context.move_to( pangocffi.units_to_double(extents[0].x), pangocffi.units_to_double(y_ranges[1]) ) context.line_to( pangocffi.units_to_double(extents[0].x + extents[0].width), pangocffi.units_to_double(y_ranges[1]) ) context.stroke() if not layout_iter.next_run(): break
def getLayoutExtent(layout: pango.Layout) -> Tuple[float, float, float, float]: e = layout.get_extents() return (pango.units_to_double(e[1].x), pango.units_to_double(e[1].y), pango.units_to_double(e[1].width), pango.units_to_double(e[1].height))
def get_extents(layout: pangocffi.Layout, ink=True) -> Rect: rect_logical, rect_ink = layout.get_extents() return from_pango_rect(rect_ink if ink else rect_logical)
def test_layout_get_pointer_returns_identical_layout(): context = Context() layout = Layout(context) identical_layout = Layout.from_pointer(layout.get_pointer()) assert identical_layout.get_pointer() == layout.get_pointer()
def test_layout_not_implemented_equality(self): context = Context() layout = Layout(context) assert ('not an object' != layout)
def test_layout_returns_identical_context(): context = Context() layout = Layout(context) identical_context = layout.get_context() assert identical_context.get_pointer() == context.get_pointer()
def test_layout_setting_properties(): context = Context() layout = Layout(context) layout.set_width(300) assert layout.get_width() == 300 layout.set_height(400) assert layout.get_height() == 400 assert layout.get_spacing() == 0 layout.set_spacing(30) assert layout.get_spacing() == 30 layout.set_alignment(Alignment.CENTER) assert layout.get_alignment() is Alignment.CENTER layout.set_ellipsize(EllipsizeMode.MIDDLE) assert layout.get_ellipsize() is EllipsizeMode.MIDDLE ink_rect, logical_rect = layout.get_extents() assert logical_rect.width == 0 assert logical_rect.height == 0 width, height = layout.get_size() assert width == 0 assert height == 0 baseline = layout.get_baseline() assert baseline == 0 line_count = layout.get_line_count() assert line_count == 1
def test_layout_returns_null_from_null_pointer(self): with self.assertRaises(ValueError): Layout.from_pointer(ffi.NULL)