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_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 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 _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 _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 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 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 _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 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 test_layout_iter_pointer(): context = Context() layout = Layout(context) layout_iter = layout.get_iter() assert isinstance(layout_iter.get_pointer(), ffi.CData)
def test_layout_iterator_run_returns_none(self): layout = Layout(self.pango_context) layout_iter = layout.get_iter() assert layout_iter.get_run() is None
def test_layout_iterator_run_returns_none(): context = Context() layout = Layout(context) layout_iter = layout.get_iter() assert layout_iter.get_run() is None