https://bugs.documentfoundation.org/show_bug.cgi?id=173217

            Bug ID: 173217
           Summary: Impress: the ODF and OOXML filters drop a hyperlink's
                    name, so link annotations carry no /Contents (PDF/UA
                    7.18.1, 7.18.5)
           Product: LibreOffice
           Version: 26.2.5.2 release
          Hardware: All
                OS: All
            Status: UNCONFIRMED
          Keywords: accessibility
          Severity: normal
          Priority: medium
         Component: Impress
          Assignee: [email protected]
          Reporter: [email protected]

LibreOffice exports a link annotation's /Contents from the hyperlink's Name --
the mechanism
put in by tdf#161583
<https://bugs.documentfoundation.org/show_bug.cgi?id=161583> (24.8.7, 25.2.2,
25.8). Writer honours it. Impress never does -- but not for want of a place to
keep the name.
SvxURLField has carried one since that same commit
(include/editeng/flditem.hxx:152, commented
// Alt-text), which wired sd and drawinglayer to it. What that commit did not
touch is the
filters: nothing that reads or writes an Impress document carries the name, so
it is empty by
the time the PDF writer looks for it. section 4 names the four lines.

Two consequences, both reproducible below:

1. No Impress document can produce a PDF that satisfies PDF/UA-1 7.18.1/2 (an
annotation shall
   have a Contents key or an Alt on the enclosing structure element) or
7.18.5/2 (a link
   shall carry an alternate description in its Contents).
2. The OOXML tooltip -- <a:hlinkClick tooltip="...">, the field PowerPoint
offers as
   "ScreenTip" -- is read and then discarded three files later (section 4), so
a PPTX cannot supply the
   description that Impress would need anyway.

=== Versions ===

Reproduced on LibreOffice 26.2.5.2 (macOS,
cd7284b4cbbfeb507e630c1aac019f4157393acb).
Validator: veraPDF 1.30.2, profile ua1 (ISO 14289-1).

The source read in section 4 is refs/heads/master as of 2026-08-21. Every line
of it is identical in
refs/heads/libreoffice-26-2 (down to the line numbers) and in
refs/heads/libreoffice-25-8
(same, bar flditem.hxx, where the name sits at 154/169/170). 25.8 is what the
Zeemless container
runs, 26.2.5.2 is what the measurements above were made on, and the defect is
the same in both.

=== 1. Writer honours the name -- the control ===

Save as writer.fodt:

xml
<?xml version="1.0" encoding="UTF-8"?>
<office:document
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
 xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
 xmlns:xlink="http://www.w3.org/1999/xlink";
 office:version="1.3"
office:mimetype="application/vnd.oasis.opendocument.text">
 <office:body><office:text>
  <text:h text:outline-level="1">Heading</text:h>
  <text:p>Follow <text:a xlink:href="#target" office:name="Internal,
named">this link</text:a>.</text:p>
  <text:p><text:bookmark text:name="target"/>The target.</text:p>
 </office:text></office:body>
</office:document>


bash
soffice --headless --convert-to \
 
'pdf:writer_pdf_Export:{"UseTaggedPDF":{"type":"boolean","value":"true"},"PDFUACompliance":{"type":"boolean","value":"true"}}'
\
  writer.fodt


The annotation carries the description, as it should:


<</Type/Annot/Subtype/Link/Border[0 0 0]/Rect[93.693 732.689 132.757 746.489]
  /Contents<FEFF0049006E007400650072006E0061006C002C0020006E0061006D00650064>
  /Dest[1 0 R/XYZ 56.7 732.689 0]/StructParent 1>>


An external xlink:href behaves the same way. Only office:name does this --
office:title and
xlink:title are ignored, which is worth a note of its own since office:title is
the attribute
ODF documents as the alternate text.

=== 2. Impress ignores it ===

Take any ODP whose text run holds a link, and give it the same attribute:

xml
<text:a xlink:href="#Slide 2" xlink:type="simple" office:name="Risks, page
2">...</text:a>


bash
soffice --headless --convert-to \
 
'pdf:impress_pdf_Export:{"UseTaggedPDF":{"type":"boolean","value":"true"},"PDFUACompliance":{"type":"boolean","value":"true"}}'
\
  impress.odp


The annotation is written without a description:


<</Type/Annot/Subtype/Link/Border[0 0 0]/Rect[35.199 496.913 127.367 505.644]
  /Dest[7 0 R/FitR 0 0 720 540]/StructParent 2>>


The same with an external xlink:href="https://example.org/": the /A action is
written, the
/Contents is not. So it is not about internal versus external links -- the name
is simply not
there.

Where it is lost -- at import, not at export. Converting that same ODP back to
ODP
(soffice --convert-to odp) returns <text:a xlink:href="#Slide 2"
xlink:type="simple">: the
attribute is gone after one round trip: what reads a text:a into an Impress
text field is not
the context that understands office:name (section 4), so the PDF writer has
nothing left to export.

=== 3. The OOXML tooltip does not survive the import either ===

A PPTX whose run carries

xml
<a:hlinkClick r:id="rId2" tooltip="Risks, page 2"
action="ppaction://hlinksldjump"/>


converts (soffice --convert-to odp) to <text:a xlink:href="#Slide 2"
xlink:type="simple"> -- no
office:name, no other attribute holding the string. Exported to PDF, the
annotation jumps to the
right slide and says nothing, and the tooltip text appears nowhere in the file.

Even once section 2 is fixed, this leaves every PowerPoint deck unable to
supply the description it
already carries. The import does read the attribute -- it just puts it where
the next step
overwrites it (section 4).

=== 4. Where it is lost, in the source ===

Every reference below is refs/heads/master at 2026-08-21, and holds line for
line in
libreoffice-26-2.

The name exists. include/editeng/flditem.hxx:152 -- SvxURLField::m_Name,
commented
// Alt-text, with GetName()/SetName() at 167-168. Added by the tdf#161583
commit
(182626 <https://gerrit.libreoffice.org/c/core/+/182626>, master 2025-03-06),
which touched
editeng, svx, drawinglayer and sd -- so the Impress side of the export path was
wired.
It touched neither xmloff nor oox.

It is not reachable over UNO. editeng/source/uno/unofield.cxx:95-98 gives the
URL field four
properties -- Format, Representation, TargetFrame, URL. There is no Name. Both
filters
below go through UNO, so this alone is enough to lose it in each direction.

ODF import splits by application. xmloff/source/text/txtparai.cxx:1354-1370
chooses the
handler for text:a by asking whether the cursor has a HyperLinkURL property:
Writer does, and
gets XMLImpHyperlinkContext_Impl, which reads office:name (line 309). Draw,
Impress and Calc do
not, and get XMLUrlFieldImportContext instead -- whose ProcessAttribute()
(xmloff/source/text/txtfldi.cxx:2886) handles exactly xlink:href and
office:target-frame-name. office:name falls through to default: and is dropped
with a
warning. This is the round trip measured in section 2.

ODF export never writes it. xmloff/source/text/txtflde.cxx:1738-1748 emits the
text:a from
the field's URL, Representation and TargetFrame -- there is nothing else to
emit.

The OOXML tooltip is read, then overwritten.
oox/source/drawingml/hyperlinkcontext.cxx:59-61 does pick up
a:hlinkClick@tooltip -- and stores
it as PROP_Representation, the link's *visible text*. Seven lines further on,
oox/source/drawingml/textrun.cxx:157 sets PROP_Representation to getText(). So
the tooltip is
imported into the one property that is guaranteed to be overwritten, which is
why section 3 finds it
nowhere in the converted file.

=== Suggested fix ===

Four changes, none of them in the PDF writer:

1. Expose the name over UNO -- add a Name property to the URL field in
   editeng/source/uno/unofield.cxx, mapped to SvxURLField::SetName()/GetName().
Without it
   the filters have nowhere to put the string.
2. ODF import -- XMLUrlFieldImportContext::ProcessAttribute() accepts
office:name, and
   PrepareField() sets it.
3. ODF export -- xmloff/source/text/txtflde.cxx writes office:name beside
xlink:href.
4. OOXML import -- hyperlinkcontext.cxx stores the tooltip as the name instead
of as
   PROP_Representation.

A fallback worth having anyway. When PDFUACompliance is on and no name is set,
the link's own
visible text is a reasonable /Contents: it is what a reader announces anyway,
and it makes
existing documents conformant without re-authoring them. The alternative -- the
warning
tdf#161583 <https://bugs.documentfoundation.org/show_bug.cgi?id=161583> added
for links with no
name -- cannot be acted on in Impress at all while 1-4 stand.

=== Related ===

- tdf#161583 <https://bugs.documentfoundation.org/show_bug.cgi?id=161583> --
RESOLVED FIXED, the
  change that made /Contents come from the name rather than from the link text.
Its notes say
  Impress gained the ability to store a name for a hyperlink, and section 4
confirms it did -- the
  filters on either side of that model were left as they were.
- tdf#167307 <https://bugs.documentfoundation.org/show_bug.cgi?id=167307> --
UNCONFIRMED, the
  other end of the same change: Acrobat stopped showing a tooltip for a Writer
link, because the
  /Contents it used to display was the link text and is now the (usually empty)
name.

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to