Skip to content

Strange additional padding at the bottom of a multi-line content with auto linebreaks #992

Description

@YDX-2147483647

When cetz v0.4.2 calculates border anchors for cetz.draw.content, it changes text.bottom-edge and increases the effective line spacing, resulting in an additional bottom padding if the content is multi-line.

cetz/src/draw/shapes.typ

Lines 1143 to 1155 in 0459295

// Compute the baseline offset
let (_, line-baseline-height) = util.measure(ctx, text(top-edge: "cap-height", bottom-edge: "baseline",
[ #show linebreak: [ ]; #body]))
let (_, line-bounds-height) = util.measure(ctx, text(top-edge: "cap-height", bottom-edge: "bounds",
[ #show linebreak: [ ]; #body]))
let baseline-offset = line-bounds-height - line-baseline-height
// Size of the bounding box
let (content-width, content-height, ..) = if auto-size {
util.measure(ctx, text(top-edge: "cap-height", bottom-edge: "baseline", body))
} else {
vector.sub(b, a)
}

Minimal example

In the following example, the height of the green border line is expected to equal to the height of the aqua block, but it isn't.

#import "@preview/cetz:0.4.2"

#cetz.canvas({
  import cetz.draw: *

  content((0, 0), name: "a", block(
    width: 6em,
    fill: aqua.lighten(50%),
    lorem(10),
  ))
  line(
    "a.north-west",
    "a.north-east",
    "a.south-east",
    "a.south-west",
    close: true,
    stroke: green,
  )
})
Image

Links and comparisons

#894 is a similar issue. #956 (first appeared in v0.4.2) has fixed that issue, but not this one.
The difference is that linebreaks in #894 are inserted manually, but here they're inserted automatically (by putting contents in a fixed-width block).
Therefore, the #show linebreak: [ ] hack used by #956 is not helpful.

In the minimal example above, changing a.south-{west,east} to a.base-{west,east} would draw the correct border line.
However, there exist certain cases that base-{west,east} are not applicable.
For instance, when drawing a chat bubble, you may want the lower-left corner of the whole group, including a triangle and a cetz.draw.content. This point locates at (x: group.triangle.west.x, y: group.content.base-west.y). If cetz had measured correctly, then this can be simplified as group.south-west.

Image

Workaround

Set text.{top,bottom}-edge explicitly and control spacing on your own.

#import "@preview/cetz:0.4.2"

#cetz.canvas({
  import cetz.draw: *

  content((0, 0), name: "a", block(
    width: 6em,
    fill: aqua.lighten(50%),
    {
      // 👇 Edit here
      set text(top-edge: "cap-height", bottom-edge: "baseline")
      v(0.5em) // or use `block.inset`
      lorem(10)
      v(0.5em)
    },
  ))
  line(
    "a.north-west",
    "a.north-east",
    "a.base-east",
    "a.base-west",
    close: true,
    stroke: green,
  )
})
Image

Activity

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions