PageRenderTime 68ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/pango/pango-layout.c

https://gitlab.com/ImageMagick/pango
C | 6471 lines | 3927 code | 970 blank | 1574 comment | 791 complexity | 5344e44b5d1f4418be39a12b6661480d MD5 | raw file
Possible License(s): LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /* Pango
  2. * pango-layout.c: High-level layout driver
  3. *
  4. * Copyright (C) 2000, 2001, 2006 Red Hat Software
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Library General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Library General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Library General Public
  17. * License along with this library; if not, write to the
  18. * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19. * Boston, MA 02111-1307, USA.
  20. */
  21. /**
  22. * SECTION:layout
  23. * @short_description:High-level layout driver objects
  24. * @title:Layout Objects
  25. *
  26. * While complete access to the layout capabilities of Pango is provided
  27. * using the detailed interfaces for itemization and shaping, using
  28. * that functionality directly involves writing a fairly large amount
  29. * of code. The objects and functions in this section provide a
  30. * high-level driver for formatting entire paragraphs of text
  31. * at once.
  32. */
  33. /**
  34. * PangoLayout:
  35. *
  36. * The #PangoLayout structure represents an entire paragraph
  37. * of text. It is initialized with a #PangoContext, UTF-8 string
  38. * and set of attributes for that string. Once that is done, the
  39. * set of formatted lines can be extracted from the object,
  40. * the layout can be rendered, and conversion between logical
  41. * character positions within the layout's text, and the physical
  42. * position of the resulting glyphs can be made.
  43. *
  44. * There are also a number of parameters to adjust the formatting
  45. * of a #PangoLayout, which are illustrated in <xref linkend="parameters"/>.
  46. * It is possible, as well, to ignore the 2-D setup, and simply
  47. * treat the results of a #PangoLayout as a list of lines.
  48. *
  49. * <figure id="parameters">
  50. * <title>Adjustable parameters for a PangoLayout</title>
  51. * <graphic fileref="layout.gif" format="GIF"></graphic>
  52. * </figure>
  53. *
  54. * The #PangoLayout structure is opaque, and has no user-visible
  55. * fields.
  56. */
  57. /**
  58. * PangoLayoutIter:
  59. *
  60. * A #PangoLayoutIter structure can be used to
  61. * iterate over the visual extents of a #PangoLayout.
  62. *
  63. * The #PangoLayoutIter structure is opaque, and
  64. * has no user-visible fields.
  65. */
  66. #include "config.h"
  67. #include "pango-glyph.h" /* For pango_shape() */
  68. #include "pango-break.h"
  69. #include "pango-item.h"
  70. #include "pango-engine.h"
  71. #include "pango-impl-utils.h"
  72. #include "pango-glyph-item.h"
  73. #include <string.h>
  74. #include "pango-layout-private.h"
  75. typedef struct _ItemProperties ItemProperties;
  76. typedef struct _ParaBreakState ParaBreakState;
  77. struct _ItemProperties
  78. {
  79. PangoUnderline uline;
  80. gboolean strikethrough;
  81. gint rise;
  82. gint letter_spacing;
  83. gboolean shape_set;
  84. PangoRectangle *shape_ink_rect;
  85. PangoRectangle *shape_logical_rect;
  86. };
  87. typedef struct _PangoLayoutLinePrivate PangoLayoutLinePrivate;
  88. struct _PangoLayoutLinePrivate
  89. {
  90. PangoLayoutLine line;
  91. guint ref_count;
  92. /* Extents cache status:
  93. *
  94. * LEAKED means that the user has access to this line structure or a
  95. * run included in this line, and so can change the glyphs/glyph-widths.
  96. * If this is true, extents caching will be disabled.
  97. */
  98. enum {
  99. NOT_CACHED,
  100. CACHED,
  101. LEAKED
  102. } cache_status;
  103. PangoRectangle ink_rect;
  104. PangoRectangle logical_rect;
  105. };
  106. struct _PangoLayoutClass
  107. {
  108. GObjectClass parent_class;
  109. };
  110. #define LINE_IS_VALID(line) ((line) && (line)->layout != NULL)
  111. #ifdef G_DISABLE_CHECKS
  112. #define ITER_IS_INVALID(iter) FALSE
  113. #else
  114. #define ITER_IS_INVALID(iter) G_UNLIKELY (check_invalid ((iter), G_STRLOC))
  115. static gboolean
  116. check_invalid (PangoLayoutIter *iter,
  117. const char *loc)
  118. {
  119. if (iter->line->layout == NULL)
  120. {
  121. g_warning ("%s: PangoLayout changed since PangoLayoutIter was created, iterator invalid", loc);
  122. return TRUE;
  123. }
  124. else
  125. {
  126. return FALSE;
  127. }
  128. }
  129. #endif
  130. static void check_context_changed (PangoLayout *layout);
  131. static void layout_changed (PangoLayout *layout);
  132. static void pango_layout_clear_lines (PangoLayout *layout);
  133. static void pango_layout_check_lines (PangoLayout *layout);
  134. static PangoAttrList *pango_layout_get_effective_attributes (PangoLayout *layout);
  135. static PangoLayoutLine * pango_layout_line_new (PangoLayout *layout);
  136. static void pango_layout_line_postprocess (PangoLayoutLine *line,
  137. ParaBreakState *state,
  138. gboolean wrapped);
  139. static int *pango_layout_line_get_log2vis_map (PangoLayoutLine *line,
  140. gboolean strong);
  141. static int *pango_layout_line_get_vis2log_map (PangoLayoutLine *line,
  142. gboolean strong);
  143. static void pango_layout_line_leaked (PangoLayoutLine *line);
  144. /* doesn't leak line */
  145. static PangoLayoutLine* _pango_layout_iter_get_line (PangoLayoutIter *iter);
  146. static void pango_layout_get_item_properties (PangoItem *item,
  147. ItemProperties *properties);
  148. static void pango_layout_get_empty_extents_at_index (PangoLayout *layout,
  149. int index,
  150. PangoRectangle *logical_rect);
  151. static void pango_layout_finalize (GObject *object);
  152. G_DEFINE_TYPE (PangoLayout, pango_layout, G_TYPE_OBJECT)
  153. static void
  154. pango_layout_init (PangoLayout *layout)
  155. {
  156. layout->serial = 1;
  157. layout->attrs = NULL;
  158. layout->font_desc = NULL;
  159. layout->text = NULL;
  160. layout->length = 0;
  161. layout->width = -1;
  162. layout->height = -1;
  163. layout->indent = 0;
  164. layout->spacing = 0;
  165. layout->alignment = PANGO_ALIGN_LEFT;
  166. layout->justify = FALSE;
  167. layout->auto_dir = TRUE;
  168. layout->log_attrs = NULL;
  169. layout->lines = NULL;
  170. layout->line_count = 0;
  171. layout->tab_width = -1;
  172. layout->unknown_glyphs_count = -1;
  173. layout->wrap = PANGO_WRAP_WORD;
  174. layout->is_wrapped = FALSE;
  175. layout->ellipsize = PANGO_ELLIPSIZE_NONE;
  176. layout->is_ellipsized = FALSE;
  177. }
  178. static void
  179. pango_layout_class_init (PangoLayoutClass *klass)
  180. {
  181. GObjectClass *object_class = G_OBJECT_CLASS (klass);
  182. object_class->finalize = pango_layout_finalize;
  183. }
  184. static void
  185. pango_layout_finalize (GObject *object)
  186. {
  187. PangoLayout *layout;
  188. layout = PANGO_LAYOUT (object);
  189. pango_layout_clear_lines (layout);
  190. if (layout->context)
  191. g_object_unref (layout->context);
  192. if (layout->attrs)
  193. pango_attr_list_unref (layout->attrs);
  194. g_free (layout->text);
  195. if (layout->font_desc)
  196. pango_font_description_free (layout->font_desc);
  197. if (layout->tabs)
  198. pango_tab_array_free (layout->tabs);
  199. G_OBJECT_CLASS (pango_layout_parent_class)->finalize (object);
  200. }
  201. /**
  202. * pango_layout_new:
  203. * @context: a #PangoContext
  204. *
  205. * Create a new #PangoLayout object with attributes initialized to
  206. * default values for a particular #PangoContext.
  207. *
  208. * Return value: the newly allocated #PangoLayout, with a reference
  209. * count of one, which should be freed with
  210. * g_object_unref().
  211. **/
  212. PangoLayout *
  213. pango_layout_new (PangoContext *context)
  214. {
  215. PangoLayout *layout;
  216. g_return_val_if_fail (context != NULL, NULL);
  217. layout = g_object_new (PANGO_TYPE_LAYOUT, NULL);
  218. layout->context = context;
  219. layout->context_serial = pango_context_get_serial (context);
  220. g_object_ref (context);
  221. return layout;
  222. }
  223. /**
  224. * pango_layout_copy:
  225. * @src: a #PangoLayout
  226. *
  227. * Does a deep copy-by-value of the @src layout. The attribute list,
  228. * tab array, and text from the original layout are all copied by
  229. * value.
  230. *
  231. * Return value: (transfer full): the newly allocated #PangoLayout,
  232. * with a reference count of one, which should be freed
  233. * with g_object_unref().
  234. **/
  235. PangoLayout*
  236. pango_layout_copy (PangoLayout *src)
  237. {
  238. PangoLayout *layout;
  239. g_return_val_if_fail (PANGO_IS_LAYOUT (src), NULL);
  240. /* Copy referenced members */
  241. layout = pango_layout_new (src->context);
  242. if (src->attrs)
  243. layout->attrs = pango_attr_list_copy (src->attrs);
  244. if (src->font_desc)
  245. layout->font_desc = pango_font_description_copy (src->font_desc);
  246. if (src->tabs)
  247. layout->tabs = pango_tab_array_copy (src->tabs);
  248. /* Dupped */
  249. layout->text = g_strdup (src->text);
  250. /* Value fields */
  251. memcpy (&layout->copy_begin, &src->copy_begin,
  252. G_STRUCT_OFFSET (PangoLayout, copy_end) - G_STRUCT_OFFSET (PangoLayout, copy_begin));
  253. return layout;
  254. }
  255. /**
  256. * pango_layout_get_context:
  257. * @layout: a #PangoLayout
  258. *
  259. * Retrieves the #PangoContext used for this layout.
  260. *
  261. * Return value: (transfer none): the #PangoContext for the layout.
  262. * This does not have an additional refcount added, so if you want to
  263. * keep a copy of this around, you must reference it yourself.
  264. **/
  265. PangoContext *
  266. pango_layout_get_context (PangoLayout *layout)
  267. {
  268. g_return_val_if_fail (layout != NULL, NULL);
  269. return layout->context;
  270. }
  271. /**
  272. * pango_layout_set_width:
  273. * @layout: a #PangoLayout.
  274. * @width: the desired width in Pango units, or -1 to indicate that no
  275. * wrapping or ellipsization should be performed.
  276. *
  277. * Sets the width to which the lines of the #PangoLayout should wrap or
  278. * ellipsized. The default value is -1: no width set.
  279. **/
  280. void
  281. pango_layout_set_width (PangoLayout *layout,
  282. int width)
  283. {
  284. g_return_if_fail (layout != NULL);
  285. if (width < 0)
  286. width = -1;
  287. if (width != layout->width)
  288. {
  289. layout->width = width;
  290. layout_changed (layout);
  291. }
  292. }
  293. /**
  294. * pango_layout_get_width:
  295. * @layout: a #PangoLayout
  296. *
  297. * Gets the width to which the lines of the #PangoLayout should wrap.
  298. *
  299. * Return value: the width in Pango units, or -1 if no width set.
  300. **/
  301. int
  302. pango_layout_get_width (PangoLayout *layout)
  303. {
  304. g_return_val_if_fail (layout != NULL, 0);
  305. return layout->width;
  306. }
  307. /**
  308. * pango_layout_set_height:
  309. * @layout: a #PangoLayout.
  310. * @height: the desired height of the layout in Pango units if positive,
  311. * or desired number of lines if negative.
  312. *
  313. * Sets the height to which the #PangoLayout should be ellipsized at. There
  314. * are two different behaviors, based on whether @height is positive or
  315. * negative.
  316. *
  317. * If @height is positive, it will be the maximum height of the layout. Only
  318. * lines would be shown that would fit, and if there is any text omitted,
  319. * an ellipsis added. At least one line is included in each paragraph regardless
  320. * of how small the height value is. A value of zero will render exactly one
  321. * line for the entire layout.
  322. *
  323. * If @height is negative, it will be the (negative of) maximum number of lines per
  324. * paragraph. That is, the total number of lines shown may well be more than
  325. * this value if the layout contains multiple paragraphs of text.
  326. * The default value of -1 means that first line of each paragraph is ellipsized.
  327. * This behvaior may be changed in the future to act per layout instead of per
  328. * paragraph. File a bug against pango at <ulink
  329. * url="http://bugzilla.gnome.org/">http://bugzilla.gnome.org/</ulink> if your
  330. * code relies on this behavior.
  331. *
  332. * Height setting only has effect if a positive width is set on
  333. * @layout and ellipsization mode of @layout is not %PANGO_ELLIPSIZE_NONE.
  334. * The behavior is undefined if a height other than -1 is set and
  335. * ellipsization mode is set to %PANGO_ELLIPSIZE_NONE, and may change in the
  336. * future.
  337. *
  338. * Since: 1.20
  339. **/
  340. void
  341. pango_layout_set_height (PangoLayout *layout,
  342. int height)
  343. {
  344. g_return_if_fail (layout != NULL);
  345. if (height != layout->height)
  346. {
  347. layout->height = height;
  348. /* Do not invalidate if the number of lines requested is
  349. * larger than the total number of lines in layout.
  350. * Bug 549003
  351. */
  352. if (layout->ellipsize != PANGO_ELLIPSIZE_NONE &&
  353. !(layout->lines && layout->is_ellipsized == FALSE &&
  354. height < 0 && layout->line_count <= (guint) -height))
  355. layout_changed (layout);
  356. }
  357. }
  358. /**
  359. * pango_layout_get_height:
  360. * @layout: a #PangoLayout
  361. *
  362. * Gets the height of layout used for ellipsization. See
  363. * pango_layout_set_height() for details.
  364. *
  365. * Return value: the height, in Pango units if positive, or
  366. * number of lines if negative.
  367. *
  368. * Since: 1.20
  369. **/
  370. int
  371. pango_layout_get_height (PangoLayout *layout)
  372. {
  373. g_return_val_if_fail (layout != NULL, 0);
  374. return layout->height;
  375. }
  376. /**
  377. * pango_layout_set_wrap:
  378. * @layout: a #PangoLayout
  379. * @wrap: the wrap mode
  380. *
  381. * Sets the wrap mode; the wrap mode only has effect if a width
  382. * is set on the layout with pango_layout_set_width().
  383. * To turn off wrapping, set the width to -1.
  384. **/
  385. void
  386. pango_layout_set_wrap (PangoLayout *layout,
  387. PangoWrapMode wrap)
  388. {
  389. g_return_if_fail (PANGO_IS_LAYOUT (layout));
  390. if (layout->wrap != wrap)
  391. {
  392. layout->wrap = wrap;
  393. if (layout->width != -1)
  394. layout_changed (layout);
  395. }
  396. }
  397. /**
  398. * pango_layout_get_wrap:
  399. * @layout: a #PangoLayout
  400. *
  401. * Gets the wrap mode for the layout.
  402. *
  403. * Use pango_layout_is_wrapped() to query whether any paragraphs
  404. * were actually wrapped.
  405. *
  406. * Return value: active wrap mode.
  407. **/
  408. PangoWrapMode
  409. pango_layout_get_wrap (PangoLayout *layout)
  410. {
  411. g_return_val_if_fail (PANGO_IS_LAYOUT (layout), 0);
  412. return layout->wrap;
  413. }
  414. /**
  415. * pango_layout_is_wrapped:
  416. * @layout: a #PangoLayout
  417. *
  418. * Queries whether the layout had to wrap any paragraphs.
  419. *
  420. * This returns %TRUE if a positive width is set on @layout,
  421. * ellipsization mode of @layout is set to %PANGO_ELLIPSIZE_NONE,
  422. * and there are paragraphs exceeding the layout width that have
  423. * to be wrapped.
  424. *
  425. * Return value: %TRUE if any paragraphs had to be wrapped, %FALSE
  426. * otherwise.
  427. *
  428. * Since: 1.16
  429. */
  430. gboolean
  431. pango_layout_is_wrapped (PangoLayout *layout)
  432. {
  433. g_return_val_if_fail (layout != NULL, FALSE);
  434. pango_layout_check_lines (layout);
  435. return layout->is_wrapped;
  436. }
  437. /**
  438. * pango_layout_set_indent:
  439. * @layout: a #PangoLayout.
  440. * @indent: the amount by which to indent.
  441. *
  442. * Sets the width in Pango units to indent each paragraph. A negative value
  443. * of @indent will produce a hanging indentation. That is, the first line will
  444. * have the full width, and subsequent lines will be indented by the
  445. * absolute value of @indent.
  446. *
  447. * The indent setting is ignored if layout alignment is set to
  448. * %PANGO_ALIGN_CENTER.
  449. **/
  450. void
  451. pango_layout_set_indent (PangoLayout *layout,
  452. int indent)
  453. {
  454. g_return_if_fail (layout != NULL);
  455. if (indent != layout->indent)
  456. {
  457. layout->indent = indent;
  458. layout_changed (layout);
  459. }
  460. }
  461. /**
  462. * pango_layout_get_indent:
  463. * @layout: a #PangoLayout
  464. *
  465. * Gets the paragraph indent width in Pango units. A negative value
  466. * indicates a hanging indentation.
  467. *
  468. * Return value: the indent in Pango units.
  469. **/
  470. int
  471. pango_layout_get_indent (PangoLayout *layout)
  472. {
  473. g_return_val_if_fail (layout != NULL, 0);
  474. return layout->indent;
  475. }
  476. /**
  477. * pango_layout_set_spacing:
  478. * @layout: a #PangoLayout.
  479. * @spacing: the amount of spacing
  480. *
  481. * Sets the amount of spacing in Pango unit between the lines of the
  482. * layout.
  483. **/
  484. void
  485. pango_layout_set_spacing (PangoLayout *layout,
  486. int spacing)
  487. {
  488. g_return_if_fail (layout != NULL);
  489. if (spacing != layout->spacing)
  490. {
  491. layout->spacing = spacing;
  492. layout_changed (layout);
  493. }
  494. }
  495. /**
  496. * pango_layout_get_spacing:
  497. * @layout: a #PangoLayout
  498. *
  499. * Gets the amount of spacing between the lines of the layout.
  500. *
  501. * Return value: the spacing in Pango units.
  502. **/
  503. int
  504. pango_layout_get_spacing (PangoLayout *layout)
  505. {
  506. g_return_val_if_fail (layout != NULL, 0);
  507. return layout->spacing;
  508. }
  509. /**
  510. * pango_layout_set_attributes:
  511. * @layout: a #PangoLayout
  512. * @attrs: (allow-none) (transfer none): a #PangoAttrList, can be %NULL
  513. *
  514. * Sets the text attributes for a layout object.
  515. * References @attrs, so the caller can unref its reference.
  516. **/
  517. void
  518. pango_layout_set_attributes (PangoLayout *layout,
  519. PangoAttrList *attrs)
  520. {
  521. PangoAttrList *old_attrs;
  522. g_return_if_fail (layout != NULL);
  523. old_attrs = layout->attrs;
  524. /* We always clear lines such that this function can be called
  525. * whenever attrs changes.
  526. */
  527. layout->attrs = attrs;
  528. if (layout->attrs)
  529. pango_attr_list_ref (layout->attrs);
  530. layout_changed (layout);
  531. if (old_attrs)
  532. pango_attr_list_unref (old_attrs);
  533. layout->tab_width = -1;
  534. }
  535. /**
  536. * pango_layout_get_attributes:
  537. * @layout: a #PangoLayout
  538. *
  539. * Gets the attribute list for the layout, if any.
  540. *
  541. * Return value: (transfer none): a #PangoAttrList.
  542. **/
  543. PangoAttrList*
  544. pango_layout_get_attributes (PangoLayout *layout)
  545. {
  546. g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
  547. return layout->attrs;
  548. }
  549. /**
  550. * pango_layout_set_font_description:
  551. * @layout: a #PangoLayout
  552. * @desc: (allow-none): the new #PangoFontDescription, or %NULL to unset the
  553. * current font description
  554. *
  555. * Sets the default font description for the layout. If no font
  556. * description is set on the layout, the font description from
  557. * the layout's context is used.
  558. **/
  559. void
  560. pango_layout_set_font_description (PangoLayout *layout,
  561. const PangoFontDescription *desc)
  562. {
  563. g_return_if_fail (layout != NULL);
  564. if (desc != layout->font_desc &&
  565. (!desc || !layout->font_desc || !pango_font_description_equal(desc, layout->font_desc)))
  566. {
  567. if (layout->font_desc)
  568. pango_font_description_free (layout->font_desc);
  569. layout->font_desc = desc ? pango_font_description_copy (desc) : NULL;
  570. layout_changed (layout);
  571. layout->tab_width = -1;
  572. }
  573. }
  574. /**
  575. * pango_layout_get_font_description:
  576. * @layout: a #PangoLayout
  577. *
  578. * Gets the font description for the layout, if any.
  579. *
  580. * Return value: (nullable): a pointer to the layout's font
  581. * description, or %NULL if the font description from the layout's
  582. * context is inherited. This value is owned by the layout and must
  583. * not be modified or freed.
  584. *
  585. * Since: 1.8
  586. **/
  587. const PangoFontDescription *
  588. pango_layout_get_font_description (PangoLayout *layout)
  589. {
  590. g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
  591. return layout->font_desc;
  592. }
  593. /**
  594. * pango_layout_set_justify:
  595. * @layout: a #PangoLayout
  596. * @justify: whether the lines in the layout should be justified.
  597. *
  598. * Sets whether each complete line should be stretched to
  599. * fill the entire width of the layout. This stretching is typically
  600. * done by adding whitespace, but for some scripts (such as Arabic),
  601. * the justification may be done in more complex ways, like extending
  602. * the characters.
  603. *
  604. * Note that this setting is not implemented and so is ignored in Pango
  605. * older than 1.18.
  606. **/
  607. void
  608. pango_layout_set_justify (PangoLayout *layout,
  609. gboolean justify)
  610. {
  611. g_return_if_fail (layout != NULL);
  612. if (justify != layout->justify)
  613. {
  614. layout->justify = justify;
  615. if (layout->is_ellipsized || layout->is_wrapped)
  616. layout_changed (layout);
  617. }
  618. }
  619. /**
  620. * pango_layout_get_justify:
  621. * @layout: a #PangoLayout
  622. *
  623. * Gets whether each complete line should be stretched to fill the entire
  624. * width of the layout.
  625. *
  626. * Return value: the justify.
  627. **/
  628. gboolean
  629. pango_layout_get_justify (PangoLayout *layout)
  630. {
  631. g_return_val_if_fail (layout != NULL, FALSE);
  632. return layout->justify;
  633. }
  634. /**
  635. * pango_layout_set_auto_dir:
  636. * @layout: a #PangoLayout
  637. * @auto_dir: if %TRUE, compute the bidirectional base direction
  638. * from the layout's contents.
  639. *
  640. * Sets whether to calculate the bidirectional base direction
  641. * for the layout according to the contents of the layout;
  642. * when this flag is on (the default), then paragraphs in
  643. @layout that begin with strong right-to-left characters
  644. * (Arabic and Hebrew principally), will have right-to-left
  645. * layout, paragraphs with letters from other scripts will
  646. * have left-to-right layout. Paragraphs with only neutral
  647. * characters get their direction from the surrounding paragraphs.
  648. *
  649. * When %FALSE, the choice between left-to-right and
  650. * right-to-left layout is done according to the base direction
  651. * of the layout's #PangoContext. (See pango_context_set_base_dir()).
  652. *
  653. * When the auto-computed direction of a paragraph differs from the
  654. * base direction of the context, the interpretation of
  655. * %PANGO_ALIGN_LEFT and %PANGO_ALIGN_RIGHT are swapped.
  656. *
  657. * Since: 1.4
  658. **/
  659. void
  660. pango_layout_set_auto_dir (PangoLayout *layout,
  661. gboolean auto_dir)
  662. {
  663. g_return_if_fail (PANGO_IS_LAYOUT (layout));
  664. auto_dir = auto_dir != FALSE;
  665. if (auto_dir != layout->auto_dir)
  666. {
  667. layout->auto_dir = auto_dir;
  668. layout_changed (layout);
  669. }
  670. }
  671. /**
  672. * pango_layout_get_auto_dir:
  673. * @layout: a #PangoLayout
  674. *
  675. * Gets whether to calculate the bidirectional base direction
  676. * for the layout according to the contents of the layout.
  677. * See pango_layout_set_auto_dir().
  678. *
  679. * Return value: %TRUE if the bidirectional base direction
  680. * is computed from the layout's contents, %FALSE otherwise.
  681. *
  682. * Since: 1.4
  683. **/
  684. gboolean
  685. pango_layout_get_auto_dir (PangoLayout *layout)
  686. {
  687. g_return_val_if_fail (PANGO_IS_LAYOUT (layout), FALSE);
  688. return layout->auto_dir;
  689. }
  690. /**
  691. * pango_layout_set_alignment:
  692. * @layout: a #PangoLayout
  693. * @alignment: the alignment
  694. *
  695. * Sets the alignment for the layout: how partial lines are
  696. * positioned within the horizontal space available.
  697. **/
  698. void
  699. pango_layout_set_alignment (PangoLayout *layout,
  700. PangoAlignment alignment)
  701. {
  702. g_return_if_fail (layout != NULL);
  703. if (alignment != layout->alignment)
  704. {
  705. layout->alignment = alignment;
  706. layout_changed (layout);
  707. }
  708. }
  709. /**
  710. * pango_layout_get_alignment:
  711. * @layout: a #PangoLayout
  712. *
  713. * Gets the alignment for the layout: how partial lines are
  714. * positioned within the horizontal space available.
  715. *
  716. * Return value: the alignment.
  717. **/
  718. PangoAlignment
  719. pango_layout_get_alignment (PangoLayout *layout)
  720. {
  721. g_return_val_if_fail (layout != NULL, PANGO_ALIGN_LEFT);
  722. return layout->alignment;
  723. }
  724. /**
  725. * pango_layout_set_tabs:
  726. * @layout: a #PangoLayout
  727. * @tabs: (allow-none): a #PangoTabArray, or %NULL
  728. *
  729. * Sets the tabs to use for @layout, overriding the default tabs
  730. * (by default, tabs are every 8 spaces). If @tabs is %NULL, the default
  731. * tabs are reinstated. @tabs is copied into the layout; you must
  732. * free your copy of @tabs yourself.
  733. **/
  734. void
  735. pango_layout_set_tabs (PangoLayout *layout,
  736. PangoTabArray *tabs)
  737. {
  738. g_return_if_fail (PANGO_IS_LAYOUT (layout));
  739. if (tabs != layout->tabs)
  740. {
  741. if (layout->tabs)
  742. pango_tab_array_free (layout->tabs);
  743. layout->tabs = tabs ? pango_tab_array_copy (tabs) : NULL;
  744. layout_changed (layout);
  745. }
  746. }
  747. /**
  748. * pango_layout_get_tabs:
  749. * @layout: a #PangoLayout
  750. *
  751. * Gets the current #PangoTabArray used by this layout. If no
  752. * #PangoTabArray has been set, then the default tabs are in use
  753. * and %NULL is returned. Default tabs are every 8 spaces.
  754. * The return value should be freed with pango_tab_array_free().
  755. *
  756. * Return value: (nullable): a copy of the tabs for this layout, or
  757. * %NULL.
  758. **/
  759. PangoTabArray*
  760. pango_layout_get_tabs (PangoLayout *layout)
  761. {
  762. g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
  763. if (layout->tabs)
  764. return pango_tab_array_copy (layout->tabs);
  765. else
  766. return NULL;
  767. }
  768. /**
  769. * pango_layout_set_single_paragraph_mode:
  770. * @layout: a #PangoLayout
  771. * @setting: new setting
  772. *
  773. * If @setting is %TRUE, do not treat newlines and similar characters
  774. * as paragraph separators; instead, keep all text in a single paragraph,
  775. * and display a glyph for paragraph separator characters. Used when
  776. * you want to allow editing of newlines on a single text line.
  777. **/
  778. void
  779. pango_layout_set_single_paragraph_mode (PangoLayout *layout,
  780. gboolean setting)
  781. {
  782. g_return_if_fail (PANGO_IS_LAYOUT (layout));
  783. setting = setting != FALSE;
  784. if (layout->single_paragraph != setting)
  785. {
  786. layout->single_paragraph = setting;
  787. layout_changed (layout);
  788. }
  789. }
  790. /**
  791. * pango_layout_get_single_paragraph_mode:
  792. * @layout: a #PangoLayout
  793. *
  794. * Obtains the value set by pango_layout_set_single_paragraph_mode().
  795. *
  796. * Return value: %TRUE if the layout does not break paragraphs at
  797. * paragraph separator characters, %FALSE otherwise.
  798. **/
  799. gboolean
  800. pango_layout_get_single_paragraph_mode (PangoLayout *layout)
  801. {
  802. g_return_val_if_fail (PANGO_IS_LAYOUT (layout), FALSE);
  803. return layout->single_paragraph;
  804. }
  805. /**
  806. * pango_layout_set_ellipsize:
  807. * @layout: a #PangoLayout
  808. * @ellipsize: the new ellipsization mode for @layout
  809. *
  810. * Sets the type of ellipsization being performed for @layout.
  811. * Depending on the ellipsization mode @ellipsize text is
  812. * removed from the start, middle, or end of text so they
  813. * fit within the width and height of layout set with
  814. * pango_layout_set_width() and pango_layout_set_height().
  815. *
  816. * If the layout contains characters such as newlines that
  817. * force it to be layed out in multiple paragraphs, then whether
  818. * each paragraph is ellipsized separately or the entire layout
  819. * is ellipsized as a whole depends on the set height of the layout.
  820. * See pango_layout_set_height() for details.
  821. *
  822. * Since: 1.6
  823. **/
  824. void
  825. pango_layout_set_ellipsize (PangoLayout *layout,
  826. PangoEllipsizeMode ellipsize)
  827. {
  828. g_return_if_fail (PANGO_IS_LAYOUT (layout));
  829. if (ellipsize != layout->ellipsize)
  830. {
  831. layout->ellipsize = ellipsize;
  832. if (layout->is_ellipsized || layout->is_wrapped)
  833. layout_changed (layout);
  834. }
  835. }
  836. /**
  837. * pango_layout_get_ellipsize:
  838. * @layout: a #PangoLayout
  839. *
  840. * Gets the type of ellipsization being performed for @layout.
  841. * See pango_layout_set_ellipsize()
  842. *
  843. * Return value: the current ellipsization mode for @layout.
  844. *
  845. * Use pango_layout_is_ellipsized() to query whether any paragraphs
  846. * were actually ellipsized.
  847. *
  848. * Since: 1.6
  849. **/
  850. PangoEllipsizeMode
  851. pango_layout_get_ellipsize (PangoLayout *layout)
  852. {
  853. g_return_val_if_fail (PANGO_IS_LAYOUT (layout), PANGO_ELLIPSIZE_NONE);
  854. return layout->ellipsize;
  855. }
  856. /**
  857. * pango_layout_is_ellipsized:
  858. * @layout: a #PangoLayout
  859. *
  860. * Queries whether the layout had to ellipsize any paragraphs.
  861. *
  862. * This returns %TRUE if the ellipsization mode for @layout
  863. * is not %PANGO_ELLIPSIZE_NONE, a positive width is set on @layout,
  864. * and there are paragraphs exceeding that width that have to be
  865. * ellipsized.
  866. *
  867. * Return value: %TRUE if any paragraphs had to be ellipsized, %FALSE
  868. * otherwise.
  869. *
  870. * Since: 1.16
  871. */
  872. gboolean
  873. pango_layout_is_ellipsized (PangoLayout *layout)
  874. {
  875. g_return_val_if_fail (layout != NULL, FALSE);
  876. pango_layout_check_lines (layout);
  877. return layout->is_ellipsized;
  878. }
  879. /**
  880. * pango_layout_set_text:
  881. * @layout: a #PangoLayout
  882. * @text: a valid UTF-8 string
  883. * @length: maximum length of @text, in bytes. -1 indicates that
  884. * the string is nul-terminated and the length should be
  885. * calculated. The text will also be truncated on
  886. * encountering a nul-termination even when @length is
  887. * positive.
  888. *
  889. * Sets the text of the layout.
  890. *
  891. * Note that if you have used
  892. * pango_layout_set_markup() or pango_layout_set_markup_with_accel() on
  893. * @layout before, you may want to call pango_layout_set_attributes() to clear
  894. * the attributes set on the layout from the markup as this function does not
  895. * clear attributes.
  896. **/
  897. void
  898. pango_layout_set_text (PangoLayout *layout,
  899. const char *text,
  900. int length)
  901. {
  902. char *old_text, *start, *end;
  903. g_return_if_fail (layout != NULL);
  904. g_return_if_fail (length == 0 || text != NULL);
  905. old_text = layout->text;
  906. if (length < 0)
  907. layout->text = g_strdup (text);
  908. else if (length > 0)
  909. /* This is not exactly what we want. We don't need the padding...
  910. */
  911. layout->text = g_strndup (text, length);
  912. else
  913. layout->text = g_malloc0 (1);
  914. layout->length = strlen (layout->text);
  915. /* validate it, and replace invalid bytes with '?'
  916. */
  917. start = layout->text;
  918. for (;;) {
  919. gboolean valid;
  920. valid = g_utf8_validate (start, -1, (const char **)&end);
  921. if (!*end)
  922. break;
  923. /* Replace invalid bytes with -1. The -1 will be converted to
  924. * ((gunichar) -1) by glib, and that in turn yields a glyph value of
  925. * ((PangoGlyph) -1) by PANGO_GET_UNKNOWN_GLYPH(-1),
  926. * and that's PANGO_GLYPH_INVALID_INPUT.
  927. */
  928. if (!valid)
  929. *end++ = -1;
  930. start = end;
  931. }
  932. if (start != layout->text)
  933. /* TODO: Write out the beginning excerpt of text? */
  934. g_warning ("Invalid UTF-8 string passed to pango_layout_set_text()");
  935. layout->n_chars = pango_utf8_strlen (layout->text, -1);
  936. layout_changed (layout);
  937. g_free (old_text);
  938. }
  939. /**
  940. * pango_layout_get_text:
  941. * @layout: a #PangoLayout
  942. *
  943. * Gets the text in the layout. The returned text should not
  944. * be freed or modified.
  945. *
  946. * Return value: the text in the @layout.
  947. **/
  948. const char*
  949. pango_layout_get_text (PangoLayout *layout)
  950. {
  951. g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
  952. /* We don't ever want to return NULL as the text.
  953. */
  954. if (G_UNLIKELY (!layout->text))
  955. return "";
  956. return layout->text;
  957. }
  958. /**
  959. * pango_layout_get_character_count:
  960. * @layout: a #PangoLayout
  961. *
  962. * Returns the number of Unicode characters in the
  963. * the text of @layout.
  964. *
  965. * Return value: the number of Unicode characters
  966. * in the text of @layout
  967. *
  968. * Since: 1.30
  969. */
  970. gint
  971. pango_layout_get_character_count (PangoLayout *layout)
  972. {
  973. g_return_val_if_fail (PANGO_IS_LAYOUT (layout), 0);
  974. return layout->n_chars;
  975. }
  976. /**
  977. * pango_layout_set_markup:
  978. * @layout: a #PangoLayout
  979. * @markup: marked-up text
  980. * @length: length of marked-up text in bytes, or -1 if @markup is
  981. * null-terminated
  982. *
  983. * Same as pango_layout_set_markup_with_accel(), but
  984. * the markup text isn't scanned for accelerators.
  985. *
  986. **/
  987. void
  988. pango_layout_set_markup (PangoLayout *layout,
  989. const char *markup,
  990. int length)
  991. {
  992. pango_layout_set_markup_with_accel (layout, markup, length, 0, NULL);
  993. }
  994. /**
  995. * pango_layout_set_markup_with_accel:
  996. * @layout: a #PangoLayout
  997. * @markup: marked-up text
  998. * (see <link linkend="PangoMarkupFormat">markup format</link>)
  999. * @length: length of marked-up text in bytes, or -1 if @markup is
  1000. * null-terminated
  1001. * @accel_marker: marker for accelerators in the text
  1002. * @accel_char: (out caller-allocates) (allow-none): return location
  1003. * for first located accelerator, or %NULL
  1004. *
  1005. * Sets the layout text and attribute list from marked-up text (see
  1006. * <link linkend="PangoMarkupFormat">markup format</link>). Replaces
  1007. * the current text and attribute list.
  1008. *
  1009. * If @accel_marker is nonzero, the given character will mark the
  1010. * character following it as an accelerator. For example, @accel_marker
  1011. * might be an ampersand or underscore. All characters marked
  1012. * as an accelerator will receive a %PANGO_UNDERLINE_LOW attribute,
  1013. * and the first character so marked will be returned in @accel_char.
  1014. * Two @accel_marker characters following each other produce a single
  1015. * literal @accel_marker character.
  1016. **/
  1017. void
  1018. pango_layout_set_markup_with_accel (PangoLayout *layout,
  1019. const char *markup,
  1020. int length,
  1021. gunichar accel_marker,
  1022. gunichar *accel_char)
  1023. {
  1024. PangoAttrList *list = NULL;
  1025. char *text = NULL;
  1026. GError *error;
  1027. g_return_if_fail (PANGO_IS_LAYOUT (layout));
  1028. g_return_if_fail (markup != NULL);
  1029. error = NULL;
  1030. if (!pango_parse_markup (markup, length,
  1031. accel_marker,
  1032. &list, &text,
  1033. accel_char,
  1034. &error))
  1035. {
  1036. g_warning ("pango_layout_set_markup_with_accel: %s", error->message);
  1037. g_error_free (error);
  1038. return;
  1039. }
  1040. pango_layout_set_text (layout, text, -1);
  1041. pango_layout_set_attributes (layout, list);
  1042. pango_attr_list_unref (list);
  1043. g_free (text);
  1044. }
  1045. /**
  1046. * pango_layout_get_unknown_glyphs_count:
  1047. * @layout: a #PangoLayout
  1048. *
  1049. * Counts the number unknown glyphs in @layout. That is, zero if
  1050. * glyphs for all characters in the layout text were found, or more
  1051. * than zero otherwise.
  1052. *
  1053. * This function can be used to determine if there are any fonts
  1054. * available to render all characters in a certain string, or when
  1055. * used in combination with %PANGO_ATTR_FALLBACK, to check if a
  1056. * certain font supports all the characters in the string.
  1057. *
  1058. * Return value: The number of unknown glyphs in @layout.
  1059. *
  1060. * Since: 1.16
  1061. */
  1062. int
  1063. pango_layout_get_unknown_glyphs_count (PangoLayout *layout)
  1064. {
  1065. PangoLayoutLine *line;
  1066. PangoLayoutRun *run;
  1067. GSList *lines_list;
  1068. GSList *runs_list;
  1069. int i, count = 0;
  1070. g_return_val_if_fail (PANGO_IS_LAYOUT (layout), 0);
  1071. pango_layout_check_lines (layout);
  1072. if (layout->unknown_glyphs_count >= 0)
  1073. return layout->unknown_glyphs_count;
  1074. lines_list = layout->lines;
  1075. while (lines_list)
  1076. {
  1077. line = lines_list->data;
  1078. runs_list = line->runs;
  1079. while (runs_list)
  1080. {
  1081. run = runs_list->data;
  1082. for (i = 0; i < run->glyphs->num_glyphs; i++)
  1083. {
  1084. if (run->glyphs->glyphs[i].glyph & PANGO_GLYPH_UNKNOWN_FLAG)
  1085. count++;
  1086. }
  1087. runs_list = runs_list->next;
  1088. }
  1089. lines_list = lines_list->next;
  1090. }
  1091. layout->unknown_glyphs_count = count;
  1092. return count;
  1093. }
  1094. static void
  1095. check_context_changed (PangoLayout *layout)
  1096. {
  1097. guint old_serial = layout->context_serial;
  1098. layout->context_serial = pango_context_get_serial (layout->context);
  1099. if (old_serial != layout->context_serial)
  1100. pango_layout_context_changed (layout);
  1101. }
  1102. static void
  1103. layout_changed (PangoLayout *layout)
  1104. {
  1105. layout->serial++;
  1106. if (layout->serial == 0)
  1107. layout->serial++;
  1108. pango_layout_clear_lines (layout);
  1109. }
  1110. /**
  1111. * pango_layout_context_changed:
  1112. * @layout: a #PangoLayout
  1113. *
  1114. * Forces recomputation of any state in the #PangoLayout that
  1115. * might depend on the layout's context. This function should
  1116. * be called if you make changes to the context subsequent
  1117. * to creating the layout.
  1118. **/
  1119. void
  1120. pango_layout_context_changed (PangoLayout *layout)
  1121. {
  1122. g_return_if_fail (PANGO_IS_LAYOUT (layout));
  1123. layout_changed (layout);
  1124. layout->tab_width = -1;
  1125. }
  1126. /**
  1127. * pango_layout_get_serial:
  1128. * @layout: a #PangoLayout
  1129. *
  1130. * Returns the current serial number of @layout. The serial number is
  1131. * initialized to an small number larger than zero when a new layout
  1132. * is created and is increased whenever the layout is changed using any
  1133. * of the setter functions, or the #PangoContext it uses has changed.
  1134. * The serial may wrap, but will never have the value 0. Since it
  1135. * can wrap, never compare it with "less than", always use "not equals".
  1136. *
  1137. * This can be used to automatically detect changes to a #PangoLayout, and
  1138. * is useful for example to decide whether a layout needs redrawing.
  1139. * To force the serial to be increased, use pango_layout_context_changed().
  1140. *
  1141. * Return value: The current serial number of @layout.
  1142. *
  1143. * Since: 1.32.4
  1144. **/
  1145. guint
  1146. pango_layout_get_serial (PangoLayout *layout)
  1147. {
  1148. check_context_changed (layout);
  1149. return layout->serial;
  1150. }
  1151. /**
  1152. * pango_layout_get_log_attrs:
  1153. * @layout: a #PangoLayout
  1154. * @attrs: (out)(array length=n_attrs)(transfer container):
  1155. * location to store a pointer to an array of logical attributes
  1156. * This value must be freed with g_free().
  1157. * @n_attrs: (out): location to store the number of the attributes in the
  1158. * array. (The stored value will be one more than the total number
  1159. * of characters in the layout, since there need to be attributes
  1160. * corresponding to both the position before the first character
  1161. * and the position after the last character.)
  1162. *
  1163. * Retrieves an array of logical attributes for each character in
  1164. * the @layout.
  1165. **/
  1166. void
  1167. pango_layout_get_log_attrs (PangoLayout *layout,
  1168. PangoLogAttr **attrs,
  1169. gint *n_attrs)
  1170. {
  1171. g_return_if_fail (layout != NULL);
  1172. pango_layout_check_lines (layout);
  1173. if (attrs)
  1174. {
  1175. *attrs = g_new (PangoLogAttr, layout->n_chars + 1);
  1176. memcpy (*attrs, layout->log_attrs, sizeof(PangoLogAttr) * (layout->n_chars + 1));
  1177. }
  1178. if (n_attrs)
  1179. *n_attrs = layout->n_chars + 1;
  1180. }
  1181. /**
  1182. * pango_layout_get_log_attrs_readonly:
  1183. * @layout: a #PangoLayout
  1184. * @n_attrs: (out): location to store the number of the attributes in
  1185. * the array
  1186. *
  1187. * Retrieves an array of logical attributes for each character in
  1188. * the @layout.
  1189. *
  1190. * This is a faster alternative to pango_layout_get_log_attrs().
  1191. * The returned array is part of @layout and must not be modified.
  1192. * Modifying the layout will invalidate the returned array.
  1193. *
  1194. * The number of attributes returned in @n_attrs will be one more
  1195. * than the total number of characters in the layout, since there
  1196. * need to be attributes corresponding to both the position before
  1197. * the first character and the position after the last character.
  1198. *
  1199. * Returns: (array length=n_attrs): an array of logical attributes
  1200. *
  1201. * Since: 1.30
  1202. */
  1203. const PangoLogAttr *
  1204. pango_layout_get_log_attrs_readonly (PangoLayout *layout,
  1205. gint *n_attrs)
  1206. {
  1207. if (n_attrs)
  1208. *n_attrs = 0;
  1209. g_return_val_if_fail (layout != NULL, NULL);
  1210. pango_layout_check_lines (layout);
  1211. if (n_attrs)
  1212. *n_attrs = layout->n_chars + 1;
  1213. return layout->log_attrs;
  1214. }
  1215. /**
  1216. * pango_layout_get_line_count:
  1217. * @layout: #PangoLayout
  1218. *
  1219. * Retrieves the count of lines for the @layout.
  1220. *
  1221. * Return value: the line count.
  1222. **/
  1223. int
  1224. pango_layout_get_line_count (PangoLayout *layout)
  1225. {
  1226. g_return_val_if_fail (layout != NULL, 0);
  1227. pango_layout_check_lines (layout);
  1228. return layout->line_count;
  1229. }
  1230. /**
  1231. * pango_layout_get_lines:
  1232. * @layout: a #PangoLayout
  1233. *
  1234. * Returns the lines of the @layout as a list.
  1235. *
  1236. * Use the faster pango_layout_get_lines_readonly() if you do not plan
  1237. * to modify the contents of the lines (glyphs, glyph widths, etc.).
  1238. *
  1239. * Return value: (element-type Pango.LayoutLine) (transfer none): a #GSList containing
  1240. * the lines in the layout. This points to internal data of the #PangoLayout
  1241. * and must be used with care. It will become invalid on any change to the layout's
  1242. * text or properties.
  1243. **/
  1244. GSList *
  1245. pango_layout_get_lines (PangoLayout *layout)
  1246. {
  1247. pango_layout_check_lines (layout);
  1248. if (layout->lines)
  1249. {
  1250. GSList *tmp_list = layout->lines;
  1251. while (tmp_list)
  1252. {
  1253. PangoLayoutLine *line = tmp_list->data;
  1254. tmp_list = tmp_list->next;
  1255. pango_layout_line_leaked (line);
  1256. }
  1257. }
  1258. return layout->lines;
  1259. }
  1260. /**
  1261. * pango_layout_get_lines_readonly:
  1262. * @layout: a #PangoLayout
  1263. *
  1264. * Returns the lines of the @layout as a list.
  1265. *
  1266. * This is a faster alternative to pango_layout_get_lines(),
  1267. * but the user is not expected
  1268. * to modify the contents of the lines (glyphs, glyph widths, etc.).
  1269. *
  1270. * Return value: (element-type Pango.LayoutLine) (transfer none): a #GSList containing
  1271. * the lines in the layout. This points to internal data of the #PangoLayout and
  1272. * must be used with care. It will become invalid on any change to the layout's
  1273. * text or properties. No changes should be made to the lines.
  1274. *
  1275. * Since: 1.16
  1276. **/
  1277. GSList *
  1278. pango_layout_get_lines_readonly (PangoLayout *layout)
  1279. {
  1280. pango_layout_check_lines (layout);
  1281. return layout->lines;
  1282. }
  1283. /**
  1284. * pango_layout_get_line:
  1285. * @layout: a #PangoLayout
  1286. * @line: the index of a line, which must be between 0 and
  1287. * <literal>pango_layout_get_line_count(layout) - 1</literal>, inclusive.
  1288. *
  1289. * Retrieves a particular line from a #PangoLayout.
  1290. *
  1291. * Use the faster pango_layout_get_line_readonly() if you do not plan
  1292. * to modify the contents of the line (glyphs, glyph widths, etc.).
  1293. *
  1294. * Return value: (transfer none) (nullable): the requested
  1295. * #PangoLayoutLine, or %NULL if the index is out of
  1296. * range. This layout line can be ref'ed and retained,
  1297. * but will become invalid if changes are made to the
  1298. * #PangoLayout.
  1299. **/
  1300. PangoLayoutLine *
  1301. pango_layout_get_line (PangoLayout *layout,
  1302. int line)
  1303. {
  1304. GSList *list_item;
  1305. g_return_val_if_fail (layout != NULL, NULL);
  1306. if (line < 0)
  1307. return NULL;
  1308. pango_layout_check_lines (layout);
  1309. list_item = g_slist_nth (layout->lines, line);
  1310. if (list_item)
  1311. {
  1312. PangoLayoutLine *line = list_item->data;
  1313. pango_layout_line_leaked (line);
  1314. return line;
  1315. }
  1316. return NULL;
  1317. }
  1318. /**
  1319. * pango_layout_get_line_readonly:
  1320. * @layout: a #PangoLayout
  1321. * @line: the index of a line, which must be between 0 and
  1322. * <literal>pango_layout_get_line_count(layout) - 1</literal>, inclusive.
  1323. *
  1324. * Retrieves a particular line from a #PangoLayout.
  1325. *
  1326. * This is a faster alternative to pango_layout_get_line(),
  1327. * but the user is not expected
  1328. * to modify the contents of the line (glyphs, glyph widths, etc.).
  1329. *
  1330. * Return value: (transfer none) (nullable): the requested
  1331. * #PangoLayoutLine, or %NULL if the index is out of
  1332. * range. This layout line can be ref'ed and retained,
  1333. * but will become invalid if changes are made to the
  1334. * #PangoLayout. No changes should be made to the line.
  1335. *
  1336. * Since: 1.16
  1337. **/
  1338. PangoLayoutLine *
  1339. pango_layout_get_line_readonly (PangoLayout *layout,
  1340. int line)
  1341. {
  1342. GSList *list_item;
  1343. g_return_val_if_fail (layout != NULL, NULL);
  1344. if (line < 0)
  1345. return NULL;
  1346. pango_layout_check_lines (layout);
  1347. list_item = g_slist_nth (layout->lines, line);
  1348. if (list_item)
  1349. {
  1350. PangoLayoutLine *line = list_item->data;
  1351. return line;
  1352. }
  1353. return NULL;
  1354. }
  1355. /**
  1356. * pango_layout_line_index_to_x:
  1357. * @line: a #PangoLayoutLine
  1358. * @index_: byte offset of a grapheme within the layout
  1359. * @trailing: an integer indicating the edge of the grapheme to retrieve
  1360. * the position of. If > 0, the trailing edge of the grapheme,
  1361. * if 0, the leading of the grapheme.
  1362. * @x_pos: (out): location to store the x_offset (in Pango unit)
  1363. *
  1364. * Converts an index within a line to a X position.
  1365. *
  1366. **/
  1367. void
  1368. pango_layout_line_index_to_x (PangoLayoutLine *line,
  1369. int index,
  1370. int trailing,
  1371. int *x_pos)
  1372. {
  1373. PangoLayout *layout = line->layout;
  1374. GSList *run_list = line->runs;
  1375. int width = 0;
  1376. while (run_list)
  1377. {
  1378. PangoLayoutRun *run = run_list->data;
  1379. ItemProperties properties;
  1380. pango_layout_get_item_properties (run->item, &properties);
  1381. if (run->item->offset <= index && run->item->offset + run->item->length > index)
  1382. {
  1383. int offset = g_utf8_pointer_to_offset (layout->text, layout->text + index);
  1384. if (trailing)
  1385. {
  1386. while (index < line->start_index + line->length &&
  1387. offset + 1 < layout->n_chars &&
  1388. !layout->log_attrs[offset + 1].is_cursor_position)
  1389. {
  1390. offset++;
  1391. index = g_utf8_next_char (layout->text + index) - layout->text;
  1392. }
  1393. }
  1394. else
  1395. {
  1396. while (index > line->start_index &&
  1397. !layout->log_attrs[offset].is_cursor_position)
  1398. {
  1399. offset--;
  1400. index = g_utf8_prev_char (layout->text + index) - layout->text;
  1401. }
  1402. }
  1403. pango_glyph_string_index_to_x (run->glyphs,
  1404. layout->text + run->item->offset,
  1405. run->item->length,
  1406. &run->item->analysis,
  1407. index - run->item->offset, trailing, x_pos);
  1408. if (x_pos)
  1409. *x_pos += width;
  1410. return;
  1411. }
  1412. width += pango_glyph_string_get_width (run->glyphs);
  1413. run_list = run_list->next;
  1414. }
  1415. if (x_pos)
  1416. *x_pos = width;
  1417. }
  1418. static PangoLayoutLine *
  1419. pango_layout_index_to_line (PangoLayout *layout,
  1420. int index,
  1421. int *line_nr,
  1422. PangoLayoutLine **line_before,
  1423. PangoLayoutLine **line_after)
  1424. {
  1425. GSList *tmp_list;
  1426. GSList *line_list;
  1427. PangoLayoutLine *line = NULL;
  1428. PangoLayoutLine *prev_line = NULL;
  1429. int i = -1;
  1430. line_list = tmp_list = layout->lines;
  1431. while (tmp_list)
  1432. {
  1433. PangoLayoutLine *tmp_line = tmp_list->data;
  1434. if (tmp_line->start_index > index)
  1435. break; /* index was in paragraph delimiters */
  1436. prev_line = line;
  1437. line = tmp_line;
  1438. line_list = tmp_list;
  1439. i++;
  1440. if (line->start_index + line->length > index)
  1441. break;
  1442. tmp_list = tmp_list->next;
  1443. }
  1444. if (line_nr)
  1445. *line_nr = i;
  1446. if (line_before)
  1447. *line_before = prev_line;
  1448. if (line_after)
  1449. *line_after = (line_list && line_list->next) ? line_list->next->data : NULL;
  1450. return line;
  1451. }
  1452. static PangoLayoutLine *
  1453. pango_layout_index_to_line_and_extents (PangoLayout *layout,
  1454. int index,
  1455. PangoRectangle *line_rect)
  1456. {
  1457. PangoLayoutIter iter;
  1458. PangoLayoutLine *line = NULL;
  1459. _pango_layout_get_iter (layout, &iter);
  1460. if (!ITER_IS_INVALID (&iter))
  1461. while (TRUE)
  1462. {
  1463. PangoLayoutLine *tmp_line = _pango_layout_iter_get_line (&iter);
  1464. if (tmp_line->start_index > index)
  1465. break; /* index was in paragraph delimiters */
  1466. line = tmp_line;
  1467. pango_layout_iter_get_line_extents (&iter, NULL, line_rect);
  1468. if (line->start_index + line->length > index)
  1469. break;
  1470. if (!pango_layout_iter_next_line (&iter))
  1471. break; /* Use end of last line */
  1472. }
  1473. _pango_layout_iter_destroy (&iter);
  1474. return line;
  1475. }
  1476. /**
  1477. * pango_layout_index_to_line_x:
  1478. * @layout: a #PangoLayout
  1479. * @index_: the byte index of a grapheme within the layout.
  1480. * @trailing: an integer indicating the edge of the grapheme to retrieve the
  1481. * position of. If > 0, the trailing edge of the grapheme, if 0,
  1482. * the leading of the grapheme.
  1483. * @line: (out) (allow-none): location to store resulting line index. (which will
  1484. * between 0 and pango_layout_get_line_count(layout) - 1), or %NULL
  1485. * @x_pos: (out) (allow-none): location to store resulting position within line
  1486. * (%PANGO_SCALE units per device unit), or %NULL
  1487. *
  1488. * Converts from byte @index_ within the @layout to line and X position.
  1489. * (X position is measured from the left edge of the line)
  1490. */
  1491. void
  1492. pango_layout_index_to_line_x (PangoLayout *layout,
  1493. int index,
  1494. gboolean trailing,
  1495. int *line,
  1496. int *x_pos)
  1497. {
  1498. int line_num;
  1499. PangoLayoutLine *layout_line = NULL;
  1500. g_return_if_fail (layout != NULL);
  1501. g_return_if_fail (index >= 0);
  1502. g_return_if_fail (index <= layout->length);
  1503. pango_layout_check_lines (layout);
  1504. layout_line = pango_layout_index_to_line (layout, index,
  1505. &line_num, NULL, NULL);
  1506. if (layout_line)
  1507. {
  1508. /* use end of line if index was in the paragraph delimiters */
  1509. if (index > layout_line->start_index + layout_line->length)
  1510. index = layout_line->start_index + layout_line->length;
  1511. if (line)
  1512. *line = line_num;
  1513. pango_layout_line_index_to_x (layout_line, index, trailing, x_pos);
  1514. }
  1515. else
  1516. {
  1517. if (line)
  1518. *line = -1;
  1519. if (x_pos)
  1520. *x_pos = -1;
  1521. }
  1522. }
  1523. /**
  1524. * pango_layout_move_cursor_visually:
  1525. * @layout: a #PangoLayout.
  1526. * @strong: whether the moving cursor is the strong cursor or the
  1527. * weak cursor. The strong cursor is the cursor corresponding
  1528. * to text insertion in the base direction for the layout.
  1529. * @old_index: the byte index of the grapheme for the old index
  1530. * @old_trailing: if 0, the cursor was at the leading edge of the
  1531. * grapheme indicated by @old_index, if > 0, the cursor
  1532. * was at the trailing edge.
  1533. * @direction: direction to move cursor. A negative
  1534. * value indicates motion to the left.
  1535. * @new_index: (out): location to store the new cursor byte index. A value of -1
  1536. * indicates that the cursor has been moved off the beginning
  1537. * of the layout. A value of %G_MAXINT indicates that
  1538. * the cursor has been moved off the end of the layout.
  1539. * @new_trailing: (out): number of characters to move forward from the
  1540. * location returned for @new_index to get the position
  1541. * where the cursor should be displayed. This allows
  1542. * distinguishing the position at the beginning of one
  1543. * line from the position at the end of the preceding
  1544. * line. @new_index is always on the line where the
  1545. * cursor should be displayed.
  1546. *
  1547. * Computes a new cursor position from an old position and
  1548. * a count of positions to move visually. If @direction is positive,
  1549. * then the new strong cursor position will be one position
  1550. * to the right of the old cursor position. If @direction is negative,
  1551. * then the new strong cursor position will be one position
  1552. * to the left of the old cursor position.
  1553. *
  1554. * In the presence of bidirectional text, the correspondence
  1555. * between logical and visual order will depend on the direction
  1556. * of the current run, and there may be jumps when the cursor
  1557. * is moved off of the end of a run.
  1558. *
  1559. * Motion here is in cursor positions, not in characters, so a
  1560. * single call to pango_layout_move_cursor_visually() may move the
  1561. * cursor over multiple characters when multiple characters combine
  1562. * to form a single grapheme.
  1563. **/
  1564. void
  1565. pango_layout_move_cursor_visually (PangoLayout *layout,
  1566. gboolean strong,
  1567. int old_index,
  1568. int old_trailing,
  1569. int direction,
  1570. int *new_index,
  1571. int *new_trailing)
  1572. {
  1573. PangoLayoutLine *line = NULL;
  1574. PangoLayoutLine *prev_line;
  1575. PangoLayoutLine *next_line;
  1576. int *log2vis_map;
  1577. int *vis2log_map;
  1578. int n_vis;
  1579. int vis_pos, vis_pos_old, log_pos;
  1580. int start_offset;
  1581. gboolean off_start = FALSE;
  1582. gboolean off_end = FALSE;
  1583. g_return_if_fail (layout != NULL);
  1584. g_return_if_fail (old_index >= 0 && old_index <= layout->length);
  1585. g_return_if_fail (old_index < layout->length || old_trailing == 0);
  1586. g_return_if_fail (new_index != NULL);
  1587. g_return_if_fail (new_trailing != NULL);
  1588. direction = (direction >= 0 ? 1 : -1);
  1589. pango_layout_check_lines (layout);
  1590. /* Find the line the old cursor is on */
  1591. line = pango_layout_index_to_line (layout, old_index,
  1592. NULL, &prev

Large files files are truncated, but you can click here to view the full file