Bug 167721 - FILEOPEN DOCX: missing indent (leftChars=0 disables style's leftChars and should use w:left)
Summary: FILEOPEN DOCX: missing indent (leftChars=0 disables style's leftChars and sho...
Status: NEW
Alias: None
Product: LibreOffice
Classification: Unclassified
Component: Writer (show other bugs)
Version:
(earliest affected)
25.8.0.0 alpha0+
Hardware: All All
: medium normal
Assignee: Justin L
URL:
Whiteboard: target:26.2.0
Keywords: bisected, filter:docx, regression
Depends on:
Blocks: CJK
  Show dependency treegraph
 
Reported: 2025-07-29 15:29 UTC by Justin L
Modified: 2025-08-14 23:28 UTC (History)
2 users (show)

See Also:
Crash report or crash signature:


Attachments
fdo67759-1.docx_import-compare-1.png: RED=25.8.0, BLUE=25.8_oldest, GRAYSCALE=Word2019 (71.27 KB, image/png)
2025-07-29 15:29 UTC, Justin L
Details
moz901814-1.docx: "Example 3" at the top of page 2 should be indented (1.20 MB, application/vnd.openxmlformats-officedocument.wordprocessingml.document)
2025-07-30 18:15 UTC, Justin L
Details
honeywellB.docx: a nasty example, that cancels w:leftChars but doesn't redefine w:left, so style's 4.5cm indent should push picture to right side. (122.99 KB, application/vnd.openxmlformats-officedocument.wordprocessingml.document)
2025-08-04 16:57 UTC, Justin L
Details
honeywellE.docx: firstLineChars doesn't negate an inherited or direct w:left property (122.99 KB, application/vnd.openxmlformats-officedocument.wordprocessingml.document)
2025-08-04 17:36 UTC, Justin L
Details
honeywellE_screenshot.png: Word 2024 - paragraph properties dialog open beside picture (132.84 KB, image/png)
2025-08-05 00:07 UTC, Justin L
Details
honeywellC.docx: inherits w:left and defines w:firstLineChars (123.00 KB, application/vnd.openxmlformats-officedocument.wordprocessingml.document)
2025-08-05 00:29 UTC, Justin L
Details
honeywellF.docx: fails to inherit w:leftChars=300 (122.99 KB, application/vnd.openxmlformats-officedocument.wordprocessingml.document)
2025-08-05 00:46 UTC, Justin L
Details
honeywell_killer1.docx: contains some of the nasty edge cases (122.53 KB, application/vnd.openxmlformats-officedocument.wordprocessingml.document)
2025-08-08 17:45 UTC, Justin L
Details
honeywell_killer3.docx: hangingChars affects left margin in unexpected ways (122.52 KB, application/vnd.openxmlformats-officedocument.wordprocessingml.document)
2025-08-11 16:45 UTC, Justin L
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Justin L 2025-07-29 15:29:37 UTC
Created attachment 202067 [details]
fdo67759-1.docx_import-compare-1.png: RED=25.8.0, BLUE=25.8_oldest, GRAYSCALE=Word2019

This overlay image shows that the image should be approximately centred on the page, but now (the red portion) shows that there is no indent before the image.

The w:drawing is an inline image positioned by a "List paragraph" style named "a3". List Paragraph defines the indent as
    <w:ind w:leftChars="400" w:left="800"/>
but this is overridden by direct paragraph formatting
    <w:ind w:leftChars="0" w:left="760"/>

The indent broke with 25.8's commit fbb46a2fd940d1b5f4b2782708756f67659c0f38
Author: Jonathan Clark on Thu Mar 13 00:36:07 2025 -0600
    tdf#83844 DOCX import: implement Ch-based LR indentation
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183066

Based on experimentation, leftChars=0 should DISABLE the use of Ch units and tells the program to use w:left instead. (If I change the direct formatting to leftChars=1, then the indent shows in the UI as 0.01ch, but with leftChars=0, then the indent is shown as 1.34cm.)

Steps to reproduce
1.) open honeywell.docx (attachment 83635 [details] from bug 67759)

The image should appear to be centred on the page because the paragraph has an indent defined.

Not really a regression, since leftChars wasn't supported at all prior to Jonathan's patch, but in this particular document ignoring leftChars is correct.

Found by Collabora's mso-test.
Comment 1 Justin L 2025-07-30 18:15:17 UTC
Created attachment 202081 [details]
moz901814-1.docx: "Example 3" at the top of page 2 should be indented

This example has direct formatting to disable firstLineChars
  <w:ind w:left="360" w:firstLineChars="0" w:firstLine="0"/>
overriding the style's definition
  <w:ind w:firstLineChars="200" w:firstLine="420"/>
Comment 2 Justin L 2025-08-04 16:57:37 UTC
Created attachment 202168 [details]
honeywellB.docx: a nasty example, that cancels w:leftChars but doesn't redefine w:left, so style's 4.5cm indent should push picture to right side.
Comment 3 Justin L 2025-08-04 17:36:36 UTC
Created attachment 202170 [details]
honeywellE.docx: firstLineChars doesn't negate an inherited or direct w:left property

The simple existence of one *Chars doesn't exclude the use of any other non-Chars definition.
Comment 4 Justin L 2025-08-05 00:07:02 UTC
Created attachment 202176 [details]
honeywellE_screenshot.png: Word 2024 - paragraph properties dialog open beside picture

(In reply to Justin L from comment #3)
> The simple existence of one *Chars doesn't exclude the use of any other
> non-Chars definition.
AFAICS, for bug 36709 it was implemented that "Ch" and "cm" cannot co-exist, but this document shows that they can. Also true in Word 2010.

So this has blown up to be bigger than I can handle.
Comment 5 Justin L 2025-08-05 00:08:25 UTC
My initial attempts at trying to fix this can be seen at https://gerrit.libreoffice.org/c/core/+/188930
Comment 6 Justin L 2025-08-05 00:29:01 UTC
Created attachment 202177 [details]
honeywellC.docx: inherits w:left and defines w:firstLineChars
Comment 7 Justin L 2025-08-05 00:46:27 UTC
Created attachment 202178 [details]
honeywellF.docx: fails to inherit w:leftChars=300
Comment 8 Justin L 2025-08-08 14:54:55 UTC
Oh no!!!
The documentation is unclear about what happens when *Chars=0 is seen. In practice you can see the unit change from Ch to cm/inches in the UI.

I THOUGHT that this was always reverting back to the last-provided non-Chars length, but that is NOT what is happening. Its more complicated than that.

Consider this situation:
Style 1: 2 inch left margin
   <w:ind w:left="2880" /> 
Style 1b: (inherits from style 1: 7 Ch left margin
   <w:ind w:leftChars="700" />

Paragraph - using style 1b: disables all Chars
   <w:ind w:leftChars="0" />

So, my expectation was that the paragraph would get the results of style 1. But that is not what MS Word does. Instead, it appears to have converted 700Ch into cm/inches. (0.49 inch in my case)

How then do we reconcile that with:
Style:      <w:ind w:leftChars="700" w:left="2880" /> 
Paragraph:  <w:ind w:leftChars="0" />

-- or --
Style 1:    <w:ind w:leftChars="700" /> 
Style 1b:   <w:ind                   w:left="2880" /> 
Paragraph:  <w:ind w:leftChars="0" />

In both of these cases, the paragraph has a 2 inch left margin.


So, what MUST be happening is that MS Word holds two values for the left margin. If leftChars is specified (non-zero), then it also recalculates an appropriate non-relative distance (hmm - but it does NOT seem to be based on the style font size - it doesn't change when I change the style/document w:sz or w:szCs).
Any time after that, a specified w:left will replace that generated value.

It looks to me like the formula used is something like 1 Ch == 5 pt.

OH. That makes sense. 100 Twip = 5 pt. and *Chars="100" = 1 Ch.
How clever.
Comment 9 Justin L 2025-08-08 17:45:14 UTC
Created attachment 202251 [details]
honeywell_killer1.docx: contains some of the nasty edge cases
Comment 10 Jonathan Clark 2025-08-08 20:25:14 UTC
(In reply to Justin L from comment #4)
> AFAICS, for bug 36709 it was implemented that "Ch" and "cm" cannot co-exist,
> but this document shows that they can. Also true in Word 2010.
> 
> So this has blown up to be bigger than I can handle.

Part of the aim for bug 36709 was to add character-based indentation to ODF, while keeping the format relatively sane compared to OOXML. The current implementation is catered to that extension.

For interop, I don't think it would be too difficult to extend the current implementation to also track a last-set twips value, if needed.

(In reply to Justin L from comment #8)
> It looks to me like the formula used is something like 1 Ch == 5 pt.
> 
> OH. That makes sense. 100 Twip = 5 pt. and *Chars="100" = 1 Ch.
> How clever.

That doesn't sound intentional to me. It makes sense to inherit the underlying twips value into twips, or the underlying chars value into chars, but crossing over like this sounds a lot like a copy-paste error.
Comment 11 Justin L 2025-08-09 11:50:34 UTC
(In reply to Justin L from comment #8)
> Consider this situation:
> Style 1:   <w:ind w:left="2880" /> 
> Style 1b:  <w:ind w:leftChars="700" />
> Paragraph: <w:ind w:leftChars="0" />
> 
> So, my expectation was that the paragraph would get the results of style 1.
> But that is not what MS Word does. Instead, it appears to have converted
> 700Ch into cm/inches. (0.49 inch in my case)

Note that when using all styles, this situations acts differently again.
Style 1:  <w:ind w:leftChars="700" />  -OR- <w:ind w:left="2880" />
Style 1b: <w:ind w:leftChars="0" />
Paragraph - using style 1b: no w:ind specified

A style apparently never inherits any fall-back w:left from it's parent, so the paragraph inherits a left margin of 0 cm. Surprise!
Comment 12 Justin L 2025-08-09 11:53:15 UTC
OK - so the next thing to do is figure out how hanging / firstLine interact.

According to the documentation, hanging has priority over firstLine, and of course hangingChars has priority over firstLineChars.

Based on my testing, priority does NOT involve inheritance, but only "simultaneously defined" properties:
    Style 1: <w:ind w:hangingChars="100" />
    Style 1b: <w:ind w:firstLineChars="200" />
Expected result: first line 2 Ch. Yes.
(Also true for "Paragraph" instead of "Style 1b")
    
    
Some surprising results:
Style: <w:ind w:hangingChars="0" w:firstLine="2880" />
Expected result: firstLine 2 inch. NO! there is no first line indent at all.

Paragraph: <w:ind w:hangingChars="0" w:firstLine="2880" />
Expected result: firstLine 2 inch. Yes.
Comment 13 Justin L 2025-08-11 16:45:55 UTC
Created attachment 202281 [details]
honeywell_killer3.docx: hangingChars affects left margin in unexpected ways

(In reply to Justin L from comment #8)
\> Style 1:    <w:ind w:leftChars="700" /> 
> Style 1b:   <w:ind                   w:left="2880" /> 
> Paragraph:  <w:ind w:leftChars="0" />
> ... the paragraph has a 2 inch left margin.

If you introduce w:hangingChars="something" in the paragraph, then strange things start to happen, and make you question whether the conclusion is correct. But this example shows that it is correct for the right margin.
Comment 14 Commit Notification 2025-08-12 00:15:57 UTC
Justin Luth committed a patch related to this issue.
It has been pushed to "master":

https://git.libreoffice.org/core/commit/6c1b8cf820b41f7a579d5d9e7036a14d22567782

related tdf#167721 cui: allow negative values for firstLine

It will be available in 26.2.0.

The patch should be included in the daily builds available at
https://dev-builds.libreoffice.org/daily/ in the next 24-48 hours. More
information about daily builds can be found at:
https://wiki.documentfoundation.org/Testing_Daily_Builds

Affected users are encouraged to test the fix and report feedback.
Comment 15 Commit Notification 2025-08-13 01:07:40 UTC
Justin Luth committed a patch related to this issue.
It has been pushed to "master":

https://git.libreoffice.org/core/commit/13c15652cb7b14aa4cb40d5379493ec65c5ae117

tdf#167721 writerfilter: ic needs to inherit from parent para-style

It will be available in 26.2.0.

The patch should be included in the daily builds available at
https://dev-builds.libreoffice.org/daily/ in the next 24-48 hours. More
information about daily builds can be found at:
https://wiki.documentfoundation.org/Testing_Daily_Builds

Affected users are encouraged to test the fix and report feedback.
Comment 16 Commit Notification 2025-08-13 01:07:43 UTC
Justin Luth committed a patch related to this issue.
It has been pushed to "master":

https://git.libreoffice.org/core/commit/bdf6b7cfb5b58ffe734e92fc73b9e91f58c1a40e

tdf#167721 writerfilter: don't adjust leftChars=0 by hangingChars

It will be available in 26.2.0.

The patch should be included in the daily builds available at
https://dev-builds.libreoffice.org/daily/ in the next 24-48 hours. More
information about daily builds can be found at:
https://wiki.documentfoundation.org/Testing_Daily_Builds

Affected users are encouraged to test the fix and report feedback.
Comment 17 Commit Notification 2025-08-13 01:07:45 UTC
Justin Luth committed a patch related to this issue.
It has been pushed to "master":

https://git.libreoffice.org/core/commit/9b9267ce91271994ce6dae11fe5cc80cee93a313

tdf#167721 writerfilter: ensure w:left applied if w:leftChars=0

It will be available in 26.2.0.

The patch should be included in the daily builds available at
https://dev-builds.libreoffice.org/daily/ in the next 24-48 hours. More
information about daily builds can be found at:
https://wiki.documentfoundation.org/Testing_Daily_Builds

Affected users are encouraged to test the fix and report feedback.
Comment 18 Commit Notification 2025-08-13 01:07:48 UTC
Justin Luth committed a patch related to this issue.
It has been pushed to "master":

https://git.libreoffice.org/core/commit/372fd2834d685bb6809b8a3a672328ff26f77b29

tdf#167721 writerfilter styles: use provided w:left when leftChars=0

It will be available in 26.2.0.

The patch should be included in the daily builds available at
https://dev-builds.libreoffice.org/daily/ in the next 24-48 hours. More
information about daily builds can be found at:
https://wiki.documentfoundation.org/Testing_Daily_Builds

Affected users are encouraged to test the fix and report feedback.
Comment 19 Commit Notification 2025-08-13 01:07:51 UTC
Justin Luth committed a patch related to this issue.
It has been pushed to "master":

https://git.libreoffice.org/core/commit/9be90060e67ca0f2eeb0c5acb2d33dd3a9730d85

tdf#167721 docx export: disable inherited leftChars when writing w:left

It will be available in 26.2.0.

The patch should be included in the daily builds available at
https://dev-builds.libreoffice.org/daily/ in the next 24-48 hours. More
information about daily builds can be found at:
https://wiki.documentfoundation.org/Testing_Daily_Builds

Affected users are encouraged to test the fix and report feedback.
Comment 20 Commit Notification 2025-08-13 01:07:53 UTC
Justin Luth committed a patch related to this issue.
It has been pushed to "master":

https://git.libreoffice.org/core/commit/30791dd5105d2ab088dbd296256357cd04a1feff

tdf#167721 docx export: add w:left=0 when w:leftChars=0

It will be available in 26.2.0.

The patch should be included in the daily builds available at
https://dev-builds.libreoffice.org/daily/ in the next 24-48 hours. More
information about daily builds can be found at:
https://wiki.documentfoundation.org/Testing_Daily_Builds

Affected users are encouraged to test the fix and report feedback.
Comment 21 Commit Notification 2025-08-13 01:08:56 UTC
Justin Luth committed a patch related to this issue.
It has been pushed to "master":

https://git.libreoffice.org/core/commit/e6a5de6f14cb2414e2f76b5a9d5a68dd28fff3ff

tdf#167721 writerfilter styles: adjust leftChars by hangingChars

It will be available in 26.2.0.

The patch should be included in the daily builds available at
https://dev-builds.libreoffice.org/daily/ in the next 24-48 hours. More
information about daily builds can be found at:
https://wiki.documentfoundation.org/Testing_Daily_Builds

Affected users are encouraged to test the fix and report feedback.
Comment 22 Commit Notification 2025-08-13 01:08:59 UTC
Justin Luth committed a patch related to this issue.
It has been pushed to "master":

https://git.libreoffice.org/core/commit/bfe32ea304fe9571764caceea9c86e190684720a

tdf#167721 writerfilter: adjust disabled leftChars by hangingChars

It will be available in 26.2.0.

The patch should be included in the daily builds available at
https://dev-builds.libreoffice.org/daily/ in the next 24-48 hours. More
information about daily builds can be found at:
https://wiki.documentfoundation.org/Testing_Daily_Builds

Affected users are encouraged to test the fix and report feedback.
Comment 23 Commit Notification 2025-08-14 01:31:35 UTC
Justin Luth committed a patch related to this issue.
It has been pushed to "master":

https://git.libreoffice.org/core/commit/6f1969379e4d871ebec042d5e1a663df8e5d484b

tdf#167721 writerfilter: one more chUnit unit test

It will be available in 26.2.0.

The patch should be included in the daily builds available at
https://dev-builds.libreoffice.org/daily/ in the next 24-48 hours. More
information about daily builds can be found at:
https://wiki.documentfoundation.org/Testing_Daily_Builds

Affected users are encouraged to test the fix and report feedback.
Comment 24 Commit Notification 2025-08-14 23:28:03 UTC
Justin Luth committed a patch related to this issue.
It has been pushed to "master":

https://git.libreoffice.org/core/commit/f23ac8bb32cf22a07c93645e604876a404769459

tdf#167721 docx export: don't spam *Chars=0

It will be available in 26.2.0.

The patch should be included in the daily builds available at
https://dev-builds.libreoffice.org/daily/ in the next 24-48 hours. More
information about daily builds can be found at:
https://wiki.documentfoundation.org/Testing_Daily_Builds

Affected users are encouraged to test the fix and report feedback.