[pango/pango2: 45/56] docs: Add a complex layout example




commit 283ebbfb6af90eee690eabf17f34d55bf0bffbf6
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Jun 12 19:18:34 2022 -0400

    docs: Add a complex layout example

 docs/meson.build     |   2 +
 docs/pango.toml.in   |   2 +
 docs/pango_layout.md | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++
 docs/parshape.png    | Bin 0 -> 48251 bytes
 examples/parshape.c  |  86 ++++++++++++++------------
 5 files changed, 221 insertions(+), 37 deletions(-)
---
diff --git a/docs/meson.build b/docs/meson.build
index 0d320590a..58543b015 100644
--- a/docs/meson.build
+++ b/docs/meson.build
@@ -8,6 +8,7 @@ pango_content_files = [
   'pango_bidi.md',
   'pango_cairo.md',
   'pango_user.md',
+  'pango_layout.md',
   'pango-name.png',
   'layout-light.png',
   'layout-dark.png',
@@ -56,6 +57,7 @@ pango_content_files = [
   'rotated-text.png',
   'bullets.png',
   'first-steps.png',
+  'parshape.png',
 ]
 
 doc_conf = configuration_data()
diff --git a/docs/pango.toml.in b/docs/pango.toml.in
index bb6ff5392..77f73456b 100644
--- a/docs/pango.toml.in
+++ b/docs/pango.toml.in
@@ -51,6 +51,7 @@ content_files = [
   "pango_bidi.md",
   "pango_cairo.md",
   "pango_user.md",
+  "pango_layout.md",
 ]
 
 content_images = [
@@ -101,6 +102,7 @@ content_images = [
   "rotated-text.png",
   "bullets.png",
   "first-steps.png",
+  "parshape.png",
 ]
 
 urlmap_file = "urlmap.js"
diff --git a/docs/pango_layout.md b/docs/pango_layout.md
new file mode 100644
index 000000000..a4d8e122b
--- /dev/null
+++ b/docs/pango_layout.md
@@ -0,0 +1,168 @@
+---
+Title: Complex layout
+---
+
+# Complex layout
+
+The central object in high-level Pango API is [class@Pango.Layout].
+It is well-suited for breaking text into lines that fill a rectangular
+area, since that is commonly how paragraphs are formatted in books.
+But in real-life situations, text does not always fit in a box.
+Examples of more complicated requirements are fitting text around
+an image, or flowing text between multiple frames.
+
+For cases like these, it is better to use [class@Pango.LineBreaker]
+directly instead of `PangoLayout` (`PangoLayout` is using a line
+breaker internally). The way `PangoLineBreaker` works is to let
+applications access the formatted result one line at a time, place
+it, and change parameters such as the line width before requesting
+the next one.
+
+The following example shows how to use `PangoLineBreaker` to
+produce an unusually shaped paragraph with a hole in the middle.
+
+## Using GtkLineBreaker
+
+```
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+
+static PangoLines *
+format_text (const char *text)
+{
+  PangoContext *context;
+  PangoLineBreaker *breaker;
+  PangoLines *lines;
+  int x, y, width;
+  int inc, m, w, w2;
+
+  context = pango_font_map_create_context (pango_font_map_get_default ());
+  breaker = pango_line_breaker_new (context);
+
+  pango_line_breaker_add_text (breaker, text, -1, NULL);
+
+  lines = pango_lines_new ();
+
+  m = 200;
+  w = 10;
+  w2 = -200;
+  inc = 40;
+
+  y = 40 * PANGO_SCALE;
+  x = (m - w / 2) * PANGO_SCALE;
+  width = w * PANGO_SCALE;
+
+  while (pango_line_breaker_has_line (breaker))
+    {
+      PangoLine *line;
+      PangoRectangle ext;
+      gboolean ltr;
+
+      line = pango_line_breaker_next_line (breaker,
+                                           x, width,
+                                           PANGO_WRAP_CHAR,
+                                           PANGO_ELLIPSIZE_NONE);
+
+      pango_line_get_extents (line, NULL, &ext);
+      line = pango_line_justify (line, width);
+      pango_lines_add_line (lines, line, x, y - ext.y);
+
+      ltr = pango_line_breaker_get_direction (breaker) == PANGO_DIRECTION_LTR;
+
+      if (w2 > 0 && ltr && x <= m * PANGO_SCALE)
+        x = (m + w2 / 2) * PANGO_SCALE;
+      else if (w2 > 0 && !ltr && x > m * PANGO_SCALE)
+        x = (m - w2 / 2) * PANGO_SCALE;
+      else
+        {
+          y += ext.height;
+
+          w += inc;
+          w2 += inc;
+          if (w + inc >= 340 || w + inc < 0)
+            inc = - inc;
+
+          if (w2 > 0)
+            width = ((w - w2) / 2) * PANGO_SCALE;
+          else
+            width = w * PANGO_SCALE;
+
+          if (ltr)
+            x = (m - w / 2) * PANGO_SCALE;
+          else
+            x = (m + w / 2) * PANGO_SCALE;
+        }
+    }
+
+  g_object_unref (breaker);
+  g_object_unref (context);
+
+  return lines;
+}
+
+static void
+draw_lines (cairo_t *cr, PangoLines *lines)
+{
+  for (int i = 0; i < pango_lines_get_line_count (lines); i++)
+    {
+      PangoLine *line = pango_lines_get_lines (lines)[i];
+      int x, y;
+
+      pango_lines_get_line_position (lines, i, &x, &y);
+
+      cairo_save (cr);
+      cairo_move_to (cr, x / (double)PANGO_SCALE, y / (double)PANGO_SCALE);
+      pango_cairo_show_line (cr, line);
+      cairo_restore (cr);
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  const char *filename;
+  PangoLines *lines;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+  char *text;
+  gsize length;
+  GError *error = NULL;
+
+  if (argc != 3)
+    {
+      g_printerr ("Usage: %s INPUT_FILENAME OUTPUT_FILENAME\n", argv[0]);
+      return 1;
+    }
+
+  if (!g_file_get_contents (argv[1], &text, &length, &error))
+    {
+      g_printerr ("%s\n", error->message);
+      return 1;
+    }
+
+  filename = argv[2];
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 400, 600);
+  cr = cairo_create (surface);
+  cairo_set_source_rgb (cr, 1, 1, 1);
+  cairo_paint (cr);
+  cairo_set_source_rgb (cr, 0, 0, 0);
+
+  lines = format_text (text);
+  draw_lines (cr, lines);
+  g_object_unref (lines);
+
+  cairo_surface_write_to_png (surface, filename);
+  g_print ("Output written to %s\n", filename);
+
+  cairo_surface_destroy (surface);
+  cairo_destroy (cr);
+
+  return 0;
+}
+```
+
+Once you build and run the example code above, you should see the
+following result:
+
+![Output of the example](parshape.png)
diff --git a/docs/parshape.png b/docs/parshape.png
new file mode 100644
index 000000000..6ac8a05da
Binary files /dev/null and b/docs/parshape.png differ
diff --git a/examples/parshape.c b/examples/parshape.c
index e33f9600f..2fe8cbe97 100644
--- a/examples/parshape.c
+++ b/examples/parshape.c
@@ -1,47 +1,18 @@
 #include <pango/pango.h>
 #include <pango/pangocairo.h>
 
-int
-main (int argc, char *argv[])
+static PangoLines *
+format_text (const char *text)
 {
-  const char *filename;
   PangoContext *context;
   PangoLineBreaker *breaker;
-  int x, y, width;
   PangoLines *lines;
+  int x, y, width;
   int inc, m, w, w2;
-  cairo_surface_t *surface;
-  cairo_t *cr;
-  char *text;
-  gsize length;
-  GError *error = NULL;
-
-  if (argc != 3)
-    {
-      g_printerr ("Usage: %s INPUT_FILENAME OUTPUT_FILENAME\n", argv[0]);
-      return 1;
-    }
-
-  if (!g_file_get_contents (argv[1], &text, &length, &error))
-    {
-      g_printerr ("%s\n", error->message);
-      return 1;
-    }
-
-  filename = argv[2];
 
   context = pango_font_map_create_context (pango_font_map_get_default ());
-
-  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 400, 600);
-  cr = cairo_create (surface);
-  cairo_set_source_rgb (cr, 1, 1, 1);
-  cairo_paint (cr);
-  cairo_set_source_rgb (cr, 0, 0, 0);
-
   breaker = pango_line_breaker_new (context);
 
-  g_print ("Using %s\n", G_OBJECT_TYPE_NAME (breaker));
-
   pango_line_breaker_add_text (breaker, text, -1, NULL);
 
   lines = pango_lines_new ();
@@ -97,9 +68,19 @@ main (int argc, char *argv[])
         }
     }
 
+  g_object_unref (breaker);
+  g_object_unref (context);
+
+  return lines;
+}
+
+static void
+draw_lines (cairo_t *cr, PangoLines *lines)
+{
   for (int i = 0; i < pango_lines_get_line_count (lines); i++)
     {
       PangoLine *line = pango_lines_get_lines (lines)[i];
+      int x, y;
 
       pango_lines_get_line_position (lines, i, &x, &y);
 
@@ -108,17 +89,48 @@ main (int argc, char *argv[])
       pango_cairo_show_line (cr, line);
       cairo_restore (cr);
     }
+}
 
-  cairo_surface_write_to_png (surface, filename);
-  g_print ("Output written to %s\n", filename);
+int
+main (int argc, char *argv[])
+{
+  const char *filename;
+  PangoLines *lines;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+  char *text;
+  gsize length;
+  GError *error = NULL;
+
+  if (argc != 3)
+    {
+      g_printerr ("Usage: %s INPUT_FILENAME OUTPUT_FILENAME\n", argv[0]);
+      return 1;
+    }
+
+  if (!g_file_get_contents (argv[1], &text, &length, &error))
+    {
+      g_printerr ("%s\n", error->message);
+      return 1;
+    }
 
+  filename = argv[2];
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 400, 600);
+  cr = cairo_create (surface);
+  cairo_set_source_rgb (cr, 1, 1, 1);
+  cairo_paint (cr);
+  cairo_set_source_rgb (cr, 0, 0, 0);
+
+  lines = format_text (text);
+  draw_lines (cr, lines);
   g_object_unref (lines);
-  g_object_unref (breaker);
+
+  cairo_surface_write_to_png (surface, filename);
+  g_print ("Output written to %s\n", filename);
 
   cairo_surface_destroy (surface);
   cairo_destroy (cr);
 
-  g_object_unref (context);
-
   return 0;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]