blob: 4c6cd02630e9c94df2ec398b98c589dea8da900e [file] [log] [blame]
/* poppler-structure.cc: glib interface to poppler
*
* Copyright (C) 2013 Igalia S.L.
* Copyright (C) 2018 Albert Astals Cid <aacid@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "config.h"
#ifndef __GI_SCANNER__
# include <StructTreeRoot.h>
# include <StructElement.h>
# include <GlobalParams.h>
# include <UnicodeMap.h>
# include <cmath>
#endif /* !__GI_SCANNER__ */
#include "poppler.h"
#include "poppler-private.h"
#include "poppler-structure-element.h"
/**
* SECTION:poppler-structure-element
* @short_description: Document structure element.
* @title: PopplerStructureElement
*
* Instances of #PopplerStructureElement are used to describe the structure
* of a #PopplerDocument. To access the elements in the structure of the
* document, use poppler_structure_element_iter_new() to obtain an iterator
* for the top-level #PopplerStructureElement, and then use the
* #PopplerStructureElementIter methods to traverse the structure tree.
*/
typedef struct _PopplerStructureElementClass
{
GObjectClass parent_class;
} PopplerStructureElementClass;
G_DEFINE_TYPE(PopplerStructureElement, poppler_structure_element, G_TYPE_OBJECT)
static PopplerStructureElement *_poppler_structure_element_new(PopplerDocument *document, const StructElement *element)
{
PopplerStructureElement *poppler_structure_element;
g_assert(POPPLER_IS_DOCUMENT(document));
g_assert(element);
poppler_structure_element = (PopplerStructureElement *)g_object_new(POPPLER_TYPE_STRUCTURE_ELEMENT, nullptr, NULL);
poppler_structure_element->document = (PopplerDocument *)g_object_ref(document);
poppler_structure_element->elem = element;
return poppler_structure_element;
}
static void poppler_structure_element_init(PopplerStructureElement *poppler_structure_element) { }
static void poppler_structure_element_finalize(GObject *object)
{
PopplerStructureElement *poppler_structure_element = POPPLER_STRUCTURE_ELEMENT(object);
/* poppler_structure_element->elem is owned by the StructTreeRoot */
g_object_unref(poppler_structure_element->document);
G_OBJECT_CLASS(poppler_structure_element_parent_class)->finalize(object);
}
static void poppler_structure_element_class_init(PopplerStructureElementClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
gobject_class->finalize = poppler_structure_element_finalize;
}
/**
* poppler_structure_element_get_kind:
* @poppler_structure_element: A #PopplerStructureElement
*
* Return value: A #PopplerStructureElementKind value.
*
* Since: 0.26
*/
PopplerStructureElementKind poppler_structure_element_get_kind(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), POPPLER_STRUCTURE_ELEMENT_CONTENT);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, POPPLER_STRUCTURE_ELEMENT_CONTENT);
switch (poppler_structure_element->elem->getType()) {
case StructElement::MCID:
return POPPLER_STRUCTURE_ELEMENT_CONTENT;
case StructElement::OBJR:
return POPPLER_STRUCTURE_ELEMENT_OBJECT_REFERENCE;
case StructElement::Document:
return POPPLER_STRUCTURE_ELEMENT_DOCUMENT;
case StructElement::Part:
return POPPLER_STRUCTURE_ELEMENT_PART;
case StructElement::Art:
return POPPLER_STRUCTURE_ELEMENT_ARTICLE;
case StructElement::Sect:
return POPPLER_STRUCTURE_ELEMENT_SECTION;
case StructElement::Div:
return POPPLER_STRUCTURE_ELEMENT_DIV;
case StructElement::Span:
return POPPLER_STRUCTURE_ELEMENT_SPAN;
case StructElement::Quote:
return POPPLER_STRUCTURE_ELEMENT_QUOTE;
case StructElement::Note:
return POPPLER_STRUCTURE_ELEMENT_NOTE;
case StructElement::Reference:
return POPPLER_STRUCTURE_ELEMENT_REFERENCE;
case StructElement::BibEntry:
return POPPLER_STRUCTURE_ELEMENT_BIBENTRY;
case StructElement::Code:
return POPPLER_STRUCTURE_ELEMENT_CODE;
case StructElement::Link:
return POPPLER_STRUCTURE_ELEMENT_LINK;
case StructElement::Annot:
return POPPLER_STRUCTURE_ELEMENT_ANNOT;
case StructElement::BlockQuote:
return POPPLER_STRUCTURE_ELEMENT_BLOCKQUOTE;
case StructElement::Caption:
return POPPLER_STRUCTURE_ELEMENT_CAPTION;
case StructElement::NonStruct:
return POPPLER_STRUCTURE_ELEMENT_NONSTRUCT;
case StructElement::TOC:
return POPPLER_STRUCTURE_ELEMENT_TOC;
case StructElement::TOCI:
return POPPLER_STRUCTURE_ELEMENT_TOC_ITEM;
case StructElement::Index:
return POPPLER_STRUCTURE_ELEMENT_INDEX;
case StructElement::Private:
return POPPLER_STRUCTURE_ELEMENT_PRIVATE;
case StructElement::P:
return POPPLER_STRUCTURE_ELEMENT_PARAGRAPH;
case StructElement::H:
return POPPLER_STRUCTURE_ELEMENT_HEADING;
case StructElement::H1:
return POPPLER_STRUCTURE_ELEMENT_HEADING_1;
case StructElement::H2:
return POPPLER_STRUCTURE_ELEMENT_HEADING_2;
case StructElement::H3:
return POPPLER_STRUCTURE_ELEMENT_HEADING_3;
case StructElement::H4:
return POPPLER_STRUCTURE_ELEMENT_HEADING_4;
case StructElement::H5:
return POPPLER_STRUCTURE_ELEMENT_HEADING_5;
case StructElement::H6:
return POPPLER_STRUCTURE_ELEMENT_HEADING_6;
case StructElement::L:
return POPPLER_STRUCTURE_ELEMENT_LIST;
case StructElement::LI:
return POPPLER_STRUCTURE_ELEMENT_LIST_ITEM;
case StructElement::Lbl:
return POPPLER_STRUCTURE_ELEMENT_LIST_LABEL;
case StructElement::LBody:
return POPPLER_STRUCTURE_ELEMENT_LIST_BODY;
case StructElement::Table:
return POPPLER_STRUCTURE_ELEMENT_TABLE;
case StructElement::TR:
return POPPLER_STRUCTURE_ELEMENT_TABLE_ROW;
case StructElement::TH:
return POPPLER_STRUCTURE_ELEMENT_TABLE_HEADING;
case StructElement::TD:
return POPPLER_STRUCTURE_ELEMENT_TABLE_DATA;
case StructElement::THead:
return POPPLER_STRUCTURE_ELEMENT_TABLE_HEADER;
case StructElement::TFoot:
return POPPLER_STRUCTURE_ELEMENT_TABLE_FOOTER;
case StructElement::TBody:
return POPPLER_STRUCTURE_ELEMENT_TABLE_BODY;
case StructElement::Ruby:
return POPPLER_STRUCTURE_ELEMENT_RUBY;
case StructElement::RB:
return POPPLER_STRUCTURE_ELEMENT_RUBY_BASE_TEXT;
case StructElement::RT:
return POPPLER_STRUCTURE_ELEMENT_RUBY_ANNOT_TEXT;
case StructElement::RP:
return POPPLER_STRUCTURE_ELEMENT_RUBY_PUNCTUATION;
case StructElement::Warichu:
return POPPLER_STRUCTURE_ELEMENT_WARICHU;
case StructElement::WT:
return POPPLER_STRUCTURE_ELEMENT_WARICHU_TEXT;
case StructElement::WP:
return POPPLER_STRUCTURE_ELEMENT_WARICHU_PUNCTUATION;
case StructElement::Figure:
return POPPLER_STRUCTURE_ELEMENT_FIGURE;
case StructElement::Formula:
return POPPLER_STRUCTURE_ELEMENT_FORMULA;
case StructElement::Form:
return POPPLER_STRUCTURE_ELEMENT_FORM;
/* There should never be elements of type StructElement::Unknown */
case StructElement::Unknown:
g_assert_not_reached();
}
g_assert_not_reached();
return POPPLER_STRUCTURE_ELEMENT_CONTENT;
}
template<typename EnumType>
struct EnumNameValue
{
const gchar *name;
EnumType value;
static const EnumNameValue<EnumType> values[];
static const Attribute::Type attribute_type;
};
#define ENUM_VALUES(E, A) \
template<> \
const Attribute::Type EnumNameValue<E>::attribute_type = Attribute::A; \
template<> \
const EnumNameValue<E> EnumNameValue<E>::values[] =
ENUM_VALUES(PopplerStructurePlacement, Placement) { { "Block", POPPLER_STRUCTURE_PLACEMENT_BLOCK }, { "Inline", POPPLER_STRUCTURE_PLACEMENT_INLINE }, { "Before", POPPLER_STRUCTURE_PLACEMENT_BEFORE },
{ "Start", POPPLER_STRUCTURE_PLACEMENT_START }, { "End", POPPLER_STRUCTURE_PLACEMENT_END }, {} };
ENUM_VALUES(PopplerStructureWritingMode, WritingMode) { { "LrTb", POPPLER_STRUCTURE_WRITING_MODE_LR_TB }, { "RlTb", POPPLER_STRUCTURE_WRITING_MODE_RL_TB }, { "TbRl", POPPLER_STRUCTURE_WRITING_MODE_TB_RL }, {} };
ENUM_VALUES(PopplerStructureBorderStyle, BorderStyle) { { "None", POPPLER_STRUCTURE_BORDER_STYLE_NONE }, { "Hidden", POPPLER_STRUCTURE_BORDER_STYLE_HIDDEN },
{ "Dotted", POPPLER_STRUCTURE_BORDER_STYLE_DOTTED }, { "Dashed", POPPLER_STRUCTURE_BORDER_STYLE_DASHED },
{ "Solid", POPPLER_STRUCTURE_BORDER_STYLE_SOLID }, { "Double", POPPLER_STRUCTURE_BORDER_STYLE_DOUBLE },
{ "Groove", POPPLER_STRUCTURE_BORDER_STYLE_GROOVE }, { "Inset", POPPLER_STRUCTURE_BORDER_STYLE_INSET },
{ "Outset", POPPLER_STRUCTURE_BORDER_STYLE_OUTSET }, {} };
ENUM_VALUES(PopplerStructureTextAlign,
TextAlign) { { "Start", POPPLER_STRUCTURE_TEXT_ALIGN_START }, { "Center", POPPLER_STRUCTURE_TEXT_ALIGN_CENTER }, { "End", POPPLER_STRUCTURE_TEXT_ALIGN_END }, { "Justify", POPPLER_STRUCTURE_TEXT_ALIGN_JUSTIFY }, {} };
ENUM_VALUES(PopplerStructureBlockAlign,
BlockAlign) { { "Before", POPPLER_STRUCTURE_BLOCK_ALIGN_BEFORE }, { "Middle", POPPLER_STRUCTURE_BLOCK_ALIGN_MIDDLE }, { "After", POPPLER_STRUCTURE_BLOCK_ALIGN_AFTER }, { "Justify", POPPLER_STRUCTURE_BLOCK_ALIGN_JUSTIFY }, {} };
ENUM_VALUES(PopplerStructureInlineAlign, InlineAlign) { { "Start", POPPLER_STRUCTURE_INLINE_ALIGN_START }, { "Center", POPPLER_STRUCTURE_INLINE_ALIGN_CENTER }, { "End", POPPLER_STRUCTURE_INLINE_ALIGN_END }, {} };
ENUM_VALUES(PopplerStructureTextDecoration, TextDecorationType) { { "None", POPPLER_STRUCTURE_TEXT_DECORATION_NONE },
{ "Underline", POPPLER_STRUCTURE_TEXT_DECORATION_UNDERLINE },
{ "Overline", POPPLER_STRUCTURE_TEXT_DECORATION_OVERLINE },
{ "LineThrough", POPPLER_STRUCTURE_TEXT_DECORATION_LINETHROUGH },
{} };
ENUM_VALUES(PopplerStructureRubyAlign, RubyAlign) { { "Start", POPPLER_STRUCTURE_RUBY_ALIGN_START }, { "Center", POPPLER_STRUCTURE_RUBY_ALIGN_CENTER }, { "End", POPPLER_STRUCTURE_RUBY_ALIGN_END },
{ "Justify", POPPLER_STRUCTURE_RUBY_ALIGN_JUSTIFY }, { "Distribute", POPPLER_STRUCTURE_RUBY_ALIGN_DISTRIBUTE }, {} };
ENUM_VALUES(PopplerStructureRubyPosition, RubyPosition) {
{ "Before", POPPLER_STRUCTURE_RUBY_POSITION_BEFORE }, { "After", POPPLER_STRUCTURE_RUBY_POSITION_AFTER }, { "Warichu", POPPLER_STRUCTURE_RUBY_POSITION_WARICHU }, { "Inline", POPPLER_STRUCTURE_RUBY_POSITION_INLINE }, {}
};
ENUM_VALUES(PopplerStructureGlyphOrientation, GlyphOrientationVertical) { { "Auto", POPPLER_STRUCTURE_GLYPH_ORIENTATION_AUTO }, { "90", POPPLER_STRUCTURE_GLYPH_ORIENTATION_90 },
{ "180", POPPLER_STRUCTURE_GLYPH_ORIENTATION_180 }, { "270", POPPLER_STRUCTURE_GLYPH_ORIENTATION_270 },
{ "360", POPPLER_STRUCTURE_GLYPH_ORIENTATION_0 }, { "-90", POPPLER_STRUCTURE_GLYPH_ORIENTATION_270 },
{ "-180", POPPLER_STRUCTURE_GLYPH_ORIENTATION_180 }, {} };
ENUM_VALUES(PopplerStructureListNumbering, ListNumbering) { { "None", POPPLER_STRUCTURE_LIST_NUMBERING_NONE },
{ "Disc", POPPLER_STRUCTURE_LIST_NUMBERING_DISC },
{ "Circle", POPPLER_STRUCTURE_LIST_NUMBERING_CIRCLE },
{ "Square", POPPLER_STRUCTURE_LIST_NUMBERING_SQUARE },
{ "Decimal", POPPLER_STRUCTURE_LIST_NUMBERING_DECIMAL },
{ "UpperRoman", POPPLER_STRUCTURE_LIST_NUMBERING_UPPER_ROMAN },
{ "LowerRoman", POPPLER_STRUCTURE_LIST_NUMBERING_LOWER_ROMAN },
{ "UpperAlpha", POPPLER_STRUCTURE_LIST_NUMBERING_UPPER_ALPHA },
{ "LowerAlpha", POPPLER_STRUCTURE_LIST_NUMBERING_LOWER_ALPHA },
{} };
ENUM_VALUES(PopplerStructureFormRole,
Role) { { "rb", POPPLER_STRUCTURE_FORM_ROLE_RADIO_BUTTON }, { "cb", POPPLER_STRUCTURE_FORM_ROLE_CHECKBOX }, { "pb", POPPLER_STRUCTURE_FORM_ROLE_PUSH_BUTTON }, { "tv", POPPLER_STRUCTURE_FORM_ROLE_TEXT_VALUE }, {} };
ENUM_VALUES(PopplerStructureFormState, checked) { { "on", POPPLER_STRUCTURE_FORM_STATE_ON }, { "off", POPPLER_STRUCTURE_FORM_STATE_OFF }, { "neutral", POPPLER_STRUCTURE_FORM_STATE_NEUTRAL }, {} };
ENUM_VALUES(PopplerStructureTableScope, Scope) { { "Row", POPPLER_STRUCTURE_TABLE_SCOPE_ROW }, { "Column", POPPLER_STRUCTURE_TABLE_SCOPE_COLUMN }, { "Both", POPPLER_STRUCTURE_TABLE_SCOPE_BOTH }, {} };
#undef ENUM_VALUES
template<typename EnumType>
static EnumType name_to_enum(const Object *name_value)
{
/*
* Non-NULL names must always be valid because Poppler
* discards the invalid attributes when parsing them.
*/
g_assert(name_value != nullptr);
for (const EnumNameValue<EnumType> *item = EnumNameValue<EnumType>::values; item->name; item++) {
if (name_value->isName(item->name)) {
return item->value;
}
}
g_assert_not_reached();
return static_cast<EnumType>(-1);
}
template<typename EnumType>
static EnumType attr_to_enum(PopplerStructureElement *poppler_structure_element)
{
const Attribute *attr = poppler_structure_element->elem->findAttribute(EnumNameValue<EnumType>::attribute_type, true);
return name_to_enum<EnumType>((attr != nullptr) ? attr->getValue() : Attribute::getDefaultValue(EnumNameValue<EnumType>::attribute_type));
}
static inline const Object *attr_value_or_default(PopplerStructureElement *poppler_structure_element, Attribute::Type attribute_type)
{
const Attribute *attr = poppler_structure_element->elem->findAttribute(attribute_type, true);
return attr ? attr->getValue() : Attribute::getDefaultValue(attribute_type);
}
/**
* poppler_structure_element_get_page:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the page number in which the element is contained.
*
* Return value: Number of the page that contains the element, of
* <code>-1</code> if not defined.
*
* Since: 0.26
*/
gint poppler_structure_element_get_page(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), -1);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, -1);
Ref ref;
if (poppler_structure_element->elem->getPageRef(ref)) {
return poppler_structure_element->document->doc->findPage(ref) - 1;
}
return -1;
}
/**
* poppler_structure_element_is_content:
* @poppler_structure_element: A #PopplerStructureElement
*
* Checks whether an element is actual document content.
*
* Return value: %TRUE if the element is content, or %FALSE otherwise.
*
* Since: 0.26
*/
gboolean poppler_structure_element_is_content(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, FALSE);
return poppler_structure_element->elem->isContent();
}
/**
* poppler_structure_element_is_inline:
* @poppler_structure_element: A #PopplerStructureElement
*
* Checks whether an element is an inline element.
*
* Return value: %TRUE if the element is an inline element, or %FALSE otherwise.
*
* Since: 0.26
*/
gboolean poppler_structure_element_is_inline(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, FALSE);
return poppler_structure_element->elem->isInline();
}
/**
* poppler_structure_element_is_block:
* @poppler_structure_element: A #PopplerStructureElement
*
* Checks whether an element is a block element.
*
* Return value: %TRUE if the element is a block element, or %FALSE otherwise.
*
* Since: 0.26
*/
gboolean poppler_structure_element_is_block(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, FALSE);
return poppler_structure_element->elem->isBlock();
}
/**
* poppler_structure_element_is_grouping:
* @poppler_structure_element: A #PopplerStructureElement
*
* Checks whether an element is a grouping element.
*
* Return value: %TRUE if the element is a grouping element, %FALSE
* otherwise.
*
* Since: 0.26
*/
gboolean poppler_structure_element_is_grouping(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, FALSE);
return poppler_structure_element->elem->isGrouping();
}
/**
* poppler_structure_element_get_id:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the identifier of an element.
*
* Return value: (transfer full): The identifier of the element (if
* defined), or %NULL.
*
* Since: 0.26
*/
gchar *poppler_structure_element_get_id(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
const GooString *string = poppler_structure_element->elem->getID();
return string ? _poppler_goo_string_to_utf8(string) : nullptr;
}
/**
* poppler_structure_element_get_title:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the title of an element.
*
* Return value: (transfer full): The title of the element, or %NULL.
*
* Since: 0.26
*/
gchar *poppler_structure_element_get_title(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
const GooString *string = poppler_structure_element->elem->getTitle();
return string ? _poppler_goo_string_to_utf8(string) : nullptr;
}
/**
* poppler_structure_element_get_abbreviation:
* @poppler_structure_element: A #PopplerStructureElement
*
* Acronyms and abbreviations contained in elements of type
* #POPPLER_STRUCTURE_ELEMENT_SPAN may have an associated expanded
* text form, which can be retrieved using this function.
*
* Return value: (transfer full): Text of the expanded abbreviation if the
* element text is an abbreviation or acrony, %NULL if not.
*
* Since: 0.26
*/
gchar *poppler_structure_element_get_abbreviation(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
if (poppler_structure_element->elem->getType() != StructElement::Span) {
return nullptr;
}
const GooString *string = poppler_structure_element->elem->getExpandedAbbr();
return string ? _poppler_goo_string_to_utf8(string) : nullptr;
}
/**
* poppler_structure_element_get_language:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the language and country code for the content in an element,
* in two-letter ISO format, e.g. <code>en_ES</code>, or %NULL if not
* defined.
*
* Return value: (transfer full): language and country code, or %NULL.
*
* Since: 0.26
*/
gchar *poppler_structure_element_get_language(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
const GooString *string = poppler_structure_element->elem->getLanguage();
return string ? _poppler_goo_string_to_utf8(string) : nullptr;
}
/**
* poppler_structure_element_get_alt_text:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the “alternate” text representation of the element (and its child
* elements). This is mostly used for non-text elements like images and
* figures, to specify a textual description of the element.
*
* Note that for elements containing proper text, the function
* poppler_structure_element_get_text() must be used instead.
*
* Return value: (transfer full): The alternate text representation for the
* element, or %NULL if not defined.
*
* Since: 0.26
*/
gchar *poppler_structure_element_get_alt_text(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
const GooString *string = poppler_structure_element->elem->getAltText();
return string ? _poppler_goo_string_to_utf8(string) : nullptr;
}
/**
* poppler_structure_element_get_actual_text:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the actual text enclosed by the element (and its child elements).
* The actual text is mostly used for non-text elements like images and
* figures which <emphasis>do</emphasis> have the graphical appearance of text, like
* a logo. For those the actual text is the equivalent text to those
* graphical elements which look like text when rendered.
*
* Note that for elements containing proper text, the function
* poppler_structure_element_get_text() must be used instead.
*
* Return value: (transfer full): The actual text for the element, or %NULL
* if not defined.
*
* Since: 0.26
*/
gchar *poppler_structure_element_get_actual_text(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
const GooString *string = poppler_structure_element->elem->getActualText();
return string ? _poppler_goo_string_to_utf8(string) : nullptr;
}
/**
* poppler_structure_element_get_text:
* @poppler_structure_element: A #PopplerStructureElement
* @flags: A #PopplerStructureGetTextFlags value, or
* %POPPLER_STRUCTURE_GET_TEXT_NONE to disable all the flags.
*
* Obtains the text enclosed by an element, or the text enclosed by the
* elements in the subtree (including the element itself).
*
* Return value: (transfer full): A string.
*
* Since: 0.26
*/
gchar *poppler_structure_element_get_text(PopplerStructureElement *poppler_structure_element, PopplerStructureGetTextFlags flags)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
GooString *string = poppler_structure_element->elem->getText(flags & POPPLER_STRUCTURE_GET_TEXT_RECURSIVE);
gchar *result = string ? _poppler_goo_string_to_utf8(string) : nullptr;
delete string;
return result;
}
struct _PopplerStructureElementIter
{
PopplerDocument *document;
union {
const StructElement *elem;
const StructTreeRoot *root;
};
gboolean is_root;
unsigned index;
};
G_DEFINE_BOXED_TYPE(PopplerStructureElementIter, poppler_structure_element_iter, poppler_structure_element_iter_copy, poppler_structure_element_iter_free)
/**
* poppler_structure_element_iter_copy:
* @iter: a #PopplerStructureElementIter
*
* Creates a new #PopplerStructureElementIter as a copy of @iter. The
* returned value must be freed with poppler_structure_element_iter_free().
*
* Return value: (transfer full): a new #PopplerStructureElementIter
*
* Since: 0.26
*/
PopplerStructureElementIter *poppler_structure_element_iter_copy(PopplerStructureElementIter *iter)
{
PopplerStructureElementIter *new_iter;
g_return_val_if_fail(iter != nullptr, NULL);
new_iter = g_slice_dup(PopplerStructureElementIter, iter);
new_iter->document = (PopplerDocument *)g_object_ref(new_iter->document);
return new_iter;
}
/**
* poppler_structure_element_iter_free:
* @iter: a #PopplerStructureElementIter
*
* Frees @iter.
*
* Since: 0.26
*/
void poppler_structure_element_iter_free(PopplerStructureElementIter *iter)
{
if (G_UNLIKELY(iter == nullptr)) {
return;
}
g_object_unref(iter->document);
g_slice_free(PopplerStructureElementIter, iter);
}
/**
* poppler_structure_element_iter_new:
* @poppler_document: a #PopplerDocument.
*
* Returns the root #PopplerStructureElementIter for @document, or %NULL. The
* returned value must be freed with poppler_structure_element_iter_free().
*
* Documents may have an associated structure tree &mdash;mostly, Tagged-PDF
* compliant documents&mdash; which can be used to obtain information about
* the document structure and its contents. Each node in the tree contains
* a #PopplerStructureElement.
*
* Here is a simple example that walks the whole tree:
*
* <informalexample><programlisting>
* static void
* walk_structure (PopplerStructureElementIter *iter)
* {
* do {
* /<!-- -->* Get the element and do something with it *<!-- -->/
* PopplerStructureElementIter *child = poppler_structure_element_iter_get_child (iter);
* if (child)
* walk_structure (child);
* poppler_structure_element_iter_free (child);
* } while (poppler_structure_element_iter_next (iter));
* }
* ...
* {
* iter = poppler_structure_element_iter_new (document);
* walk_structure (iter);
* poppler_structure_element_iter_free (iter);
* }
* </programlisting></informalexample>
*
* Return value: (transfer full): a new #PopplerStructureElementIter, or %NULL if document
* doesn't have structure tree.
*
* Since: 0.26
*/
PopplerStructureElementIter *poppler_structure_element_iter_new(PopplerDocument *poppler_document)
{
PopplerStructureElementIter *iter;
g_return_val_if_fail(POPPLER_IS_DOCUMENT(poppler_document), NULL);
const StructTreeRoot *root = poppler_document->doc->getStructTreeRoot();
if (root == nullptr) {
return nullptr;
}
if (root->getNumChildren() == 0) {
return nullptr;
}
iter = g_slice_new0(PopplerStructureElementIter);
iter->document = (PopplerDocument *)g_object_ref(poppler_document);
iter->is_root = TRUE;
iter->root = root;
return iter;
}
/**
* poppler_structure_element_iter_next:
* @iter: a #PopplerStructureElementIter
*
* Sets @iter to point to the next structure element at the current level
* of the tree, if valid. See poppler_structure_element_iter_new() for more
* information.
*
* Return value: %TRUE, if @iter was set to the next structure element
*
* Since: 0.26
*/
gboolean poppler_structure_element_iter_next(PopplerStructureElementIter *iter)
{
unsigned elements;
g_return_val_if_fail(iter != nullptr, FALSE);
elements = iter->is_root ? iter->root->getNumChildren() : iter->elem->getNumChildren();
return ++iter->index < elements;
}
/**
* poppler_structure_element_iter_get_element:
* @iter: a #PopplerStructureElementIter
*
* Returns the #PopplerStructureElementIter associated with @iter.
*
* Return value: (transfer full): a new #PopplerStructureElementIter
*
* Since: 0.26
*/
PopplerStructureElement *poppler_structure_element_iter_get_element(PopplerStructureElementIter *iter)
{
g_return_val_if_fail(iter != nullptr, NULL);
const StructElement *elem = iter->is_root ? iter->root->getChild(iter->index) : iter->elem->getChild(iter->index);
return _poppler_structure_element_new(iter->document, elem);
}
/**
* poppler_structure_element_iter_get_child:
* @parent: a #PopplerStructureElementIter
*
* Returns a new iterator to the children elements of the
* #PopplerStructureElement associated with @iter. The returned value must
* be freed with poppler_structure_element_iter_free().
*
* Return value: a new #PopplerStructureElementIter
*
* Since: 0.26
*/
PopplerStructureElementIter *poppler_structure_element_iter_get_child(PopplerStructureElementIter *parent)
{
const StructElement *elem;
g_return_val_if_fail(parent != nullptr, NULL);
elem = parent->is_root ? parent->root->getChild(parent->index) : parent->elem->getChild(parent->index);
if (elem->getNumChildren() > 0) {
PopplerStructureElementIter *child = g_slice_new0(PopplerStructureElementIter);
child->document = (PopplerDocument *)g_object_ref(parent->document);
child->elem = elem;
return child;
}
return nullptr;
}
struct _PopplerTextSpan
{
gchar *text;
gchar *font_name;
guint flags;
PopplerColor color;
};
G_DEFINE_BOXED_TYPE(PopplerTextSpan, poppler_text_span, poppler_text_span_copy, poppler_text_span_free)
enum
{
POPPLER_TEXT_SPAN_FIXED_WIDTH = (1 << 0),
POPPLER_TEXT_SPAN_SERIF = (1 << 1),
POPPLER_TEXT_SPAN_ITALIC = (1 << 2),
POPPLER_TEXT_SPAN_BOLD = (1 << 3),
};
static PopplerTextSpan *text_span_poppler_text_span(const TextSpan &span)
{
PopplerTextSpan *new_span = g_slice_new0(PopplerTextSpan);
if (GooString *text = span.getText()) {
new_span->text = _poppler_goo_string_to_utf8(text);
}
new_span->color.red = colToDbl(span.getColor().r) * 65535;
new_span->color.green = colToDbl(span.getColor().g) * 65535;
new_span->color.blue = colToDbl(span.getColor().b) * 65535;
if (span.getFont()) {
// GfxFont sometimes does not have a family name but there
// is always a font name that can be used as fallback.
const GooString *font_name = span.getFont()->getFamily();
if (font_name) {
new_span->font_name = _poppler_goo_string_to_utf8(font_name);
} else if (span.getFont()->getName()) {
const GooString aux(*span.getFont()->getName());
new_span->font_name = _poppler_goo_string_to_utf8(&aux);
} else {
new_span->font_name = nullptr;
}
if (span.getFont()->isFixedWidth()) {
new_span->flags |= POPPLER_TEXT_SPAN_FIXED_WIDTH;
}
if (span.getFont()->isSerif()) {
new_span->flags |= POPPLER_TEXT_SPAN_SERIF;
}
if (span.getFont()->isItalic()) {
new_span->flags |= POPPLER_TEXT_SPAN_ITALIC;
}
if (span.getFont()->isBold()) {
new_span->flags |= POPPLER_TEXT_SPAN_BOLD;
}
/* isBold() can return false for some fonts whose weight is heavy */
switch (span.getFont()->getWeight()) {
case GfxFont::W500:
case GfxFont::W600:
case GfxFont::W700:
case GfxFont::W800:
case GfxFont::W900:
new_span->flags |= POPPLER_TEXT_SPAN_BOLD;
default:
break;
}
}
return new_span;
}
/**
* poppler_text_span_copy:
* @poppler_text_span: a #PopplerTextSpan
*
* Makes a copy of a text span.
*
* Return value: (transfer full): A new #PopplerTextSpan
*
* Since: 0.26
*/
PopplerTextSpan *poppler_text_span_copy(PopplerTextSpan *poppler_text_span)
{
PopplerTextSpan *new_span;
g_return_val_if_fail(poppler_text_span != nullptr, NULL);
new_span = g_slice_dup(PopplerTextSpan, poppler_text_span);
new_span->text = g_strdup(poppler_text_span->text);
if (poppler_text_span->font_name) {
new_span->font_name = g_strdup(poppler_text_span->font_name);
}
return new_span;
}
/**
* poppler_text_span_free:
* @poppler_text_span: A #PopplerTextSpan
*
* Frees a text span.
*
* Since: 0.26
*/
void poppler_text_span_free(PopplerTextSpan *poppler_text_span)
{
if (G_UNLIKELY(poppler_text_span == nullptr)) {
return;
}
g_free(poppler_text_span->text);
g_free(poppler_text_span->font_name);
g_slice_free(PopplerTextSpan, poppler_text_span);
}
/**
* poppler_text_span_is_fixed_width_font:
* @poppler_text_span: a #PopplerTextSpan
*
* Check wether a text span is meant to be rendered using a fixed-width font.
*
* Return value: Whether the span uses a fixed-width font.
*
* Since: 0.26
*/
gboolean poppler_text_span_is_fixed_width_font(PopplerTextSpan *poppler_text_span)
{
g_return_val_if_fail(poppler_text_span != nullptr, FALSE);
return (poppler_text_span->flags & POPPLER_TEXT_SPAN_FIXED_WIDTH);
}
/**
* poppler_text_span_is_serif_font:
* @poppler_text_span: a #PopplerTextSpan
*
* Check whether a text span is meant to be rendered using a serif font.
*
* Return value: Whether the span uses a serif font.
*
* Since: 0.26
*/
gboolean poppler_text_span_is_serif_font(PopplerTextSpan *poppler_text_span)
{
g_return_val_if_fail(poppler_text_span != nullptr, FALSE);
return (poppler_text_span->flags & POPPLER_TEXT_SPAN_SERIF);
}
/**
* poppler_text_span_is_bold_font:
* @poppler_text_span: a #PopplerTextSpan
*
* Check whether a text span is meant to be rendered using a bold font.
*
* Return value: Whether the span uses bold font.
*
* Since: 0.26
*/
gboolean poppler_text_span_is_bold_font(PopplerTextSpan *poppler_text_span)
{
g_return_val_if_fail(poppler_text_span != nullptr, FALSE);
return (poppler_text_span->flags & POPPLER_TEXT_SPAN_BOLD);
}
/**
* poppler_text_span_get_color:
* @poppler_text_span: a #PopplerTextSpan
* @color: (out): a return location for a #PopplerColor
*
* Obtains the color in which the text is to be rendered.
*
* Since: 0.26
*/
void poppler_text_span_get_color(PopplerTextSpan *poppler_text_span, PopplerColor *color)
{
g_return_if_fail(poppler_text_span != nullptr);
g_return_if_fail(color != nullptr);
*color = poppler_text_span->color;
}
/**
* poppler_text_span_get_text:
* @poppler_text_span: a #PopplerTextSpan
*
* Obtains the text contained in the span.
*
* Return value: (transfer none): A string.
*
* Since: 0.26
*/
const gchar *poppler_text_span_get_text(PopplerTextSpan *poppler_text_span)
{
g_return_val_if_fail(poppler_text_span != nullptr, NULL);
return poppler_text_span->text;
}
/**
* poppler_text_span_get_font_name:
* @poppler_text_span: a #PopplerTextSpan
*
* Obtains the name of the font in which the span is to be rendered.
*
* Return value: (transfer none): A string containing the font name, or
* %NULL if a font is not defined.
*
* Since: 0.26
*/
const gchar *poppler_text_span_get_font_name(PopplerTextSpan *poppler_text_span)
{
g_return_val_if_fail(poppler_text_span != nullptr, NULL);
return poppler_text_span->font_name;
}
/**
* poppler_structure_element_get_text_spans:
* @poppler_structure_element: A #PopplerStructureElement
* @n_text_spans: (out): A pointer to the location where the number of elements in
* the returned array will be stored.
*
* Obtains the text enclosed by an element, as an array of #PopplerTextSpan
* structures. Each item in the list is a piece of text which share the same
* attributes, plus its attributes. The following example shows how to
* obtain and free the text spans of an element:
*
* <informalexample><programlisting>
* guint i, n_spans;
* PopplerTextSpan **text_spans =
* poppler_structure_element_get_text_spans (element, &n_spans);
* /<!-- -->* Use the text spans *<!-- -->/
* for (i = 0; i < n_spans; i++)
* poppler_text_span_free (text_spans[i]);
* g_free (text_spans);
* </programlisting></informalexample>
*
* Return value: (transfer full) (array length=n_text_spans) (element-type PopplerTextSpan):
* An array of #PopplerTextSpan elements.
*
* Since: 0.26
*/
PopplerTextSpan **poppler_structure_element_get_text_spans(PopplerStructureElement *poppler_structure_element, guint *n_text_spans)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
g_return_val_if_fail(n_text_spans != nullptr, NULL);
g_return_val_if_fail(poppler_structure_element->elem != nullptr, NULL);
if (!poppler_structure_element->elem->isContent()) {
return nullptr;
}
const TextSpanArray spans(poppler_structure_element->elem->getTextSpans());
PopplerTextSpan **text_spans = g_new0(PopplerTextSpan *, spans.size());
size_t i = 0;
for (const TextSpan &s : spans) {
text_spans[i++] = text_span_poppler_text_span(s);
}
*n_text_spans = spans.size();
return text_spans;
}
/* General Layout Attributes */
/**
* poppler_structure_element_get_placement:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the placement type of the structure element.
*
* Return value: A #PopplerStructurePlacement value.
*
* Since: 0.26
*/
PopplerStructurePlacement poppler_structure_element_get_placement(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), EnumNameValue<PopplerStructurePlacement>::values[0].value);
return attr_to_enum<PopplerStructurePlacement>(poppler_structure_element);
}
/**
* poppler_structure_element_get_writing_mode:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the writing mode (writing direction) of the content associated
* with a structure element.
*
* Return value: A #PopplerStructureWritingMode value.
*
* Since: 0.26
*/
PopplerStructureWritingMode poppler_structure_element_get_writing_mode(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), EnumNameValue<PopplerStructureWritingMode>::values[0].value);
return attr_to_enum<PopplerStructureWritingMode>(poppler_structure_element);
}
static void convert_border_style(const Object *object, PopplerStructureBorderStyle *values)
{
g_assert(object != nullptr);
g_assert(values != nullptr);
if (object->isArray()) {
g_assert(object->arrayGetLength() == 4);
for (guint i = 0; i < 4; i++) {
Object item = object->arrayGet(i);
values[i] = name_to_enum<PopplerStructureBorderStyle>(&item);
}
} else {
values[0] = values[1] = values[2] = values[3] = name_to_enum<PopplerStructureBorderStyle>(object);
}
}
/**
* poppler_structure_element_get_border_style:
* @poppler_structure_element: A #PopplerStructureElement
* @border_styles: (out) (array fixed-size=4) (element-type PopplerStructureBorderStyle):
* An array of four #PopplerStructureBorderStyle elements.
*
* Obtains the border style of a structure element. The result values
* are in before-after-start-end ordering. For example, using Western
* left-to-right writing, that is top-bottom-left-right.
*
* Since: 0.26
*/
void poppler_structure_element_get_border_style(PopplerStructureElement *poppler_structure_element, PopplerStructureBorderStyle *border_styles)
{
g_return_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element));
g_return_if_fail(border_styles != nullptr);
convert_border_style(attr_value_or_default(poppler_structure_element, Attribute::BorderStyle), border_styles);
}
static inline void convert_doubles_array(const Object *object, gdouble **values, guint *n_values)
{
g_assert(object->isArray());
g_assert(n_values != nullptr);
g_assert(values != nullptr);
*n_values = object->arrayGetLength();
gdouble *doubles = g_new(gdouble, *n_values);
for (guint i = 0; i < *n_values; i++) {
doubles[i] = object->arrayGet(i).getNum();
}
values = &doubles;
}
static inline void convert_color(const Object *object, PopplerColor *color)
{
g_assert(color != nullptr);
g_assert(object->isArray() && object->arrayGetLength() != 3);
color->red = object->arrayGet(0).getNum() * 65535;
color->green = object->arrayGet(1).getNum() * 65535;
color->blue = object->arrayGet(2).getNum() * 65535;
}
/**
* poppler_structure_element_get_color:
* @poppler_structure_element: A #PopplerStructureElement
* @color: (out): A #PopplerColor.
*
* Obtains the color of the content contained in the element.
* If this attribute is not specified, the color for this element shall
* be the current text fill color in effect at the start of its associated content.
*
* Return value: %TRUE if a color is defined for the element,
* %FALSE otherwise.
*
* Since: 0.26
*/
gboolean poppler_structure_element_get_color(PopplerStructureElement *poppler_structure_element, PopplerColor *color)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
g_return_val_if_fail(color != nullptr, FALSE);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::Color);
if (value == nullptr) {
return FALSE;
}
convert_color(value, color);
return TRUE;
}
/**
* poppler_structure_element_get_background_color:
* @poppler_structure_element: A #PopplerStructureElement
* @color: (out): A #PopplerColor.
*
* Obtains the background color of the element. If this attribute is
* not specified, the element shall be treated as if it were transparent.
*
* Return value: %TRUE if a color is defined for the element,
* %FALSE otherwise.
*
* Since: 0.26
*/
gboolean poppler_structure_element_get_background_color(PopplerStructureElement *poppler_structure_element, PopplerColor *color)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
g_return_val_if_fail(color != nullptr, FALSE);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::BackgroundColor);
if (value == nullptr) {
return FALSE;
}
convert_color(value, color);
return TRUE;
}
/**
* poppler_structure_element_get_border_color:
* @poppler_structure_element: A #PopplerStructureElement
* @colors: (out) (array fixed-size=4) (element-type PopplerColor): An array
* of four #PopplerColor.
*
* Obtains the color of border around the element. The result values
* are in before-after-start-end ordering (for the typical Western
* left-to-right writing, that is top-bottom-left-right).
* If this attribute is not specified, the border color for this element shall
* be the current text fill color in effect at the start of its associated
* content.
*
* Return value: %TRUE if a color is defined for the element,
* %FALSE otherwise.
*
* Since: 0.26
*/
gboolean poppler_structure_element_get_border_color(PopplerStructureElement *poppler_structure_element, PopplerColor *colors)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
g_return_val_if_fail(colors != nullptr, FALSE);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::BorderColor);
if (value == nullptr) {
return FALSE;
}
g_assert(value->isArray());
if (value->arrayGetLength() == 4) {
// One color per side.
for (guint i = 0; i < 4; i++) {
Object item = value->arrayGet(i);
convert_color(&item, &colors[i]);
}
} else {
// Same color in all sides.
g_assert(value->arrayGetLength() == 3);
convert_color(value, &colors[0]);
colors[1] = colors[2] = colors[3] = colors[0];
}
return TRUE;
}
static inline void convert_double_or_4_doubles(const Object *object, gdouble *value)
{
g_assert(object != nullptr);
if (object->isArray()) {
g_assert(object->arrayGetLength() == 4);
for (guint i = 0; i < 4; i++) {
value[i] = object->arrayGet(i).getNum();
}
} else {
g_assert(object->isNum());
value[0] = value[1] = value[2] = value[3] = object->getNum();
}
}
/**
* poppler_structure_element_get_border_thickness:
* @poppler_structure_element: A #PopplerStructureElement
* @border_thicknesses: (out) (array fixed-size=4) (element-type gdouble):
* Array with the four values of border thicknesses.
*
* Obtains the thickness of the border of an element. The result values
* are in before-after-start-end ordering (for the typical Western
* left-to-right writing, that is top-bottom-left-right).
* A value of 0 indicates that the border shall not be drawn.
*
* Return value: %TRUE if the border thickness attribute is defined for
* the element, %FALSE otherwise.
*
* Since: 0.26
*/
gboolean poppler_structure_element_get_border_thickness(PopplerStructureElement *poppler_structure_element, gdouble *border_thicknesses)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), FALSE);
g_return_val_if_fail(border_thicknesses != nullptr, FALSE);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::BorderThickness);
if (value == nullptr) {
return FALSE;
}
convert_double_or_4_doubles(value, border_thicknesses);
return TRUE;
}
/**
* poppler_structure_element_get_padding:
* @poppler_structure_element: A #PopplerStructureElement
* @paddings: (out) (array fixed-size=4) (element-type gdouble):
* Padding for the four sides of the element.
*
* Obtains the padding of an element (space around it). The result
* values are in before-after-start-end ordering. For example using
* Western left-to-right writing, that is top-bottom-left-right.
*
* Since: 0.26
*/
void poppler_structure_element_get_padding(PopplerStructureElement *poppler_structure_element, gdouble *paddings)
{
g_return_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element));
g_return_if_fail(paddings != nullptr);
convert_double_or_4_doubles(attr_value_or_default(poppler_structure_element, Attribute::Padding), paddings);
}
/* Layout Attributes for block-level structure elements */
/**
* poppler_structure_element_get_space_before:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the amount of empty space before the block-level structure element.
*
* Return value: A positive value.
*
* Since: 0.26
*/
gdouble poppler_structure_element_get_space_before(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
return attr_value_or_default(poppler_structure_element, Attribute::SpaceBefore)->getNum();
}
/**
* poppler_structure_element_get_space_after:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the amount of empty space after the block-level structure element.
*
* Return value: A positive value.
*
* Since: 0.26
*/
gdouble poppler_structure_element_get_space_after(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
return attr_value_or_default(poppler_structure_element, Attribute::SpaceAfter)->getNum();
}
/**
* poppler_structure_element_get_start_indent:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the amount of indentation at the beginning of the block-level structure element.
*
* Return value: A numeric value.
*
* Since: 0.26
*/
gdouble poppler_structure_element_get_start_indent(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
return attr_value_or_default(poppler_structure_element, Attribute::StartIndent)->getNum();
}
/**
* poppler_structure_element_get_end_indent:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the amount of indentation at the end of the block-level structure element.
*
* Return value: A numeric value.
*
* Since: 0.26
*/
gdouble poppler_structure_element_get_end_indent(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
return attr_value_or_default(poppler_structure_element, Attribute::EndIndent)->getNum();
}
/**
* poppler_structure_element_get_text_indent:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the amount of indentation of the text contained in the block-level structure element.
*
* Return value: A numeric value.
*
* Since: 0.26
*/
gdouble poppler_structure_element_get_text_indent(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
return attr_value_or_default(poppler_structure_element, Attribute::TextIndent)->getNum();
}
/**
* poppler_structure_element_get_text_align:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the text alignment mode of the text contained into a
* block-level structure element.
*
* Return value: A #PopplerStructureTextAlign value.
*
* Since: 0.26
*/
PopplerStructureTextAlign poppler_structure_element_get_text_align(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), EnumNameValue<PopplerStructureTextAlign>::values[0].value);
return attr_to_enum<PopplerStructureTextAlign>(poppler_structure_element);
}
/**
* poppler_structure_element_get_bounding_box:
* @poppler_structure_element: A #PopplerStructureElement
* @bounding_box: (out): A #PopplerRectangle.
*
* Obtains the size of the bounding box of a block-level structure element.
*
* Return value: %TRUE if a bounding box is defined for the element,
* %FALSE otherwise.
*
* Since: 0.26
*/
gboolean poppler_structure_element_get_bounding_box(PopplerStructureElement *poppler_structure_element, PopplerRectangle *bounding_box)
{
g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), FALSE);
g_return_val_if_fail(bounding_box != nullptr, FALSE);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::BBox);
if (value == nullptr) {
return FALSE;
}
gdouble dimensions[4];
convert_double_or_4_doubles(value, dimensions);
bounding_box->x1 = dimensions[0];
bounding_box->y1 = dimensions[1];
bounding_box->x2 = dimensions[2];
bounding_box->y2 = dimensions[3];
return TRUE;
}
/**
* poppler_structure_element_get_width:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the width of the block-level structure element. Note that for elements which do
* not specify a width, it has to be calculated, and in this case -1 is returned.
*
* Return value: A positive value if a width is defined, or -1
* if the width is to be calculated automatically.
*
* Since: 0.26
*/
gdouble poppler_structure_element_get_width(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::Width);
return value->isName("Auto") ? -1.0 : value->getNum();
}
/**
* poppler_structure_element_get_height:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the height of the block-level structure element. Note that for elements which do
* not specify a height, it has to be calculated, and in this case -1 is returned.
*
* Return value: A positive value if a width is defined, or -1
* if the height is to be calculated automatically.
*
* Since: 0.26
*/
gdouble poppler_structure_element_get_height(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), NAN);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::Height);
return value->isName("Auto") ? -1.0 : value->getNum();
}
/**
* poppler_structure_element_get_block_align:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the block-alignment mode of the block-level structure element.
*
* Return value: A #PopplerStructureBlockAlign value.
*
* Since: 0.26
*/
PopplerStructureBlockAlign poppler_structure_element_get_block_align(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), EnumNameValue<PopplerStructureBlockAlign>::values[0].value);
return attr_to_enum<PopplerStructureBlockAlign>(poppler_structure_element);
}
/**
* poppler_structure_element_get_inline_align:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the inline-alignment mode of the block-level structure element.
*
* Return value: A #PopplerStructureInlineAlign value.
*
* Since: 0.26
*/
PopplerStructureInlineAlign poppler_structure_element_get_inline_align(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_block(poppler_structure_element), EnumNameValue<PopplerStructureInlineAlign>::values[0].value);
return attr_to_enum<PopplerStructureInlineAlign>(poppler_structure_element);
}
/**
* poppler_structure_element_get_table_border_style:
* @poppler_structure_element: A #PopplerStructureElement
* @border_styles: (out) (array fixed-size=4) (element-type PopplerStructureBorderStyle):
* An array of four #PopplerStructureBorderStyle elements.
*
* Obtains the table cell border style of a block-level structure element. The result values
* are in before-after-start-end ordering. For example, using Western
* left-to-right writing, that is top-bottom-left-right.
*
* Since: 0.26
*/
void poppler_structure_element_get_table_border_style(PopplerStructureElement *poppler_structure_element, PopplerStructureBorderStyle *border_styles)
{
g_return_if_fail(poppler_structure_element_is_block(poppler_structure_element));
g_return_if_fail(border_styles != nullptr);
convert_border_style(attr_value_or_default(poppler_structure_element, Attribute::TBorderStyle), border_styles);
}
/**
* poppler_structure_element_get_table_padding:
* @poppler_structure_element: A #PopplerStructureElement
* @paddings: (out) (array fixed-size=4) (element-type gdouble):
* Padding for the four sides of the element.
*
* Obtains the padding between the table cell’s content rectangle and the
* surrounding border of a block-level structure element. The result
* values are in before-after-start-end ordering (for the typical
* Western left-to-right writing, that is top-bottom-left-right).
*
* Since: 0.26
*/
void poppler_structure_element_get_table_padding(PopplerStructureElement *poppler_structure_element, gdouble *paddings)
{
g_return_if_fail(poppler_structure_element_is_block(poppler_structure_element));
g_return_if_fail(paddings != nullptr);
convert_double_or_4_doubles(attr_value_or_default(poppler_structure_element, Attribute::TPadding), paddings);
}
/* Layout Attributes for inline-level structure elements */
/**
* poppler_structure_element_get_baseline_shift:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains how much the text contained in the inline-level structure element should be shifted,
* measuring from the baseline of the glyphs.
*
* Return value: A numeric value.
*
* Since: 0.26
*/
gdouble poppler_structure_element_get_baseline_shift(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), NAN);
return attr_value_or_default(poppler_structure_element, Attribute::BaselineShift)->getNum();
}
/**
* poppler_structure_element_get_line_height:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the line height for the text contained in the inline-level structure element.
* Note that for elements which do not specify a line height, it has to be calculated,
* and in this case -1 is returned.
*
* Return value: A positive value if a line height is defined, or -1
* if the height is to be calculated automatically.
*
* Since: 0.26
*/
gdouble poppler_structure_element_get_line_height(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), NAN);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::LineHeight);
return (value->isName("Normal") || value->isName("Auto")) ? -1.0 : value->getNum();
}
/**
* poppler_structure_element_get_text_decoration_color:
* @poppler_structure_element: A #PopplerStructureElement
* @color: (out): A #PopplerColor.
*
* Obtains the color of the text decoration for the text contained
* in the inline-level structure element.
* If this attribute is not specified, the color for this element shall be the current fill
* color in effect at the start of its associated content.
*
* Return value: %TRUE if a color is defined for the element,
* %FALSE otherwise.
*
* Since: 0.26
*/
gboolean poppler_structure_element_get_text_decoration_color(PopplerStructureElement *poppler_structure_element, PopplerColor *color)
{
g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), FALSE);
g_return_val_if_fail(color != nullptr, FALSE);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::TextDecorationColor);
if (value == nullptr) {
return FALSE;
}
convert_color(value, color);
return FALSE;
}
/**
* poppler_structure_element_get_text_decoration_thickness:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the thickness of the text decoration for the text contained
* in the inline-level structure element.
* If this attribute is not specified, it shall be derived from the current
* stroke thickness in effect at the start of the element’s associated content.
*
* Return value: Thickness of the text decoration, or NAN if not defined.
*
* Since: 0.26
*/
gdouble poppler_structure_element_get_text_decoration_thickness(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), NAN);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::TextDecorationThickness);
return (value == nullptr) ? NAN : value->getNum();
}
/**
* poppler_structure_element_get_text_decoration_type:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the text decoration type of the text contained in the
* inline-level structure element.
*
* Return value: A #PopplerStructureTextDecoration value.
*
* Since: 0.26
*/
PopplerStructureTextDecoration poppler_structure_element_get_text_decoration_type(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), EnumNameValue<PopplerStructureTextDecoration>::values[0].value);
return attr_to_enum<PopplerStructureTextDecoration>(poppler_structure_element);
}
/**
* poppler_structure_element_get_ruby_align:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the alignment for the ruby text contained in a
* inline-level structure element.
*
* Return value: A #PopplerStructureRubyAlign value.
*
* Since: 0.26
*/
PopplerStructureRubyAlign poppler_structure_element_get_ruby_align(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), EnumNameValue<PopplerStructureRubyAlign>::values[0].value);
return attr_to_enum<PopplerStructureRubyAlign>(poppler_structure_element);
}
/**
* poppler_structure_element_get_ruby_position:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the position for the ruby text contained in a
* inline-level structure element.
*
* Return value: A #PopplerStructureRubyPosition value.
*
* Since: 0.26
*/
PopplerStructureRubyPosition poppler_structure_element_get_ruby_position(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), EnumNameValue<PopplerStructureRubyPosition>::values[0].value);
return attr_to_enum<PopplerStructureRubyPosition>(poppler_structure_element);
}
/**
* poppler_structure_element_get_glyph_orientation:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the glyph orientation for the text contained in a
* inline-level structure element.
*
* Return value: A #PopplerStructureGlyphOrientation value.
*
* Since: 0.26
*/
PopplerStructureGlyphOrientation poppler_structure_element_get_glyph_orientation(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_inline(poppler_structure_element), EnumNameValue<PopplerStructureGlyphOrientation>::values[0].value);
return attr_to_enum<PopplerStructureGlyphOrientation>(poppler_structure_element);
}
/* Column Attributes */
/**
* poppler_structure_element_get_column_count:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the number of columns used to lay out the content contained
* in the grouping element.
*
* Return value: Number of columns.
*
* Since: 0.26
*/
guint poppler_structure_element_get_column_count(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_is_grouping(poppler_structure_element), 0);
return static_cast<guint>(attr_value_or_default(poppler_structure_element, Attribute::ColumnCount)->getInt());
}
/**
* poppler_structure_element_get_column_gaps:
* @poppler_structure_element: A #PopplerStructureElement
* @n_values: (out): Size of the returned array.
*
* Obtains the size of the gaps in between adjacent columns. Returns an
* array of elements: the first one is the size of the gap in between
* columns 1 and 2, second is the size between columns 2 and 3, and so on.
*
* For elements which use a single column, %NULL is returned and @n_values
* is set to zero.
*
* If the attribute is undefined, %NULL is returned and @n_values is set
* to a non-zero value.
*
* The array with the results is allocated by the function. When it is
* not needed anymore, be sure to call g_free() on it.
*
* Return value: (transfer full) (array length=n_values) (element-type gdouble):
* Array containing the values for the column gaps, or %NULL if the
* array is empty or the attribute is not defined.
*
* Since: 0.26
*/
gdouble *poppler_structure_element_get_column_gaps(PopplerStructureElement *poppler_structure_element, guint *n_values)
{
g_return_val_if_fail(poppler_structure_element_is_grouping(poppler_structure_element), NULL);
g_return_val_if_fail(n_values != nullptr, NULL);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::ColumnGap);
if (value == nullptr) {
*n_values = static_cast<guint>(-1);
return nullptr;
}
gdouble *result = nullptr;
convert_doubles_array(value, &result, n_values);
return result;
}
/**
* poppler_structure_element_get_column_widths:
* @poppler_structure_element: A #PopplerStructureElement
* @n_values: (out): Size of the returned array.
*
* Obtains an array with the widths of the columns.
*
* The array with the results is allocated by the function. When it is
* not needed anymore, be sure to call g_free() on it.
*
* Return value: (transfer full) (array length=n_values) (element-type gdouble):
* Array containing widths of the columns, or %NULL if the attribute
* is not defined.
*
* Since: 0.26
*/
gdouble *poppler_structure_element_get_column_widths(PopplerStructureElement *poppler_structure_element, guint *n_values)
{
g_return_val_if_fail(poppler_structure_element_is_grouping(poppler_structure_element), NULL);
g_return_val_if_fail(n_values != nullptr, NULL);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::ColumnWidths);
if (value == nullptr) {
return nullptr;
}
gdouble *result = nullptr;
convert_doubles_array(value, &result, n_values);
return result;
}
/* List Attribute */
/**
* poppler_structure_element_get_list_numbering:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the list numbering style for list items.
*
* Return value: A #PopplerStructureListNumbering value.
*
* Since: 0.26
*/
PopplerStructureListNumbering poppler_structure_element_get_list_numbering(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_LIST_ITEM, EnumNameValue<PopplerStructureListNumbering>::values[0].value);
return attr_to_enum<PopplerStructureListNumbering>(poppler_structure_element);
}
/* PrintField Attributes */
/**
* poppler_structure_element_get_form_role:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the role of a form structure element that is part of a form, or is
* a form field. This hints how the control for the element is intended
* to be rendered.
*
* Return value: A #PopplerStructureFormRole value.
*
* Since: 0.26
*/
PopplerStructureFormRole poppler_structure_element_get_form_role(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_FORM, EnumNameValue<PopplerStructureFormRole>::values[0].value);
/*
* The Role attribute can actually be undefined.
*/
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::Role);
if (value == nullptr) {
return POPPLER_STRUCTURE_FORM_ROLE_UNDEFINED;
}
return name_to_enum<PopplerStructureFormRole>(value);
}
/**
* poppler_structure_element_get_form_state:
* @poppler_structure_element: A #PopplerStructureElement
*
* For a structure element that is a form field, obtains in which state
* the associated control is expected to be rendered.
*
* Return value: A #PopplerStructureFormState value.
*
* Since: 0.26
*/
PopplerStructureFormState poppler_structure_element_get_form_state(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_FORM, EnumNameValue<PopplerStructureFormState>::values[0].value);
return attr_to_enum<PopplerStructureFormState>(poppler_structure_element);
}
/**
* poppler_structure_element_get_form_description:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the textual description of the form element. Note that the
* description is for informative purposes, and it is not intended
* to be rendered. For example, assistive technologies may use the
* description field to provide an alternate way of presenting an
* element to the user.
*
* The returned string is allocated by the function. When it is
* not needed anymore, be sure to call g_free() on it.
*
* Return value: (transfer full): A string, or %NULL if the attribute
* is not defined.
*
* Since: 0.26
*/
gchar *poppler_structure_element_get_form_description(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_FORM, NULL);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::Desc);
if (value == nullptr) {
return nullptr;
}
if (value->isString()) {
return _poppler_goo_string_to_utf8(value->getString());
}
if (value->isName()) {
return g_strdup(value->getName());
}
g_assert_not_reached();
return nullptr;
}
/* Table Attributes */
/**
* poppler_structure_element_get_table_row_span:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the number of rows the table element spans to.
*
* Return value: A positive, non-zero value.
*
* Since: 0.26
*/
guint poppler_structure_element_get_table_row_span(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_TABLE, 0);
return static_cast<guint>(attr_value_or_default(poppler_structure_element, Attribute::RowSpan)->getInt());
}
/**
* poppler_structure_element_get_table_column_span:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the number of columns the table element spans to.
*
* Return value: A positive, non-zero value.
*
* Since: 0.26
*/
guint poppler_structure_element_get_table_column_span(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_TABLE, 0);
return static_cast<guint>(attr_value_or_default(poppler_structure_element, Attribute::ColSpan)->getInt());
}
/**
* poppler_structure_element_get_table_headers:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains an array with the names of the table column headers. This is only
* useful for table header row elements.
*
* The array with the results is allocated by the function. The number
* of items in the returned array can be obtained with g_strv_length().
* The returned value must be freed using g_strfreev().
*
* Return value: (transfer full) (array zero-terminated=1) (element-type gchar*):
* Zero-terminated array of strings with the table header names,
* or %NULL if the attribute is not defined.
*
* Since: 0.26
*/
gchar **poppler_structure_element_get_table_headers(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_TABLE, NULL);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::Headers);
if (value == nullptr) {
return nullptr;
}
g_assert(value->isArray());
const guint n_values = value->arrayGetLength();
gchar **result = g_new0(gchar *, n_values + 1);
for (guint i = 0; i < n_values; i++) {
Object item = value->arrayGet(i);
if (item.isString()) {
result[i] = _poppler_goo_string_to_utf8(item.getString());
} else if (item.isName()) {
result[i] = g_strdup(item.getName());
} else {
g_assert_not_reached();
}
}
return result;
}
/**
* poppler_structure_element_get_table_scope:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the scope of a table structure element.
*
* Return value: A #PopplerStructureTableScope value.
*
* Since: 0.26
*/
PopplerStructureTableScope poppler_structure_element_get_table_scope(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(poppler_structure_element_get_kind(poppler_structure_element) == POPPLER_STRUCTURE_ELEMENT_TABLE, EnumNameValue<PopplerStructureTableScope>::values[0].value);
return attr_to_enum<PopplerStructureTableScope>(poppler_structure_element);
}
/**
* poppler_structure_element_get_table_summary:
* @poppler_structure_element: A #PopplerStructureElement
*
* Obtains the textual summary of the contents of the table element. Note that
* the summary is meant for informative purposes, and it is not intended
* to be rendered. For example, assistive technologies may use the
* description field to provide an alternate way of presenting an element
* to the user, or a document indexer may want to scan it for additional
* keywords.
*
* The returned string is allocated by the function. When it is
* not needed anymore, be sure to call g_free() on it.
*
* Return value: (transfer full): A string, or %NULL if the attribute
* is not defined.
*
* Since: 0.26
*/
gchar *poppler_structure_element_get_table_summary(PopplerStructureElement *poppler_structure_element)
{
g_return_val_if_fail(POPPLER_IS_STRUCTURE_ELEMENT(poppler_structure_element), NULL);
const Object *value = attr_value_or_default(poppler_structure_element, Attribute::Summary);
if (value == nullptr) {
return nullptr;
}
if (value->isString()) {
return _poppler_goo_string_to_utf8(value->getString());
}
if (value->isName()) {
return g_strdup(value->getName());
}
g_assert_not_reached();
return nullptr;
}