1/* poppler-structure.cc: glib interface to poppler
2 *
3 * Copyright (C) 2013 Igalia S.L.
4 * Copyright (C) 2018 Albert Astals Cid <aacid@kde.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22
23#ifndef __GI_SCANNER__
24# include <StructTreeRoot.h>
25# include <StructElement.h>
26# include <GlobalParams.h>
27# include <UnicodeMap.h>
28# include <cmath>
29#endif /* !__GI_SCANNER__ */
30
31#include "poppler.h"
32#include "poppler-private.h"
33#include "poppler-structure-element.h"
34
35/**
36 * SECTION:poppler-structure-element
37 * @short_description: Document structure element.
38 * @title: PopplerStructureElement
39 *
40 * Instances of #PopplerStructureElement are used to describe the structure
41 * of a #PopplerDocument. To access the elements in the structure of the
42 * document, use poppler_structure_element_iter_new() to obtain an iterator
43 * for the top-level #PopplerStructureElement, and then use the
44 * #PopplerStructureElementIter methods to traverse the structure tree.
45 */
46
47typedef struct _PopplerStructureElementClass
48{
49 GObjectClass parent_class;
50} PopplerStructureElementClass;
51
52G_DEFINE_TYPE(PopplerStructureElement, poppler_structure_element, G_TYPE_OBJECT)
53
54static PopplerStructureElement *_poppler_structure_element_new(PopplerDocument *document, const StructElement *element)
55{
56 PopplerStructureElement *poppler_structure_element;
57
58 g_assert(POPPLER_IS_DOCUMENT(document));
59 g_assert(element);
60
61 poppler_structure_element = (PopplerStructureElement *)g_object_new(POPPLER_TYPE_STRUCTURE_ELEMENT, first_property_name: nullptr, NULL);
62 poppler_structure_element->document = (PopplerDocument *)g_object_ref(document);
63 poppler_structure_element->elem = element;
64
65 return poppler_structure_element;
66}
67
68static void poppler_structure_element_init(PopplerStructureElement *poppler_structure_element) { }
69
70static void poppler_structure_element_finalize(GObject *object)
71{
72 PopplerStructureElement *poppler_structure_element = POPPLER_STRUCTURE_ELEMENT(object);
73
74 /* poppler_structure_element->elem is owned by the StructTreeRoot */
75 g_object_unref(object: poppler_structure_element->document);
76
77 G_OBJECT_CLASS(poppler_structure_element_parent_class)->finalize(object);
78}
79
80static void poppler_structure_element_class_init(PopplerStructureElementClass *klass)
81{
82 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
83 gobject_class->finalize = poppler_structure_element_finalize;
84}
85
86/**
87 * poppler_structure_element_get_kind:
88 * @poppler_structure_element: A #PopplerStructureElement
89 *
90 * Return value: A #PopplerStructureElementKind value.
91 *
92 * Since: 0.26
93 */
94PopplerStructureElementKind poppler_structure_element_get_kind(PopplerStructureElement *poppler_structure_element)
95{
96 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), POPPLER_STRUCTURE_ELEMENT_CONTENT);
97 g_return_val_if_fail(poppler_structure_element->elem != nullptr, POPPLER_STRUCTURE_ELEMENT_CONTENT);
98
99 switch (poppler_structure_element->elem->getType()) {
100 case StructElement::MCID:
101 return POPPLER_STRUCTURE_ELEMENT_CONTENT;
102 case StructElement::OBJR:
103 return POPPLER_STRUCTURE_ELEMENT_OBJECT_REFERENCE;
104 case StructElement::Document:
105 return POPPLER_STRUCTURE_ELEMENT_DOCUMENT;
106 case StructElement::Part:
107 return POPPLER_STRUCTURE_ELEMENT_PART;
108 case StructElement::Art:
109 return POPPLER_STRUCTURE_ELEMENT_ARTICLE;
110 case StructElement::Sect:
111 return POPPLER_STRUCTURE_ELEMENT_SECTION;
112 case StructElement::Div:
113 return POPPLER_STRUCTURE_ELEMENT_DIV;
114 case StructElement::Span:
115 return POPPLER_STRUCTURE_ELEMENT_SPAN;
116 case StructElement::Quote:
117 return POPPLER_STRUCTURE_ELEMENT_QUOTE;
118 case StructElement::Note:
119 return POPPLER_STRUCTURE_ELEMENT_NOTE;
120 case StructElement::Reference:
121 return POPPLER_STRUCTURE_ELEMENT_REFERENCE;
122 case StructElement::BibEntry:
123 return POPPLER_STRUCTURE_ELEMENT_BIBENTRY;
124 case StructElement::Code:
125 return POPPLER_STRUCTURE_ELEMENT_CODE;
126 case StructElement::Link:
127 return POPPLER_STRUCTURE_ELEMENT_LINK;
128 case StructElement::Annot:
129 return POPPLER_STRUCTURE_ELEMENT_ANNOT;
130 case StructElement::BlockQuote:
131 return POPPLER_STRUCTURE_ELEMENT_BLOCKQUOTE;
132 case StructElement::Caption:
133 return POPPLER_STRUCTURE_ELEMENT_CAPTION;
134 case StructElement::NonStruct:
135 return POPPLER_STRUCTURE_ELEMENT_NONSTRUCT;
136 case StructElement::TOC:
137 return POPPLER_STRUCTURE_ELEMENT_TOC;
138 case StructElement::TOCI:
139 return POPPLER_STRUCTURE_ELEMENT_TOC_ITEM;
140 case StructElement::Index:
141 return POPPLER_STRUCTURE_ELEMENT_INDEX;
142 case StructElement::Private:
143 return POPPLER_STRUCTURE_ELEMENT_PRIVATE;
144 case StructElement::P:
145 return POPPLER_STRUCTURE_ELEMENT_PARAGRAPH;
146 case StructElement::H:
147 return POPPLER_STRUCTURE_ELEMENT_HEADING;
148 case StructElement::H1:
149 return POPPLER_STRUCTURE_ELEMENT_HEADING_1;
150 case StructElement::H2:
151 return POPPLER_STRUCTURE_ELEMENT_HEADING_2;
152 case StructElement::H3:
153 return POPPLER_STRUCTURE_ELEMENT_HEADING_3;
154 case StructElement::H4:
155 return POPPLER_STRUCTURE_ELEMENT_HEADING_4;
156 case StructElement::H5:
157 return POPPLER_STRUCTURE_ELEMENT_HEADING_5;
158 case StructElement::H6:
159 return POPPLER_STRUCTURE_ELEMENT_HEADING_6;
160 case StructElement::L:
161 return POPPLER_STRUCTURE_ELEMENT_LIST;
162 case StructElement::LI:
163 return POPPLER_STRUCTURE_ELEMENT_LIST_ITEM;
164 case StructElement::Lbl:
165 return POPPLER_STRUCTURE_ELEMENT_LIST_LABEL;
166 case StructElement::LBody:
167 return POPPLER_STRUCTURE_ELEMENT_LIST_BODY;
168 case StructElement::Table:
169 return POPPLER_STRUCTURE_ELEMENT_TABLE;
170 case StructElement::TR:
171 return POPPLER_STRUCTURE_ELEMENT_TABLE_ROW;
172 case StructElement::TH:
173 return POPPLER_STRUCTURE_ELEMENT_TABLE_HEADING;
174 case StructElement::TD:
175 return POPPLER_STRUCTURE_ELEMENT_TABLE_DATA;
176 case StructElement::THead:
177 return POPPLER_STRUCTURE_ELEMENT_TABLE_HEADER;
178 case StructElement::TFoot:
179 return POPPLER_STRUCTURE_ELEMENT_TABLE_FOOTER;
180 case StructElement::TBody:
181 return POPPLER_STRUCTURE_ELEMENT_TABLE_BODY;
182 case StructElement::Ruby:
183 return POPPLER_STRUCTURE_ELEMENT_RUBY;
184 case StructElement::RB:
185 return POPPLER_STRUCTURE_ELEMENT_RUBY_BASE_TEXT;
186 case StructElement::RT:
187 return POPPLER_STRUCTURE_ELEMENT_RUBY_ANNOT_TEXT;
188 case StructElement::RP:
189 return POPPLER_STRUCTURE_ELEMENT_RUBY_PUNCTUATION;
190 case StructElement::Warichu:
191 return POPPLER_STRUCTURE_ELEMENT_WARICHU;
192 case StructElement::WT:
193 return POPPLER_STRUCTURE_ELEMENT_WARICHU_TEXT;
194 case StructElement::WP:
195 return POPPLER_STRUCTURE_ELEMENT_WARICHU_PUNCTUATION;
196 case StructElement::Figure:
197 return POPPLER_STRUCTURE_ELEMENT_FIGURE;
198 case StructElement::Formula:
199 return POPPLER_STRUCTURE_ELEMENT_FORMULA;
200 case StructElement::Form:
201 return POPPLER_STRUCTURE_ELEMENT_FORM;
202
203 /* There should never be elements of type StructElement::Unknown */
204 case StructElement::Unknown:
205 g_assert_not_reached();
206 }
207
208 g_assert_not_reached();
209 return POPPLER_STRUCTURE_ELEMENT_CONTENT;
210}
211
212template<typename EnumType>
213struct EnumNameValue
214{
215 const gchar *name;
216 EnumType value;
217
218 static const EnumNameValue<EnumType> values[];
219 static const Attribute::Type attribute_type;
220};
221
222#define ENUM_VALUES(E, A) \
223 template<> \
224 const Attribute::Type EnumNameValue<E>::attribute_type = Attribute::A; \
225 template<> \
226 const EnumNameValue<E> EnumNameValue<E>::values[] =
227
228ENUM_VALUES(PopplerStructurePlacement, Placement) { { .name: "Block", .value: POPPLER_STRUCTURE_PLACEMENT_BLOCK }, { .name: "Inline", .value: POPPLER_STRUCTURE_PLACEMENT_INLINE }, { .name: "Before", .value: POPPLER_STRUCTURE_PLACEMENT_BEFORE },
229 { .name: "Start", .value: POPPLER_STRUCTURE_PLACEMENT_START }, { .name: "End", .value: POPPLER_STRUCTURE_PLACEMENT_END }, {} };
230
231ENUM_VALUES(PopplerStructureWritingMode, WritingMode) { { .name: "LrTb", .value: POPPLER_STRUCTURE_WRITING_MODE_LR_TB }, { .name: "RlTb", .value: POPPLER_STRUCTURE_WRITING_MODE_RL_TB }, { .name: "TbRl", .value: POPPLER_STRUCTURE_WRITING_MODE_TB_RL }, {} };
232
233ENUM_VALUES(PopplerStructureBorderStyle, BorderStyle) { { .name: "None", .value: POPPLER_STRUCTURE_BORDER_STYLE_NONE }, { .name: "Hidden", .value: POPPLER_STRUCTURE_BORDER_STYLE_HIDDEN },
234 { .name: "Dotted", .value: POPPLER_STRUCTURE_BORDER_STYLE_DOTTED }, { .name: "Dashed", .value: POPPLER_STRUCTURE_BORDER_STYLE_DASHED },
235 { .name: "Solid", .value: POPPLER_STRUCTURE_BORDER_STYLE_SOLID }, { .name: "Double", .value: POPPLER_STRUCTURE_BORDER_STYLE_DOUBLE },
236 { .name: "Groove", .value: POPPLER_STRUCTURE_BORDER_STYLE_GROOVE }, { .name: "Inset", .value: POPPLER_STRUCTURE_BORDER_STYLE_INSET },
237 { .name: "Outset", .value: POPPLER_STRUCTURE_BORDER_STYLE_OUTSET }, {} };
238
239ENUM_VALUES(PopplerStructureTextAlign,
240 TextAlign) { { .name: "Start", .value: POPPLER_STRUCTURE_TEXT_ALIGN_START }, { .name: "Center", .value: POPPLER_STRUCTURE_TEXT_ALIGN_CENTER }, { .name: "End", .value: POPPLER_STRUCTURE_TEXT_ALIGN_END }, { .name: "Justify", .value: POPPLER_STRUCTURE_TEXT_ALIGN_JUSTIFY }, {} };
241
242ENUM_VALUES(PopplerStructureBlockAlign,
243 BlockAlign) { { .name: "Before", .value: POPPLER_STRUCTURE_BLOCK_ALIGN_BEFORE }, { .name: "Middle", .value: POPPLER_STRUCTURE_BLOCK_ALIGN_MIDDLE }, { .name: "After", .value: POPPLER_STRUCTURE_BLOCK_ALIGN_AFTER }, { .name: "Justify", .value: POPPLER_STRUCTURE_BLOCK_ALIGN_JUSTIFY }, {} };
244
245ENUM_VALUES(PopplerStructureInlineAlign, InlineAlign) { { .name: "Start", .value: POPPLER_STRUCTURE_INLINE_ALIGN_START }, { .name: "Center", .value: POPPLER_STRUCTURE_INLINE_ALIGN_CENTER }, { .name: "End", .value: POPPLER_STRUCTURE_INLINE_ALIGN_END }, {} };
246
247ENUM_VALUES(PopplerStructureTextDecoration, TextDecorationType) { { .name: "None", .value: POPPLER_STRUCTURE_TEXT_DECORATION_NONE },
248 { .name: "Underline", .value: POPPLER_STRUCTURE_TEXT_DECORATION_UNDERLINE },
249 { .name: "Overline", .value: POPPLER_STRUCTURE_TEXT_DECORATION_OVERLINE },
250 { .name: "LineThrough", .value: POPPLER_STRUCTURE_TEXT_DECORATION_LINETHROUGH },
251 {} };
252
253ENUM_VALUES(PopplerStructureRubyAlign, RubyAlign) { { .name: "Start", .value: POPPLER_STRUCTURE_RUBY_ALIGN_START }, { .name: "Center", .value: POPPLER_STRUCTURE_RUBY_ALIGN_CENTER }, { .name: "End", .value: POPPLER_STRUCTURE_RUBY_ALIGN_END },
254 { .name: "Justify", .value: POPPLER_STRUCTURE_RUBY_ALIGN_JUSTIFY }, { .name: "Distribute", .value: POPPLER_STRUCTURE_RUBY_ALIGN_DISTRIBUTE }, {} };
255
256ENUM_VALUES(PopplerStructureRubyPosition, RubyPosition) {
257 { .name: "Before", .value: POPPLER_STRUCTURE_RUBY_POSITION_BEFORE }, { .name: "After", .value: POPPLER_STRUCTURE_RUBY_POSITION_AFTER }, { .name: "Warichu", .value: POPPLER_STRUCTURE_RUBY_POSITION_WARICHU }, { .name: "Inline", .value: POPPLER_STRUCTURE_RUBY_POSITION_INLINE }, {}
258};
259
260ENUM_VALUES(PopplerStructureGlyphOrientation, GlyphOrientationVertical) { { .name: "Auto", .value: POPPLER_STRUCTURE_GLYPH_ORIENTATION_AUTO }, { .name: "90", .value: POPPLER_STRUCTURE_GLYPH_ORIENTATION_90 },
261 { .name: "180", .value: POPPLER_STRUCTURE_GLYPH_ORIENTATION_180 }, { .name: "270", .value: POPPLER_STRUCTURE_GLYPH_ORIENTATION_270 },
262 { .name: "360", .value: POPPLER_STRUCTURE_GLYPH_ORIENTATION_0 }, { .name: "-90", .value: POPPLER_STRUCTURE_GLYPH_ORIENTATION_270 },
263 { .name: "-180", .value: POPPLER_STRUCTURE_GLYPH_ORIENTATION_180 }, {} };
264
265ENUM_VALUES(PopplerStructureListNumbering, ListNumbering) { { .name: "None", .value: POPPLER_STRUCTURE_LIST_NUMBERING_NONE },
266 { .name: "Disc", .value: POPPLER_STRUCTURE_LIST_NUMBERING_DISC },
267 { .name: "Circle", .value: POPPLER_STRUCTURE_LIST_NUMBERING_CIRCLE },
268 { .name: "Square", .value: POPPLER_STRUCTURE_LIST_NUMBERING_SQUARE },
269 { .name: "Decimal", .value: POPPLER_STRUCTURE_LIST_NUMBERING_DECIMAL },
270 { .name: "UpperRoman", .value: POPPLER_STRUCTURE_LIST_NUMBERING_UPPER_ROMAN },
271 { .name: "LowerRoman", .value: POPPLER_STRUCTURE_LIST_NUMBERING_LOWER_ROMAN },
272 { .name: "UpperAlpha", .value: POPPLER_STRUCTURE_LIST_NUMBERING_UPPER_ALPHA },
273 { .name: "LowerAlpha", .value: POPPLER_STRUCTURE_LIST_NUMBERING_LOWER_ALPHA },
274 {} };
275
276ENUM_VALUES(PopplerStructureFormRole,
277 Role) { { .name: "rb", .value: POPPLER_STRUCTURE_FORM_ROLE_RADIO_BUTTON }, { .name: "cb", .value: POPPLER_STRUCTURE_FORM_ROLE_CHECKBOX }, { .name: "pb", .value: POPPLER_STRUCTURE_FORM_ROLE_PUSH_BUTTON }, { .name: "tv", .value: POPPLER_STRUCTURE_FORM_ROLE_TEXT_VALUE }, {} };
278
279ENUM_VALUES(PopplerStructureFormState, checked) { { .name: "on", .value: POPPLER_STRUCTURE_FORM_STATE_ON }, { .name: "off", .value: POPPLER_STRUCTURE_FORM_STATE_OFF }, { .name: "neutral", .value: POPPLER_STRUCTURE_FORM_STATE_NEUTRAL }, {} };
280
281ENUM_VALUES(PopplerStructureTableScope, Scope) { { .name: "Row", .value: POPPLER_STRUCTURE_TABLE_SCOPE_ROW }, { .name: "Column", .value: POPPLER_STRUCTURE_TABLE_SCOPE_COLUMN }, { .name: "Both", .value: POPPLER_STRUCTURE_TABLE_SCOPE_BOTH }, {} };
282
283#undef ENUM_VALUES
284
285template<typename EnumType>
286static EnumType name_to_enum(const Object *name_value)
287{
288 /*
289 * Non-NULL names must always be valid because Poppler
290 * discards the invalid attributes when parsing them.
291 */
292 g_assert(name_value != nullptr);
293
294 for (const EnumNameValue<EnumType> *item = EnumNameValue<EnumType>::values; item->name; item++) {
295 if (name_value->isName(item->name)) {
296 return item->value;
297 }
298 }
299
300 g_assert_not_reached();
301 return static_cast<EnumType>(-1);
302}
303
304template<typename EnumType>
305static EnumType attr_to_enum(PopplerStructureElement *poppler_structure_element)
306{
307 const Attribute *attr = poppler_structure_element->elem->findAttribute(attributeType: EnumNameValue<EnumType>::attribute_type, inherit: true);
308 return name_to_enum<EnumType>((attr != nullptr) ? attr->getValue() : Attribute::getDefaultValue(type: EnumNameValue<EnumType>::attribute_type));
309}
310
311static inline const Object *attr_value_or_default(PopplerStructureElement *poppler_structure_element, Attribute::Type attribute_type)
312{
313 const Attribute *attr = poppler_structure_element->elem->findAttribute(attributeType: attribute_type, inherit: true);
314 return attr ? attr->getValue() : Attribute::getDefaultValue(type: attribute_type);
315}
316
317/**
318 * poppler_structure_element_get_page:
319 * @poppler_structure_element: A #PopplerStructureElement
320 *
321 * Obtains the page number in which the element is contained.
322 *
323 * Return value: Number of the page that contains the element, of
324 * <code>-1</code> if not defined.
325 *
326 * Since: 0.26
327 */
328gint poppler_structure_element_get_page(PopplerStructureElement *poppler_structure_element)
329{
330 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), -1);
331 g_return_val_if_fail(poppler_structure_element->elem != nullptr, -1);
332
333 Ref ref;
334 if (poppler_structure_element->elem->getPageRef(ref)) {
335 return poppler_structure_element->document->doc->findPage(ref) - 1;
336 }
337
338 return -1;
339}
340
341/**
342 * poppler_structure_element_is_content:
343 * @poppler_structure_element: A #PopplerStructureElement
344 *
345 * Checks whether an element is actual document content.
346 *
347 * Return value: %TRUE if the element is content, or %FALSE otherwise.
348 *
349 * Since: 0.26
350 */
351gboolean poppler_structure_element_is_content(PopplerStructureElement *poppler_structure_element)
352{
353 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
354 g_return_val_if_fail(poppler_structure_element->elem != nullptr, FALSE);
355
356 return poppler_structure_element->elem->isContent();
357}
358
359/**
360 * poppler_structure_element_is_inline:
361 * @poppler_structure_element: A #PopplerStructureElement
362 *
363 * Checks whether an element is an inline element.
364 *
365 * Return value: %TRUE if the element is an inline element, or %FALSE otherwise.
366 *
367 * Since: 0.26
368 */
369gboolean poppler_structure_element_is_inline(PopplerStructureElement *poppler_structure_element)
370{
371 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
372 g_return_val_if_fail(poppler_structure_element->elem != nullptr, FALSE);
373
374 return poppler_structure_element->elem->isInline();
375}
376
377/**
378 * poppler_structure_element_is_block:
379 * @poppler_structure_element: A #PopplerStructureElement
380 *
381 * Checks whether an element is a block element.
382 *
383 * Return value: %TRUE if the element is a block element, or %FALSE otherwise.
384 *
385 * Since: 0.26
386 */
387gboolean poppler_structure_element_is_block(PopplerStructureElement *poppler_structure_element)
388{
389 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
390 g_return_val_if_fail(poppler_structure_element->elem != nullptr, FALSE);
391
392 return poppler_structure_element->elem->isBlock();
393}
394
395/**
396 * poppler_structure_element_is_grouping:
397 * @poppler_structure_element: A #PopplerStructureElement
398 *
399 * Checks whether an element is a grouping element.
400 *
401 * Return value: %TRUE if the element is a grouping element, %FALSE
402 * otherwise.
403 *
404 * Since: 0.26
405 */
406gboolean poppler_structure_element_is_grouping(PopplerStructureElement *poppler_structure_element)
407{
408 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
409 g_return_val_if_fail(poppler_structure_element->elem != nullptr, FALSE);
410
411 return poppler_structure_element->elem->isGrouping();
412}
413
414/**
415 * poppler_structure_element_get_id:
416 * @poppler_structure_element: A #PopplerStructureElement
417 *
418 * Obtains the identifier of an element.
419 *
420 * Return value: (transfer full): The identifier of the element (if
421 * defined), or %NULL.
422 *
423 * Since: 0.26
424 */
425gchar *poppler_structure_element_get_id(PopplerStructureElement *poppler_structure_element)
426{
427 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
428 g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
429
430 const GooString *string = poppler_structure_element->elem->getID();
431 return string ? _poppler_goo_string_to_utf8(s: string) : nullptr;
432}
433
434/**
435 * poppler_structure_element_get_title:
436 * @poppler_structure_element: A #PopplerStructureElement
437 *
438 * Obtains the title of an element.
439 *
440 * Return value: (transfer full): The title of the element, or %NULL.
441 *
442 * Since: 0.26
443 */
444gchar *poppler_structure_element_get_title(PopplerStructureElement *poppler_structure_element)
445{
446 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
447 g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
448
449 const GooString *string = poppler_structure_element->elem->getTitle();
450 return string ? _poppler_goo_string_to_utf8(s: string) : nullptr;
451}
452
453/**
454 * poppler_structure_element_get_abbreviation:
455 * @poppler_structure_element: A #PopplerStructureElement
456 *
457 * Acronyms and abbreviations contained in elements of type
458 * #POPPLER_STRUCTURE_ELEMENT_SPAN may have an associated expanded
459 * text form, which can be retrieved using this function.
460 *
461 * Return value: (transfer full): Text of the expanded abbreviation if the
462 * element text is an abbreviation or acrony, %NULL if not.
463 *
464 * Since: 0.26
465 */
466gchar *poppler_structure_element_get_abbreviation(PopplerStructureElement *poppler_structure_element)
467{
468 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
469 g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
470
471 if (poppler_structure_element->elem->getType() != StructElement::Span) {
472 return nullptr;
473 }
474
475 const GooString *string = poppler_structure_element->elem->getExpandedAbbr();
476 return string ? _poppler_goo_string_to_utf8(s: string) : nullptr;
477}
478
479/**
480 * poppler_structure_element_get_language:
481 * @poppler_structure_element: A #PopplerStructureElement
482 *
483 * Obtains the language and country code for the content in an element,
484 * in two-letter ISO format, e.g. <code>en_ES</code>, or %NULL if not
485 * defined.
486 *
487 * Return value: (transfer full): language and country code, or %NULL.
488 *
489 * Since: 0.26
490 */
491gchar *poppler_structure_element_get_language(PopplerStructureElement *poppler_structure_element)
492{
493 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
494 g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
495
496 const GooString *string = poppler_structure_element->elem->getLanguage();
497 return string ? _poppler_goo_string_to_utf8(s: string) : nullptr;
498}
499
500/**
501 * poppler_structure_element_get_alt_text:
502 * @poppler_structure_element: A #PopplerStructureElement
503 *
504 * Obtains the “alternate” text representation of the element (and its child
505 * elements). This is mostly used for non-text elements like images and
506 * figures, to specify a textual description of the element.
507 *
508 * Note that for elements containing proper text, the function
509 * poppler_structure_element_get_text() must be used instead.
510 *
511 * Return value: (transfer full): The alternate text representation for the
512 * element, or %NULL if not defined.
513 *
514 * Since: 0.26
515 */
516gchar *poppler_structure_element_get_alt_text(PopplerStructureElement *poppler_structure_element)
517{
518 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
519 g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
520
521 const GooString *string = poppler_structure_element->elem->getAltText();
522 return string ? _poppler_goo_string_to_utf8(s: string) : nullptr;
523}
524
525/**
526 * poppler_structure_element_get_actual_text:
527 * @poppler_structure_element: A #PopplerStructureElement
528 *
529 * Obtains the actual text enclosed by the element (and its child elements).
530 * The actual text is mostly used for non-text elements like images and
531 * figures which <emphasis>do</emphasis> have the graphical appearance of text, like
532 * a logo. For those the actual text is the equivalent text to those
533 * graphical elements which look like text when rendered.
534 *
535 * Note that for elements containing proper text, the function
536 * poppler_structure_element_get_text() must be used instead.
537 *
538 * Return value: (transfer full): The actual text for the element, or %NULL
539 * if not defined.
540 *
541 * Since: 0.26
542 */
543gchar *poppler_structure_element_get_actual_text(PopplerStructureElement *poppler_structure_element)
544{
545 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
546 g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
547
548 const GooString *string = poppler_structure_element->elem->getActualText();
549 return string ? _poppler_goo_string_to_utf8(s: string) : nullptr;
550}
551
552/**
553 * poppler_structure_element_get_text:
554 * @poppler_structure_element: A #PopplerStructureElement
555 * @flags: A #PopplerStructureGetTextFlags value, or
556 * %POPPLER_STRUCTURE_GET_TEXT_NONE to disable all the flags.
557 *
558 * Obtains the text enclosed by an element, or the text enclosed by the
559 * elements in the subtree (including the element itself).
560 *
561 * Return value: (transfer full): A string.
562 *
563 * Since: 0.26
564 */
565gchar *poppler_structure_element_get_text(PopplerStructureElement *poppler_structure_element, PopplerStructureGetTextFlags flags)
566{
567 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
568 g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
569
570 GooString *string = poppler_structure_element->elem->getText(recursive: flags & POPPLER_STRUCTURE_GET_TEXT_RECURSIVE);
571 gchar *result = string ? _poppler_goo_string_to_utf8(s: string) : nullptr;
572 delete string;
573 return result;
574}
575
576struct _PopplerStructureElementIter
577{
578 PopplerDocument *document;
579 union {
580 const StructElement *elem;
581 const StructTreeRoot *root;
582 };
583 gboolean is_root;
584 unsigned index;
585};
586
587G_DEFINE_BOXED_TYPE(PopplerStructureElementIter, poppler_structure_element_iter, poppler_structure_element_iter_copy, poppler_structure_element_iter_free)
588
589/**
590 * poppler_structure_element_iter_copy:
591 * @iter: a #PopplerStructureElementIter
592 *
593 * Creates a new #PopplerStructureElementIter as a copy of @iter. The
594 * returned value must be freed with poppler_structure_element_iter_free().
595 *
596 * Return value: (transfer full): a new #PopplerStructureElementIter
597 *
598 * Since: 0.26
599 */
600PopplerStructureElementIter *poppler_structure_element_iter_copy(PopplerStructureElementIter *iter)
601{
602 PopplerStructureElementIter *new_iter;
603
604 g_return_val_if_fail(iter != nullptr, NULL);
605
606 new_iter = g_slice_dup(PopplerStructureElementIter, iter);
607 new_iter->document = (PopplerDocument *)g_object_ref(new_iter->document);
608
609 return new_iter;
610}
611
612/**
613 * poppler_structure_element_iter_free:
614 * @iter: a #PopplerStructureElementIter
615 *
616 * Frees @iter.
617 *
618 * Since: 0.26
619 */
620void poppler_structure_element_iter_free(PopplerStructureElementIter *iter)
621{
622 if (G_UNLIKELY(iter == nullptr)) {
623 return;
624 }
625
626 g_object_unref(object: iter->document);
627 g_slice_free(PopplerStructureElementIter, iter);
628}
629
630/**
631 * poppler_structure_element_iter_new:
632 * @poppler_document: a #PopplerDocument.
633 *
634 * Returns the root #PopplerStructureElementIter for @document, or %NULL. The
635 * returned value must be freed with poppler_structure_element_iter_free().
636 *
637 * Documents may have an associated structure tree &mdash;mostly, Tagged-PDF
638 * compliant documents&mdash; which can be used to obtain information about
639 * the document structure and its contents. Each node in the tree contains
640 * a #PopplerStructureElement.
641 *
642 * Here is a simple example that walks the whole tree:
643 *
644 * <informalexample><programlisting>
645 * static void
646 * walk_structure (PopplerStructureElementIter *iter)
647 * {
648 * do {
649 * /<!-- -->* Get the element and do something with it *<!-- -->/
650 * PopplerStructureElementIter *child = poppler_structure_element_iter_get_child (iter);
651 * if (child)
652 * walk_structure (child);
653 * poppler_structure_element_iter_free (child);
654 * } while (poppler_structure_element_iter_next (iter));
655 * }
656 * ...
657 * {
658 * iter = poppler_structure_element_iter_new (document);
659 * walk_structure (iter);
660 * poppler_structure_element_iter_free (iter);
661 * }
662 * </programlisting></informalexample>
663 *
664 * Return value: (transfer full): a new #PopplerStructureElementIter, or %NULL if document
665 * doesn't have structure tree.
666 *
667 * Since: 0.26
668 */
669PopplerStructureElementIter *poppler_structure_element_iter_new(PopplerDocument *poppler_document)
670{
671 PopplerStructureElementIter *iter;
672
673 g_return_val_if_fail(POPPLER_IS_DOCUMENT(poppler_document), NULL);
674
675 const StructTreeRoot *root = poppler_document->doc->getStructTreeRoot();
676 if (root == nullptr) {
677 return nullptr;
678 }
679
680 if (root->getNumChildren() == 0) {
681 return nullptr;
682 }
683
684 iter = g_slice_new0(PopplerStructureElementIter);
685 iter->document = (PopplerDocument *)g_object_ref(poppler_document);
686 iter->is_root = TRUE;
687 iter->root = root;
688
689 return iter;
690}
691
692/**
693 * poppler_structure_element_iter_next:
694 * @iter: a #PopplerStructureElementIter
695 *
696 * Sets @iter to point to the next structure element at the current level
697 * of the tree, if valid. See poppler_structure_element_iter_new() for more
698 * information.
699 *
700 * Return value: %TRUE, if @iter was set to the next structure element
701 *
702 * Since: 0.26
703 */
704gboolean poppler_structure_element_iter_next(PopplerStructureElementIter *iter)
705{
706 unsigned elements;
707
708 g_return_val_if_fail(iter != nullptr, FALSE);
709
710 elements = iter->is_root ? iter->root->getNumChildren() : iter->elem->getNumChildren();
711
712 return ++iter->index < elements;
713}
714
715/**
716 * poppler_structure_element_iter_get_element:
717 * @iter: a #PopplerStructureElementIter
718 *
719 * Returns the #PopplerStructureElementIter associated with @iter.
720 *
721 * Return value: (transfer full): a new #PopplerStructureElementIter
722 *
723 * Since: 0.26
724 */
725PopplerStructureElement *poppler_structure_element_iter_get_element(PopplerStructureElementIter *iter)
726{
727 g_return_val_if_fail(iter != nullptr, NULL);
728
729 const StructElement *elem = iter->is_root ? iter->root->getChild(i: iter->index) : iter->elem->getChild(i: iter->index);
730
731 return _poppler_structure_element_new(document: iter->document, element: elem);
732}
733
734/**
735 * poppler_structure_element_iter_get_child:
736 * @parent: a #PopplerStructureElementIter
737 *
738 * Returns a new iterator to the children elements of the
739 * #PopplerStructureElement associated with @iter. The returned value must
740 * be freed with poppler_structure_element_iter_free().
741 *
742 * Return value: a new #PopplerStructureElementIter
743 *
744 * Since: 0.26
745 */
746PopplerStructureElementIter *poppler_structure_element_iter_get_child(PopplerStructureElementIter *parent)
747{
748 const StructElement *elem;
749
750 g_return_val_if_fail(parent != nullptr, NULL);
751
752 elem = parent->is_root ? parent->root->getChild(i: parent->index) : parent->elem->getChild(i: parent->index);
753
754 if (elem->getNumChildren() > 0) {
755 PopplerStructureElementIter *child = g_slice_new0(PopplerStructureElementIter);
756 child->document = (PopplerDocument *)g_object_ref(parent->document);
757 child->elem = elem;
758 return child;
759 }
760
761 return nullptr;
762}
763
764struct _PopplerTextSpan
765{
766 gchar *text;
767 gchar *font_name;
768 guint flags;
769 PopplerColor color;
770};
771
772G_DEFINE_BOXED_TYPE(PopplerTextSpan, poppler_text_span, poppler_text_span_copy, poppler_text_span_free)
773
774enum
775{
776 POPPLER_TEXT_SPAN_FIXED_WIDTH = (1 << 0),
777 POPPLER_TEXT_SPAN_SERIF = (1 << 1),
778 POPPLER_TEXT_SPAN_ITALIC = (1 << 2),
779 POPPLER_TEXT_SPAN_BOLD = (1 << 3),
780};
781
782static PopplerTextSpan *text_span_poppler_text_span(const TextSpan &span)
783{
784 PopplerTextSpan *new_span = g_slice_new0(PopplerTextSpan);
785 if (GooString *text = span.getText()) {
786 new_span->text = _poppler_goo_string_to_utf8(s: text);
787 }
788
789 new_span->color.red = colToDbl(x: span.getColor().r) * 65535;
790 new_span->color.green = colToDbl(x: span.getColor().g) * 65535;
791 new_span->color.blue = colToDbl(x: span.getColor().b) * 65535;
792
793 if (span.getFont()) {
794 // GfxFont sometimes does not have a family name but there
795 // is always a font name that can be used as fallback.
796 const GooString *font_name = span.getFont()->getFamily();
797 if (font_name) {
798 new_span->font_name = _poppler_goo_string_to_utf8(s: font_name);
799 } else if (span.getFont()->getName()) {
800 const GooString aux(*span.getFont()->getName());
801 new_span->font_name = _poppler_goo_string_to_utf8(s: &aux);
802 } else {
803 new_span->font_name = nullptr;
804 }
805
806 if (span.getFont()->isFixedWidth()) {
807 new_span->flags |= POPPLER_TEXT_SPAN_FIXED_WIDTH;
808 }
809 if (span.getFont()->isSerif()) {
810 new_span->flags |= POPPLER_TEXT_SPAN_SERIF;
811 }
812 if (span.getFont()->isItalic()) {
813 new_span->flags |= POPPLER_TEXT_SPAN_ITALIC;
814 }
815 if (span.getFont()->isBold()) {
816 new_span->flags |= POPPLER_TEXT_SPAN_BOLD;
817 }
818
819 /* isBold() can return false for some fonts whose weight is heavy */
820 switch (span.getFont()->getWeight()) {
821 case GfxFont::W500:
822 case GfxFont::W600:
823 case GfxFont::W700:
824 case GfxFont::W800:
825 case GfxFont::W900:
826 new_span->flags |= POPPLER_TEXT_SPAN_BOLD;
827 default:
828 break;
829 }
830 }
831
832 return new_span;
833}
834
835/**
836 * poppler_text_span_copy:
837 * @poppler_text_span: a #PopplerTextSpan
838 *
839 * Makes a copy of a text span.
840 *
841 * Return value: (transfer full): A new #PopplerTextSpan
842 *
843 * Since: 0.26
844 */
845PopplerTextSpan *poppler_text_span_copy(PopplerTextSpan *poppler_text_span)
846{
847 PopplerTextSpan *new_span;
848
849 g_return_val_if_fail(poppler_text_span != nullptr, NULL);
850
851 new_span = g_slice_dup(PopplerTextSpan, poppler_text_span);
852 new_span->text = g_strdup(str: poppler_text_span->text);
853 if (poppler_text_span->font_name) {
854 new_span->font_name = g_strdup(str: poppler_text_span->font_name);
855 }
856 return new_span;
857}
858
859/**
860 * poppler_text_span_free:
861 * @poppler_text_span: A #PopplerTextSpan
862 *
863 * Frees a text span.
864 *
865 * Since: 0.26
866 */
867void poppler_text_span_free(PopplerTextSpan *poppler_text_span)
868{
869 if (G_UNLIKELY(poppler_text_span == nullptr)) {
870 return;
871 }
872
873 g_free(mem: poppler_text_span->text);
874 g_free(mem: poppler_text_span->font_name);
875 g_slice_free(PopplerTextSpan, poppler_text_span);
876}
877
878/**
879 * poppler_text_span_is_fixed_width_font:
880 * @poppler_text_span: a #PopplerTextSpan
881 *
882 * Check wether a text span is meant to be rendered using a fixed-width font.
883 *
884 * Return value: Whether the span uses a fixed-width font.
885 *
886 * Since: 0.26
887 */
888gboolean poppler_text_span_is_fixed_width_font(PopplerTextSpan *poppler_text_span)
889{
890 g_return_val_if_fail(poppler_text_span != nullptr, FALSE);
891
892 return (poppler_text_span->flags & POPPLER_TEXT_SPAN_FIXED_WIDTH);
893}
894
895/**
896 * poppler_text_span_is_serif_font:
897 * @poppler_text_span: a #PopplerTextSpan
898 *
899 * Check whether a text span is meant to be rendered using a serif font.
900 *
901 * Return value: Whether the span uses a serif font.
902 *
903 * Since: 0.26
904 */
905gboolean poppler_text_span_is_serif_font(PopplerTextSpan *poppler_text_span)
906{
907 g_return_val_if_fail(poppler_text_span != nullptr, FALSE);
908
909 return (poppler_text_span->flags & POPPLER_TEXT_SPAN_SERIF);
910}
911
912/**
913 * poppler_text_span_is_bold_font:
914 * @poppler_text_span: a #PopplerTextSpan
915 *
916 * Check whether a text span is meant to be rendered using a bold font.
917 *
918 * Return value: Whether the span uses bold font.
919 *
920 * Since: 0.26
921 */
922gboolean poppler_text_span_is_bold_font(PopplerTextSpan *poppler_text_span)
923{
924 g_return_val_if_fail(poppler_text_span != nullptr, FALSE);
925
926 return (poppler_text_span->flags & POPPLER_TEXT_SPAN_BOLD);
927}
928
929/**
930 * poppler_text_span_get_color:
931 * @poppler_text_span: a #PopplerTextSpan
932 * @color: (out): a return location for a #PopplerColor
933 *
934 * Obtains the color in which the text is to be rendered.
935 *
936 * Since: 0.26
937 */
938void poppler_text_span_get_color(PopplerTextSpan *poppler_text_span, PopplerColor *color)
939{
940 g_return_if_fail(poppler_text_span != nullptr);
941 g_return_if_fail(color != nullptr);
942
943 *color = poppler_text_span->color;
944}
945
946/**
947 * poppler_text_span_get_text:
948 * @poppler_text_span: a #PopplerTextSpan
949 *
950 * Obtains the text contained in the span.
951 *
952 * Return value: (transfer none): A string.
953 *
954 * Since: 0.26
955 */
956const gchar *poppler_text_span_get_text(PopplerTextSpan *poppler_text_span)
957{
958 g_return_val_if_fail(poppler_text_span != nullptr, NULL);
959
960 return poppler_text_span->text;
961}
962
963/**
964 * poppler_text_span_get_font_name:
965 * @poppler_text_span: a #PopplerTextSpan
966 *
967 * Obtains the name of the font in which the span is to be rendered.
968 *
969 * Return value: (transfer none): A string containing the font name, or
970 * %NULL if a font is not defined.
971 *
972 * Since: 0.26
973 */
974const gchar *poppler_text_span_get_font_name(PopplerTextSpan *poppler_text_span)
975{
976 g_return_val_if_fail(poppler_text_span != nullptr, NULL);
977
978 return poppler_text_span->font_name;
979}
980
981/**
982 * poppler_structure_element_get_text_spans:
983 * @poppler_structure_element: A #PopplerStructureElement
984 * @n_text_spans: (out): A pointer to the location where the number of elements in
985 * the returned array will be stored.
986 *
987 * Obtains the text enclosed by an element, as an array of #PopplerTextSpan
988 * structures. Each item in the list is a piece of text which share the same
989 * attributes, plus its attributes. The following example shows how to
990 * obtain and free the text spans of an element:
991 *
992 * <informalexample><programlisting>
993 * guint i, n_spans;
994 * PopplerTextSpan **text_spans =
995 * poppler_structure_element_get_text_spans (element, &n_spans);
996 * /<!-- -->* Use the text spans *<!-- -->/
997 * for (i = 0; i < n_spans; i++)
998 * poppler_text_span_free (text_spans[i]);
999 * g_free (text_spans);
1000 * </programlisting></informalexample>
1001 *
1002 * Return value: (transfer full) (array length=n_text_spans) (element-type PopplerTextSpan):
1003 * An array of #PopplerTextSpan elements.
1004 *
1005 * Since: 0.26
1006 */
1007PopplerTextSpan **poppler_structure_element_get_text_spans(PopplerStructureElement *poppler_structure_element, guint *n_text_spans)
1008{
1009 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
1010 g_return_val_if_fail(n_text_spans != nullptr, NULL);
1011 g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
1012
1013 if (!poppler_structure_element->elem->isContent()) {
1014 return nullptr;
1015 }
1016
1017 const TextSpanArray spans(poppler_structure_element->elem->getTextSpans());
1018 PopplerTextSpan **text_spans = g_new0(PopplerTextSpan *, spans.size());
1019
1020 size_t i = 0;
1021 for (const TextSpan &s : spans) {
1022 text_spans[i++] = text_span_poppler_text_span(span: s);
1023 }
1024
1025 *n_text_spans = spans.size();
1026
1027 return text_spans;
1028}
1029
1030/* General Layout Attributes */
1031
1032/**
1033 * poppler_structure_element_get_placement:
1034 * @poppler_structure_element: A #PopplerStructureElement
1035 *
1036 * Obtains the placement type of the structure element.
1037 *
1038 * Return value: A #PopplerStructurePlacement value.
1039 *
1040 * Since: 0.26
1041 */
1042PopplerStructurePlacement poppler_structure_element_get_placement(PopplerStructureElement *poppler_structure_element)
1043{
1044 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), EnumNameValue<PopplerStructurePlacement>::values[0].value);
1045 return attr_to_enum<PopplerStructurePlacement>(poppler_structure_element);
1046}
1047
1048/**
1049 * poppler_structure_element_get_writing_mode:
1050 * @poppler_structure_element: A #PopplerStructureElement
1051 *
1052 * Obtains the writing mode (writing direction) of the content associated
1053 * with a structure element.
1054 *
1055 * Return value: A #PopplerStructureWritingMode value.
1056 *
1057 * Since: 0.26
1058 */
1059PopplerStructureWritingMode poppler_structure_element_get_writing_mode(PopplerStructureElement *poppler_structure_element)
1060{
1061 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), EnumNameValue<PopplerStructureWritingMode>::values[0].value);
1062 return attr_to_enum<PopplerStructureWritingMode>(poppler_structure_element);
1063}
1064
1065static void convert_border_style(const Object *object, PopplerStructureBorderStyle *values)
1066{
1067 g_assert(object != nullptr);
1068 g_assert(values != nullptr);
1069
1070 if (object->isArray()) {
1071 g_assert(object->arrayGetLength() == 4);
1072 for (guint i = 0; i < 4; i++) {
1073 Object item = object->arrayGet(i);
1074 values[i] = name_to_enum<PopplerStructureBorderStyle>(name_value: &item);
1075 }
1076 } else {
1077 values[0] = values[1] = values[2] = values[3] = name_to_enum<PopplerStructureBorderStyle>(name_value: object);
1078 }
1079}
1080
1081/**
1082 * poppler_structure_element_get_border_style:
1083 * @poppler_structure_element: A #PopplerStructureElement
1084 * @border_styles: (out) (array fixed-size=4) (element-type PopplerStructureBorderStyle):
1085 * An array of four #PopplerStructureBorderStyle elements.
1086 *
1087 * Obtains the border style of a structure element. The result values
1088 * are in before-after-start-end ordering. For example, using Western
1089 * left-to-right writing, that is top-bottom-left-right.
1090 *
1091 * Since: 0.26
1092 */
1093void poppler_structure_element_get_border_style(PopplerStructureElement *poppler_structure_element, PopplerStructureBorderStyle *border_styles)
1094{
1095 g_return_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element));
1096 g_return_if_fail(border_styles != nullptr);
1097
1098 convert_border_style(object: attr_value_or_default(poppler_structure_element, attribute_type: Attribute::BorderStyle), values: border_styles);
1099}
1100
1101static inline void convert_doubles_array(const Object *object, gdouble **values, guint *n_values)
1102{
1103 g_assert(object->isArray());
1104 g_assert(n_values != nullptr);
1105 g_assert(values != nullptr);
1106
1107 *n_values = object->arrayGetLength();
1108 gdouble *doubles = g_new(gdouble, *n_values);
1109
1110 for (guint i = 0; i < *n_values; i++) {
1111 doubles[i] = object->arrayGet(i).getNum();
1112 }
1113
1114 values = &doubles;
1115}
1116
1117static inline void convert_color(const Object *object, PopplerColor *color)
1118{
1119 g_assert(color != nullptr);
1120 g_assert(object->isArray() && object->arrayGetLength() != 3);
1121
1122 color->red = object->arrayGet(i: 0).getNum() * 65535;
1123 color->green = object->arrayGet(i: 1).getNum() * 65535;
1124 color->blue = object->arrayGet(i: 2).getNum() * 65535;
1125}
1126
1127/**
1128 * poppler_structure_element_get_color:
1129 * @poppler_structure_element: A #PopplerStructureElement
1130 * @color: (out): A #PopplerColor.
1131 *
1132 * Obtains the color of the content contained in the element.
1133 * If this attribute is not specified, the color for this element shall
1134 * be the current text fill color in effect at the start of its associated content.
1135 *
1136 * Return value: %TRUE if a color is defined for the element,
1137 * %FALSE otherwise.
1138 *
1139 * Since: 0.26
1140 */
1141gboolean poppler_structure_element_get_color(PopplerStructureElement *poppler_structure_element, PopplerColor *color)
1142{
1143 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
1144 g_return_val_if_fail(color != nullptr, FALSE);
1145
1146 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::Color);
1147 if (value == nullptr) {
1148 return FALSE;
1149 }
1150
1151 convert_color(object: value, color);
1152 return TRUE;
1153}
1154
1155/**
1156 * poppler_structure_element_get_background_color:
1157 * @poppler_structure_element: A #PopplerStructureElement
1158 * @color: (out): A #PopplerColor.
1159 *
1160 * Obtains the background color of the element. If this attribute is
1161 * not specified, the element shall be treated as if it were transparent.
1162 *
1163 * Return value: %TRUE if a color is defined for the element,
1164 * %FALSE otherwise.
1165 *
1166 * Since: 0.26
1167 */
1168gboolean poppler_structure_element_get_background_color(PopplerStructureElement *poppler_structure_element, PopplerColor *color)
1169{
1170 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
1171 g_return_val_if_fail(color != nullptr, FALSE);
1172
1173 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::BackgroundColor);
1174 if (value == nullptr) {
1175 return FALSE;
1176 }
1177
1178 convert_color(object: value, color);
1179 return TRUE;
1180}
1181
1182/**
1183 * poppler_structure_element_get_border_color:
1184 * @poppler_structure_element: A #PopplerStructureElement
1185 * @colors: (out) (array fixed-size=4) (element-type PopplerColor): An array
1186 * of four #PopplerColor.
1187 *
1188 * Obtains the color of border around the element. The result values
1189 * are in before-after-start-end ordering (for the typical Western
1190 * left-to-right writing, that is top-bottom-left-right).
1191 * If this attribute is not specified, the border color for this element shall
1192 * be the current text fill color in effect at the start of its associated
1193 * content.
1194 *
1195 * Return value: %TRUE if a color is defined for the element,
1196 * %FALSE otherwise.
1197 *
1198 * Since: 0.26
1199 */
1200gboolean poppler_structure_element_get_border_color(PopplerStructureElement *poppler_structure_element, PopplerColor *colors)
1201{
1202 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
1203 g_return_val_if_fail(colors != nullptr, FALSE);
1204
1205 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::BorderColor);
1206 if (value == nullptr) {
1207 return FALSE;
1208 }
1209
1210 g_assert(value->isArray());
1211 if (value->arrayGetLength() == 4) {
1212 // One color per side.
1213 for (guint i = 0; i < 4; i++) {
1214 Object item = value->arrayGet(i);
1215 convert_color(object: &item, color: &colors[i]);
1216 }
1217 } else {
1218 // Same color in all sides.
1219 g_assert(value->arrayGetLength() == 3);
1220 convert_color(object: value, color: &colors[0]);
1221 colors[1] = colors[2] = colors[3] = colors[0];
1222 }
1223
1224 return TRUE;
1225}
1226
1227static inline void convert_double_or_4_doubles(const Object *object, gdouble *value)
1228{
1229 g_assert(object != nullptr);
1230
1231 if (object->isArray()) {
1232 g_assert(object->arrayGetLength() == 4);
1233 for (guint i = 0; i < 4; i++) {
1234 value[i] = object->arrayGet(i).getNum();
1235 }
1236 } else {
1237 g_assert(object->isNum());
1238 value[0] = value[1] = value[2] = value[3] = object->getNum();
1239 }
1240}
1241
1242/**
1243 * poppler_structure_element_get_border_thickness:
1244 * @poppler_structure_element: A #PopplerStructureElement
1245 * @border_thicknesses: (out) (array fixed-size=4) (element-type gdouble):
1246 * Array with the four values of border thicknesses.
1247 *
1248 * Obtains the thickness of the border of an element. The result values
1249 * are in before-after-start-end ordering (for the typical Western
1250 * left-to-right writing, that is top-bottom-left-right).
1251 * A value of 0 indicates that the border shall not be drawn.
1252 *
1253 * Return value: %TRUE if the border thickness attribute is defined for
1254 * the element, %FALSE otherwise.
1255 *
1256 * Since: 0.26
1257 */
1258gboolean poppler_structure_element_get_border_thickness(PopplerStructureElement *poppler_structure_element, gdouble *border_thicknesses)
1259{
1260 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
1261 g_return_val_if_fail(border_thicknesses != nullptr, FALSE);
1262
1263 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::BorderThickness);
1264 if (value == nullptr) {
1265 return FALSE;
1266 }
1267
1268 convert_double_or_4_doubles(object: value, value: border_thicknesses);
1269 return TRUE;
1270}
1271
1272/**
1273 * poppler_structure_element_get_padding:
1274 * @poppler_structure_element: A #PopplerStructureElement
1275 * @paddings: (out) (array fixed-size=4) (element-type gdouble):
1276 * Padding for the four sides of the element.
1277 *
1278 * Obtains the padding of an element (space around it). The result
1279 * values are in before-after-start-end ordering. For example using
1280 * Western left-to-right writing, that is top-bottom-left-right.
1281 *
1282 * Since: 0.26
1283 */
1284void poppler_structure_element_get_padding(PopplerStructureElement *poppler_structure_element, gdouble *paddings)
1285{
1286 g_return_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element));
1287 g_return_if_fail(paddings != nullptr);
1288
1289 convert_double_or_4_doubles(object: attr_value_or_default(poppler_structure_element, attribute_type: Attribute::Padding), value: paddings);
1290}
1291
1292/* Layout Attributes for block-level structure elements */
1293
1294/**
1295 * poppler_structure_element_get_space_before:
1296 * @poppler_structure_element: A #PopplerStructureElement
1297 *
1298 * Obtains the amount of empty space before the block-level structure element.
1299 *
1300 * Return value: A positive value.
1301 *
1302 * Since: 0.26
1303 */
1304gdouble poppler_structure_element_get_space_before(PopplerStructureElement *poppler_structure_element)
1305{
1306 g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
1307 return attr_value_or_default(poppler_structure_element, attribute_type: Attribute::SpaceBefore)->getNum();
1308}
1309
1310/**
1311 * poppler_structure_element_get_space_after:
1312 * @poppler_structure_element: A #PopplerStructureElement
1313 *
1314 * Obtains the amount of empty space after the block-level structure element.
1315 *
1316 * Return value: A positive value.
1317 *
1318 * Since: 0.26
1319 */
1320gdouble poppler_structure_element_get_space_after(PopplerStructureElement *poppler_structure_element)
1321{
1322 g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
1323 return attr_value_or_default(poppler_structure_element, attribute_type: Attribute::SpaceAfter)->getNum();
1324}
1325
1326/**
1327 * poppler_structure_element_get_start_indent:
1328 * @poppler_structure_element: A #PopplerStructureElement
1329 *
1330 * Obtains the amount of indentation at the beginning of the block-level structure element.
1331 *
1332 * Return value: A numeric value.
1333 *
1334 * Since: 0.26
1335 */
1336gdouble poppler_structure_element_get_start_indent(PopplerStructureElement *poppler_structure_element)
1337{
1338 g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
1339 return attr_value_or_default(poppler_structure_element, attribute_type: Attribute::StartIndent)->getNum();
1340}
1341
1342/**
1343 * poppler_structure_element_get_end_indent:
1344 * @poppler_structure_element: A #PopplerStructureElement
1345 *
1346 * Obtains the amount of indentation at the end of the block-level structure element.
1347 *
1348 * Return value: A numeric value.
1349 *
1350 * Since: 0.26
1351 */
1352gdouble poppler_structure_element_get_end_indent(PopplerStructureElement *poppler_structure_element)
1353{
1354 g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
1355 return attr_value_or_default(poppler_structure_element, attribute_type: Attribute::EndIndent)->getNum();
1356}
1357
1358/**
1359 * poppler_structure_element_get_text_indent:
1360 * @poppler_structure_element: A #PopplerStructureElement
1361 *
1362 * Obtains the amount of indentation of the text contained in the block-level structure element.
1363 *
1364 * Return value: A numeric value.
1365 *
1366 * Since: 0.26
1367 */
1368gdouble poppler_structure_element_get_text_indent(PopplerStructureElement *poppler_structure_element)
1369{
1370 g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
1371 return attr_value_or_default(poppler_structure_element, attribute_type: Attribute::TextIndent)->getNum();
1372}
1373
1374/**
1375 * poppler_structure_element_get_text_align:
1376 * @poppler_structure_element: A #PopplerStructureElement
1377 *
1378 * Obtains the text alignment mode of the text contained into a
1379 * block-level structure element.
1380 *
1381 * Return value: A #PopplerStructureTextAlign value.
1382 *
1383 * Since: 0.26
1384 */
1385PopplerStructureTextAlign poppler_structure_element_get_text_align(PopplerStructureElement *poppler_structure_element)
1386{
1387 g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), EnumNameValue<PopplerStructureTextAlign>::values[0].value);
1388 return attr_to_enum<PopplerStructureTextAlign>(poppler_structure_element);
1389}
1390
1391/**
1392 * poppler_structure_element_get_bounding_box:
1393 * @poppler_structure_element: A #PopplerStructureElement
1394 * @bounding_box: (out): A #PopplerRectangle.
1395 *
1396 * Obtains the size of the bounding box of a block-level structure element.
1397 *
1398 * Return value: %TRUE if a bounding box is defined for the element,
1399 * %FALSE otherwise.
1400 *
1401 * Since: 0.26
1402 */
1403gboolean poppler_structure_element_get_bounding_box(PopplerStructureElement *poppler_structure_element, PopplerRectangle *bounding_box)
1404{
1405 g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), FALSE);
1406 g_return_val_if_fail(bounding_box != nullptr, FALSE);
1407
1408 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::BBox);
1409 if (value == nullptr) {
1410 return FALSE;
1411 }
1412
1413 gdouble dimensions[4];
1414 convert_double_or_4_doubles(object: value, value: dimensions);
1415
1416 bounding_box->x1 = dimensions[0];
1417 bounding_box->y1 = dimensions[1];
1418 bounding_box->x2 = dimensions[2];
1419 bounding_box->y2 = dimensions[3];
1420
1421 return TRUE;
1422}
1423
1424/**
1425 * poppler_structure_element_get_width:
1426 * @poppler_structure_element: A #PopplerStructureElement
1427 *
1428 * Obtains the width of the block-level structure element. Note that for elements which do
1429 * not specify a width, it has to be calculated, and in this case -1 is returned.
1430 *
1431 * Return value: A positive value if a width is defined, or -1
1432 * if the width is to be calculated automatically.
1433 *
1434 * Since: 0.26
1435 */
1436gdouble poppler_structure_element_get_width(PopplerStructureElement *poppler_structure_element)
1437{
1438 g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
1439 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::Width);
1440 return value->isName(nameA: "Auto") ? -1.0 : value->getNum();
1441}
1442
1443/**
1444 * poppler_structure_element_get_height:
1445 * @poppler_structure_element: A #PopplerStructureElement
1446 *
1447 * Obtains the height of the block-level structure element. Note that for elements which do
1448 * not specify a height, it has to be calculated, and in this case -1 is returned.
1449 *
1450 * Return value: A positive value if a width is defined, or -1
1451 * if the height is to be calculated automatically.
1452 *
1453 * Since: 0.26
1454 */
1455gdouble poppler_structure_element_get_height(PopplerStructureElement *poppler_structure_element)
1456{
1457 g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
1458 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::Height);
1459 return value->isName(nameA: "Auto") ? -1.0 : value->getNum();
1460}
1461
1462/**
1463 * poppler_structure_element_get_block_align:
1464 * @poppler_structure_element: A #PopplerStructureElement
1465 *
1466 * Obtains the block-alignment mode of the block-level structure element.
1467 *
1468 * Return value: A #PopplerStructureBlockAlign value.
1469 *
1470 * Since: 0.26
1471 */
1472PopplerStructureBlockAlign poppler_structure_element_get_block_align(PopplerStructureElement *poppler_structure_element)
1473{
1474 g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), EnumNameValue<PopplerStructureBlockAlign>::values[0].value);
1475 return attr_to_enum<PopplerStructureBlockAlign>(poppler_structure_element);
1476}
1477
1478/**
1479 * poppler_structure_element_get_inline_align:
1480 * @poppler_structure_element: A #PopplerStructureElement
1481 *
1482 * Obtains the inline-alignment mode of the block-level structure element.
1483 *
1484 * Return value: A #PopplerStructureInlineAlign value.
1485 *
1486 * Since: 0.26
1487 */
1488PopplerStructureInlineAlign poppler_structure_element_get_inline_align(PopplerStructureElement *poppler_structure_element)
1489{
1490 g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), EnumNameValue<PopplerStructureInlineAlign>::values[0].value);
1491 return attr_to_enum<PopplerStructureInlineAlign>(poppler_structure_element);
1492}
1493
1494/**
1495 * poppler_structure_element_get_table_border_style:
1496 * @poppler_structure_element: A #PopplerStructureElement
1497 * @border_styles: (out) (array fixed-size=4) (element-type PopplerStructureBorderStyle):
1498 * An array of four #PopplerStructureBorderStyle elements.
1499 *
1500 * Obtains the table cell border style of a block-level structure element. The result values
1501 * are in before-after-start-end ordering. For example, using Western
1502 * left-to-right writing, that is top-bottom-left-right.
1503 *
1504 * Since: 0.26
1505 */
1506void poppler_structure_element_get_table_border_style(PopplerStructureElement *poppler_structure_element, PopplerStructureBorderStyle *border_styles)
1507{
1508 g_return_if_fail(poppler_structure_element_is_block(poppler_structure_element));
1509 g_return_if_fail(border_styles != nullptr);
1510
1511 convert_border_style(object: attr_value_or_default(poppler_structure_element, attribute_type: Attribute::TBorderStyle), values: border_styles);
1512}
1513
1514/**
1515 * poppler_structure_element_get_table_padding:
1516 * @poppler_structure_element: A #PopplerStructureElement
1517 * @paddings: (out) (array fixed-size=4) (element-type gdouble):
1518 * Padding for the four sides of the element.
1519 *
1520 * Obtains the padding between the table cell’s content rectangle and the
1521 * surrounding border of a block-level structure element. The result
1522 * values are in before-after-start-end ordering (for the typical
1523 * Western left-to-right writing, that is top-bottom-left-right).
1524 *
1525 * Since: 0.26
1526 */
1527void poppler_structure_element_get_table_padding(PopplerStructureElement *poppler_structure_element, gdouble *paddings)
1528{
1529 g_return_if_fail(poppler_structure_element_is_block(poppler_structure_element));
1530 g_return_if_fail(paddings != nullptr);
1531
1532 convert_double_or_4_doubles(object: attr_value_or_default(poppler_structure_element, attribute_type: Attribute::TPadding), value: paddings);
1533}
1534
1535/* Layout Attributes for inline-level structure elements */
1536
1537/**
1538 * poppler_structure_element_get_baseline_shift:
1539 * @poppler_structure_element: A #PopplerStructureElement
1540 *
1541 * Obtains how much the text contained in the inline-level structure element should be shifted,
1542 * measuring from the baseline of the glyphs.
1543 *
1544 * Return value: A numeric value.
1545 *
1546 * Since: 0.26
1547 */
1548gdouble poppler_structure_element_get_baseline_shift(PopplerStructureElement *poppler_structure_element)
1549{
1550 g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), NAN);
1551 return attr_value_or_default(poppler_structure_element, attribute_type: Attribute::BaselineShift)->getNum();
1552}
1553
1554/**
1555 * poppler_structure_element_get_line_height:
1556 * @poppler_structure_element: A #PopplerStructureElement
1557 *
1558 * Obtains the line height for the text contained in the inline-level structure element.
1559 * Note that for elements which do not specify a line height, it has to be calculated,
1560 * and in this case -1 is returned.
1561 *
1562 * Return value: A positive value if a line height is defined, or -1
1563 * if the height is to be calculated automatically.
1564 *
1565 * Since: 0.26
1566 */
1567gdouble poppler_structure_element_get_line_height(PopplerStructureElement *poppler_structure_element)
1568{
1569 g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), NAN);
1570 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::LineHeight);
1571 return (value->isName(nameA: "Normal") || value->isName(nameA: "Auto")) ? -1.0 : value->getNum();
1572}
1573
1574/**
1575 * poppler_structure_element_get_text_decoration_color:
1576 * @poppler_structure_element: A #PopplerStructureElement
1577 * @color: (out): A #PopplerColor.
1578 *
1579 * Obtains the color of the text decoration for the text contained
1580 * in the inline-level structure element.
1581 * If this attribute is not specified, the color for this element shall be the current fill
1582 * color in effect at the start of its associated content.
1583 *
1584 * Return value: %TRUE if a color is defined for the element,
1585 * %FALSE otherwise.
1586 *
1587 * Since: 0.26
1588 */
1589gboolean poppler_structure_element_get_text_decoration_color(PopplerStructureElement *poppler_structure_element, PopplerColor *color)
1590{
1591 g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), FALSE);
1592 g_return_val_if_fail(color != nullptr, FALSE);
1593
1594 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::TextDecorationColor);
1595 if (value == nullptr) {
1596 return FALSE;
1597 }
1598
1599 convert_color(object: value, color);
1600 return FALSE;
1601}
1602
1603/**
1604 * poppler_structure_element_get_text_decoration_thickness:
1605 * @poppler_structure_element: A #PopplerStructureElement
1606 *
1607 * Obtains the thickness of the text decoration for the text contained
1608 * in the inline-level structure element.
1609 * If this attribute is not specified, it shall be derived from the current
1610 * stroke thickness in effect at the start of the element’s associated content.
1611 *
1612 * Return value: Thickness of the text decoration, or NAN if not defined.
1613 *
1614 * Since: 0.26
1615 */
1616gdouble poppler_structure_element_get_text_decoration_thickness(PopplerStructureElement *poppler_structure_element)
1617{
1618 g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), NAN);
1619
1620 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::TextDecorationThickness);
1621 return (value == nullptr) ? NAN : value->getNum();
1622}
1623
1624/**
1625 * poppler_structure_element_get_text_decoration_type:
1626 * @poppler_structure_element: A #PopplerStructureElement
1627 *
1628 * Obtains the text decoration type of the text contained in the
1629 * inline-level structure element.
1630 *
1631 * Return value: A #PopplerStructureTextDecoration value.
1632 *
1633 * Since: 0.26
1634 */
1635PopplerStructureTextDecoration poppler_structure_element_get_text_decoration_type(PopplerStructureElement *poppler_structure_element)
1636{
1637 g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), EnumNameValue<PopplerStructureTextDecoration>::values[0].value);
1638 return attr_to_enum<PopplerStructureTextDecoration>(poppler_structure_element);
1639}
1640
1641/**
1642 * poppler_structure_element_get_ruby_align:
1643 * @poppler_structure_element: A #PopplerStructureElement
1644 *
1645 * Obtains the alignment for the ruby text contained in a
1646 * inline-level structure element.
1647 *
1648 * Return value: A #PopplerStructureRubyAlign value.
1649 *
1650 * Since: 0.26
1651 */
1652PopplerStructureRubyAlign poppler_structure_element_get_ruby_align(PopplerStructureElement *poppler_structure_element)
1653{
1654 g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), EnumNameValue<PopplerStructureRubyAlign>::values[0].value);
1655 return attr_to_enum<PopplerStructureRubyAlign>(poppler_structure_element);
1656}
1657
1658/**
1659 * poppler_structure_element_get_ruby_position:
1660 * @poppler_structure_element: A #PopplerStructureElement
1661 *
1662 * Obtains the position for the ruby text contained in a
1663 * inline-level structure element.
1664 *
1665 * Return value: A #PopplerStructureRubyPosition value.
1666 *
1667 * Since: 0.26
1668 */
1669PopplerStructureRubyPosition poppler_structure_element_get_ruby_position(PopplerStructureElement *poppler_structure_element)
1670{
1671 g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), EnumNameValue<PopplerStructureRubyPosition>::values[0].value);
1672 return attr_to_enum<PopplerStructureRubyPosition>(poppler_structure_element);
1673}
1674
1675/**
1676 * poppler_structure_element_get_glyph_orientation:
1677 * @poppler_structure_element: A #PopplerStructureElement
1678 *
1679 * Obtains the glyph orientation for the text contained in a
1680 * inline-level structure element.
1681 *
1682 * Return value: A #PopplerStructureGlyphOrientation value.
1683 *
1684 * Since: 0.26
1685 */
1686PopplerStructureGlyphOrientation poppler_structure_element_get_glyph_orientation(PopplerStructureElement *poppler_structure_element)
1687{
1688 g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), EnumNameValue<PopplerStructureGlyphOrientation>::values[0].value);
1689 return attr_to_enum<PopplerStructureGlyphOrientation>(poppler_structure_element);
1690}
1691
1692/* Column Attributes */
1693
1694/**
1695 * poppler_structure_element_get_column_count:
1696 * @poppler_structure_element: A #PopplerStructureElement
1697 *
1698 * Obtains the number of columns used to lay out the content contained
1699 * in the grouping element.
1700 *
1701 * Return value: Number of columns.
1702 *
1703 * Since: 0.26
1704 */
1705guint poppler_structure_element_get_column_count(PopplerStructureElement *poppler_structure_element)
1706{
1707 g_return_val_if_fail(poppler_structure_element_is_grouping(poppler_structure_element), 0);
1708 return static_cast<guint>(attr_value_or_default(poppler_structure_element, attribute_type: Attribute::ColumnCount)->getInt());
1709}
1710
1711/**
1712 * poppler_structure_element_get_column_gaps:
1713 * @poppler_structure_element: A #PopplerStructureElement
1714 * @n_values: (out): Size of the returned array.
1715 *
1716 * Obtains the size of the gaps in between adjacent columns. Returns an
1717 * array of elements: the first one is the size of the gap in between
1718 * columns 1 and 2, second is the size between columns 2 and 3, and so on.
1719 *
1720 * For elements which use a single column, %NULL is returned and @n_values
1721 * is set to zero.
1722 *
1723 * If the attribute is undefined, %NULL is returned and @n_values is set
1724 * to a non-zero value.
1725 *
1726 * The array with the results is allocated by the function. When it is
1727 * not needed anymore, be sure to call g_free() on it.
1728 *
1729 * Return value: (transfer full) (array length=n_values) (element-type gdouble):
1730 * Array containing the values for the column gaps, or %NULL if the
1731 * array is empty or the attribute is not defined.
1732 *
1733 * Since: 0.26
1734 */
1735gdouble *poppler_structure_element_get_column_gaps(PopplerStructureElement *poppler_structure_element, guint *n_values)
1736{
1737 g_return_val_if_fail(poppler_structure_element_is_grouping(poppler_structure_element), NULL);
1738 g_return_val_if_fail(n_values != nullptr, NULL);
1739
1740 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::ColumnGap);
1741 if (value == nullptr) {
1742 *n_values = static_cast<guint>(-1);
1743 return nullptr;
1744 }
1745
1746 gdouble *result = nullptr;
1747 convert_doubles_array(object: value, values: &result, n_values);
1748 return result;
1749}
1750
1751/**
1752 * poppler_structure_element_get_column_widths:
1753 * @poppler_structure_element: A #PopplerStructureElement
1754 * @n_values: (out): Size of the returned array.
1755 *
1756 * Obtains an array with the widths of the columns.
1757 *
1758 * The array with the results is allocated by the function. When it is
1759 * not needed anymore, be sure to call g_free() on it.
1760 *
1761 * Return value: (transfer full) (array length=n_values) (element-type gdouble):
1762 * Array containing widths of the columns, or %NULL if the attribute
1763 * is not defined.
1764 *
1765 * Since: 0.26
1766 */
1767gdouble *poppler_structure_element_get_column_widths(PopplerStructureElement *poppler_structure_element, guint *n_values)
1768{
1769 g_return_val_if_fail(poppler_structure_element_is_grouping(poppler_structure_element), NULL);
1770 g_return_val_if_fail(n_values != nullptr, NULL);
1771
1772 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::ColumnWidths);
1773 if (value == nullptr) {
1774 return nullptr;
1775 }
1776
1777 gdouble *result = nullptr;
1778 convert_doubles_array(object: value, values: &result, n_values);
1779 return result;
1780}
1781
1782/* List Attribute */
1783
1784/**
1785 * poppler_structure_element_get_list_numbering:
1786 * @poppler_structure_element: A #PopplerStructureElement
1787 *
1788 * Obtains the list numbering style for list items.
1789 *
1790 * Return value: A #PopplerStructureListNumbering value.
1791 *
1792 * Since: 0.26
1793 */
1794PopplerStructureListNumbering poppler_structure_element_get_list_numbering(PopplerStructureElement *poppler_structure_element)
1795{
1796 g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_LIST_ITEM, EnumNameValue<PopplerStructureListNumbering>::values[0].value);
1797 return attr_to_enum<PopplerStructureListNumbering>(poppler_structure_element);
1798}
1799
1800/* PrintField Attributes */
1801
1802/**
1803 * poppler_structure_element_get_form_role:
1804 * @poppler_structure_element: A #PopplerStructureElement
1805 *
1806 * Obtains the role of a form structure element that is part of a form, or is
1807 * a form field. This hints how the control for the element is intended
1808 * to be rendered.
1809 *
1810 * Return value: A #PopplerStructureFormRole value.
1811 *
1812 * Since: 0.26
1813 */
1814PopplerStructureFormRole poppler_structure_element_get_form_role(PopplerStructureElement *poppler_structure_element)
1815{
1816 g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_FORM, EnumNameValue<PopplerStructureFormRole>::values[0].value);
1817
1818 /*
1819 * The Role attribute can actually be undefined.
1820 */
1821 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::Role);
1822 if (value == nullptr) {
1823 return POPPLER_STRUCTURE_FORM_ROLE_UNDEFINED;
1824 }
1825
1826 return name_to_enum<PopplerStructureFormRole>(name_value: value);
1827}
1828
1829/**
1830 * poppler_structure_element_get_form_state:
1831 * @poppler_structure_element: A #PopplerStructureElement
1832 *
1833 * For a structure element that is a form field, obtains in which state
1834 * the associated control is expected to be rendered.
1835 *
1836 * Return value: A #PopplerStructureFormState value.
1837 *
1838 * Since: 0.26
1839 */
1840PopplerStructureFormState poppler_structure_element_get_form_state(PopplerStructureElement *poppler_structure_element)
1841{
1842 g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_FORM, EnumNameValue<PopplerStructureFormState>::values[0].value);
1843 return attr_to_enum<PopplerStructureFormState>(poppler_structure_element);
1844}
1845
1846/**
1847 * poppler_structure_element_get_form_description:
1848 * @poppler_structure_element: A #PopplerStructureElement
1849 *
1850 * Obtains the textual description of the form element. Note that the
1851 * description is for informative purposes, and it is not intended
1852 * to be rendered. For example, assistive technologies may use the
1853 * description field to provide an alternate way of presenting an
1854 * element to the user.
1855 *
1856 * The returned string is allocated by the function. When it is
1857 * not needed anymore, be sure to call g_free() on it.
1858 *
1859 * Return value: (transfer full): A string, or %NULL if the attribute
1860 * is not defined.
1861 *
1862 * Since: 0.26
1863 */
1864gchar *poppler_structure_element_get_form_description(PopplerStructureElement *poppler_structure_element)
1865{
1866 g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_FORM, NULL);
1867
1868 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::Desc);
1869 if (value == nullptr) {
1870 return nullptr;
1871 }
1872 if (value->isString()) {
1873 return _poppler_goo_string_to_utf8(s: value->getString());
1874 }
1875 if (value->isName()) {
1876 return g_strdup(str: value->getName());
1877 }
1878
1879 g_assert_not_reached();
1880 return nullptr;
1881}
1882
1883/* Table Attributes */
1884
1885/**
1886 * poppler_structure_element_get_table_row_span:
1887 * @poppler_structure_element: A #PopplerStructureElement
1888 *
1889 * Obtains the number of rows the table element spans to.
1890 *
1891 * Return value: A positive, non-zero value.
1892 *
1893 * Since: 0.26
1894 */
1895guint poppler_structure_element_get_table_row_span(PopplerStructureElement *poppler_structure_element)
1896{
1897 g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_TABLE, 0);
1898 return static_cast<guint>(attr_value_or_default(poppler_structure_element, attribute_type: Attribute::RowSpan)->getInt());
1899}
1900
1901/**
1902 * poppler_structure_element_get_table_column_span:
1903 * @poppler_structure_element: A #PopplerStructureElement
1904 *
1905 * Obtains the number of columns the table element spans to.
1906 *
1907 * Return value: A positive, non-zero value.
1908 *
1909 * Since: 0.26
1910 */
1911guint poppler_structure_element_get_table_column_span(PopplerStructureElement *poppler_structure_element)
1912{
1913 g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_TABLE, 0);
1914 return static_cast<guint>(attr_value_or_default(poppler_structure_element, attribute_type: Attribute::ColSpan)->getInt());
1915}
1916
1917/**
1918 * poppler_structure_element_get_table_headers:
1919 * @poppler_structure_element: A #PopplerStructureElement
1920 *
1921 * Obtains an array with the names of the table column headers. This is only
1922 * useful for table header row elements.
1923 *
1924 * The array with the results is allocated by the function. The number
1925 * of items in the returned array can be obtained with g_strv_length().
1926 * The returned value must be freed using g_strfreev().
1927 *
1928 * Return value: (transfer full) (array zero-terminated=1) (element-type gchar*):
1929 * Zero-terminated array of strings with the table header names,
1930 * or %NULL if the attribute is not defined.
1931 *
1932 * Since: 0.26
1933 */
1934gchar **poppler_structure_element_get_table_headers(PopplerStructureElement *poppler_structure_element)
1935{
1936 g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_TABLE, NULL);
1937
1938 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::Headers);
1939 if (value == nullptr) {
1940 return nullptr;
1941 }
1942
1943 g_assert(value->isArray());
1944
1945 const guint n_values = value->arrayGetLength();
1946 gchar **result = g_new0(gchar *, n_values + 1);
1947
1948 for (guint i = 0; i < n_values; i++) {
1949 Object item = value->arrayGet(i);
1950
1951 if (item.isString()) {
1952 result[i] = _poppler_goo_string_to_utf8(s: item.getString());
1953 } else if (item.isName()) {
1954 result[i] = g_strdup(str: item.getName());
1955 } else {
1956 g_assert_not_reached();
1957 }
1958 }
1959
1960 return result;
1961}
1962
1963/**
1964 * poppler_structure_element_get_table_scope:
1965 * @poppler_structure_element: A #PopplerStructureElement
1966 *
1967 * Obtains the scope of a table structure element.
1968 *
1969 * Return value: A #PopplerStructureTableScope value.
1970 *
1971 * Since: 0.26
1972 */
1973PopplerStructureTableScope poppler_structure_element_get_table_scope(PopplerStructureElement *poppler_structure_element)
1974{
1975 g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_TABLE, EnumNameValue<PopplerStructureTableScope>::values[0].value);
1976 return attr_to_enum<PopplerStructureTableScope>(poppler_structure_element);
1977}
1978
1979/**
1980 * poppler_structure_element_get_table_summary:
1981 * @poppler_structure_element: A #PopplerStructureElement
1982 *
1983 * Obtains the textual summary of the contents of the table element. Note that
1984 * the summary is meant for informative purposes, and it is not intended
1985 * to be rendered. For example, assistive technologies may use the
1986 * description field to provide an alternate way of presenting an element
1987 * to the user, or a document indexer may want to scan it for additional
1988 * keywords.
1989 *
1990 * The returned string is allocated by the function. When it is
1991 * not needed anymore, be sure to call g_free() on it.
1992 *
1993 * Return value: (transfer full): A string, or %NULL if the attribute
1994 * is not defined.
1995 *
1996 * Since: 0.26
1997 */
1998gchar *poppler_structure_element_get_table_summary(PopplerStructureElement *poppler_structure_element)
1999{
2000 g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
2001
2002 const Object *value = attr_value_or_default(poppler_structure_element, attribute_type: Attribute::Summary);
2003 if (value == nullptr) {
2004 return nullptr;
2005 }
2006 if (value->isString()) {
2007 return _poppler_goo_string_to_utf8(s: value->getString());
2008 }
2009 if (value->isName()) {
2010 return g_strdup(str: value->getName());
2011 }
2012
2013 g_assert_not_reached();
2014 return nullptr;
2015}
2016

source code of poppler/glib/poppler-structure-element.cc