Skip to content

fix(style): honour line-height instead of forcing 1.2 x font-size - #24

Open
leshchenko1979 wants to merge 1 commit into
Macawls:mainfrom
leshchenko1979:fix/line-height-inheritance
Open

leshchenko1979 wants to merge 1 commit into
Macawls:mainfrom
leshchenko1979:fix/line-height-inheritance

Conversation

@leshchenko1979

Copy link
Copy Markdown
Contributor

Problem

line-height is parsed and stored, but never reaches the renderer: every line advances by 1.2 × font-size no matter what the element declares.

Reproduced on main (32f3fad) — wrapped text, font-size: 20px, all four declarations produce a byte-identical SVG with baselines at 19.3, 43.3, 67.3, 91.3, i.e. a fixed 24px step:

line-height: 3.0   -> step 24px
line-height: 3     -> step 24px
line-height: 60px  -> step 24px
line-height: 300%  -> step 24px

Cause

Two bugs in style/resolve.go, both needed fixing:

1. The inherited value is clobbered. The tail of resolveStyle:

if v, ok := props["line-height"]; ok {
    cs.LineHeight = resolveLineHeight(v, cs.FontSize, ctx)
} else {
    cs.LineHeight = 1.2 * cs.FontSize
}

Text nodes never declare line-height themselves, so the else branch overwrites the value inherited two lines earlier with the default. Only the declaring element ever sees its own value, and it is not the element that draws the text.

2. Inheritance cannot carry a unitless value. resolveLineHeight collapses 2.5 to 50px at the ancestor. CSS inherits the number, so a child with font-size: 10px must get 25px, not 50px.

Fix

  • ComputedStyle.LineHeightFactor keeps the unitless multiplier; inheritProperty carries it alongside LineHeight.
  • The default is applied only when nothing was inherited (cs.LineHeight == 0), and a factor inherited from an ancestor is recomputed against the element's own font-size.
  • Percentages resolve against the element's own font-size. Previously they went through ResolveContext.ContainerSize, which is 0 for line-height, so 250% produced 0.

Verification

Measured against Chromium (Playwright) with the same DejaVu Sans file handed to both engines, wrapped text, font-size: 20px:

declared before after Chromium
1 24px 20px 20px
2 24px 40px 40px
3 24px 60px 60px
250% 24px 50px 50px
inherited 2.5 from parent 24px 50px 50px

Tests added:

  • style/line_height_test.go — unit: unitless scaling, px inheritance, override, percent against own font-size, default when absent.
  • ogre_line_height_e2e_test.go — through the public Render: line step follows the declaration, inheritance from a parent without a declaration on the child, percent.

go build ./..., go vet ./... and go test ./... pass.

Fixes #21

line-height never reached the renderer: every line advanced by 1.2 x
font-size regardless of what the element declared.

Two causes, both in style/resolve.go:

1. The tail of resolveStyle clobbered the resolved value on every node
   that did not declare line-height itself:

       if v, ok := props["line-height"]; ok {
               cs.LineHeight = resolveLineHeight(v, cs.FontSize, ctx)
       } else {
               cs.LineHeight = 1.2 * cs.FontSize
       }

   Text nodes never declare line-height, so the inherited value was
   overwritten with the default on the way down to them.

2. resolveLineHeight collapsed a unitless value to px immediately, so
   inheritance could only carry a stale px number. CSS inherits the
   number, which means a child with a different font-size recomputes it.

Fix: keep the unitless multiplier in ComputedStyle.LineHeightFactor and
let inheritance carry it; recompute the px value against the element's
own font-size. A unitless declaration now survives the whole tree.

Percentages are resolved against the element's own font-size instead of
going through ResolveContext.ContainerSize, which is 0 for line-height
and produced 0.

Verified against Chromium (same DejaVu Sans file for both engines),
wrapped text at font-size 20px:

  line-height 1   step 20px   (was 24px, Chromium 20px)
  line-height 2   step 40px   (was 24px, Chromium 40px)
  line-height 3   step 60px   (was 24px, Chromium 60px)
  250%            step 50px   (was 24px, Chromium 50px)
  inherited 2.5   step 50px   (was 24px, Chromium 50px)

Fixes Macawls#21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

line-height is ignored: every line advances by 1.2 x font-size

1 participant