Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

line-height does not render in the middle #670

Open
jorgenhorstink opened this issue Jun 20, 2013 · 8 comments · May be fixed by #2762
Open

line-height does not render in the middle #670

jorgenhorstink opened this issue Jun 20, 2013 · 8 comments · May be fixed by #2762

Comments

@jorgenhorstink
Copy link

Hi,

Yesterday I've been digging into the source code, but I was not able to isolate the issue. Line-height is not rendered in the middle as a webbrowser does;

<!DOCTYPE html>
<html>
    <body>
        <div style="font-size: 40px; line-height: 400px; border: 1px solid red; width: 500px;">Not in the middle</div>
    </body>
</html>

I cloned the most recent version of the source code, and I am still able to reproduce the issue. I do not know the details about how line-height should be calculated and rendered, but I think it is a bug. Am I right, if so, any ideas how to fix the issue? I think it has something to do with the way the position of line boxes is calculated.

expected result
The text Not in the middle, should be in the middle.

@bsweeney
Copy link
Member

It's not perfect, but if you add vertical-align: middle to your style then the placement by dompdf is much closer to what you see in the browser.

@jorgenhorstink
Copy link
Author

I see, it helps a bit. Do you have any idea what causes the issue? I'd love to see this issues fixed, and if you can point me in the right direction, I'm going to spend some time at least trying to fix it. I suppose it has something to do with the way the position of line boxes is being calculated...

@jorgenhorstink
Copy link
Author

This one breaks vertical-align... See comment below

I made some changes, but I don't know if it is going to break on other cases. It seems to fix the line-height issue.

HTML used:

<!DOCTYPE html>
<html>
  <body>
    <h1>DOMPDF</h1>
    <div style="font-size: 20px; line-height: 30px; margin-bottom: 10px; vertical-align: top; border: 1px solid red; width: 500px;">Line<br>Line</div>
    <div style="font-size: 20px; line-height: 140px; margin-bottom: 10px; vertical-align: bottom; border: 1px solid red; width: 500px;">Line<br>Line</div>
    <div style="font-size: 50px; line-height: 50px; margin-bottom: 10px; border: 1px solid red; width: 500px;">Line</div>
    <div style="font-size: 14px; line-height: 40px; margin-bottom: 10px; border: 1px solid red; width: 500px;">Line</div>
    <div style="font-size: 20px; line-height: 30px; margin-bottom: 10px; border: 1px solid red; width: 500px;">Line</div>
  </body>
</html>

Added to style.cls.php:

function has_normal_line_height() {
  return $this->_props["line_height"] === "normal";
}

Added to block_frame_reflower.cls.php vertical_align function:

// Prevent vertical_align if the element has line-height
if (!$frame->get_parent()->get_style()->has_normal_line_height()) {
    continue;
}

Added a new function to block_frame_reflower.cls.php:

function line_height() {

  $canvas = null;

  foreach ( $this->_frame->get_line_boxes() as $line ) {

    $height = $line->h;

    foreach ( $line->get_frames() as $frame ) {
      $style = $frame->get_style();

      if ( $style->display !== "inline" ) {
        continue;
      }

      if ( !isset($canvas) ) {
        $canvas = $frame->get_root()->get_dompdf()->get_canvas();
      }

      $fontheight = $canvas->get_font_height($style->font_family, $style->font_size);

      $lineHeight = $frame->get_parent()->get_style()->line_height;

      $y_offset = ($height - $fontheight) / 2;

      if ( $y_offset ) {
        $frame->move(0, $y_offset);
      }
    }
  }
}

Added to block_frame_reflower.cls.php within reflow function after call $this->vertical_align();:

$this->line_height();

Result as attached:

screen shot 2013-06-21 at 11 09 09 am

screen shot 2013-06-21 at 11 08 58 am

@jorgenhorstink
Copy link
Author

Okey, the previous comment broke the vertical-align...

Using 0.9 as arbitrary value gave me better results compared to Google Chrome.

<!DOCTYPE html>
<html>
  <body>
    <h1>DOMPDF</h1>
    <div style="border: 1px solid red; width: 700px; margin-bottom: 10px;">
      <span style="line-height: 30px; font-size: 14px;">lh 20px fs 10px</span>
      <span style="vertical-align: middle; font-size: 14px;">lh 40px fs 10px</span>
      <span style="vertical-align: top; font-size: 14px;">lh 40px fs 10px</span>
      <span style="vertical-align: bottom; font-size: 14px;">B lh 40px fs 10px</span>
    </div>
    <div style="border: 1px solid red; width: 700px; margin-bottom: 14px;">
      <span style="line-height: 30px; font-size: 14px">lh 20px fs 10px</span>
    </div>
    <div style="border: 1px solid red; width: 700px; margin-bottom: 10px;">
      <span style="line-height: 60px; font-size: 30px;">lh 20px fs 10px</span>
      <span style="vertical-align: middle; font-size: 30px;">lh 40px fs 10px</span>
      <span style="vertical-align: top; font-size: 14px;">lh 40px fs 10px</span>
      <span style="vertical-align: bottom; font-size: 20px;">lh 40px fs 10px</span>
    </div>
    <div style="border: 1px solid red; width: 700px; margin-bottom: 14px;">
      <span style="line-height: 50px; font-size: 50px">lh 20px fs 10px</span>
    </div>
    <div style="font-size: 20px; line-height: 30px; margin-bottom: 10px; vertical-align: top; border: 1px solid red; width: 700px;">Line<br>Line</div>
    <div style="font-size: 20px; line-height: 70px; margin-bottom: 10px; vertical-align: bottom; border: 1px solid red; width: 700px;">Line<br>Line</div>
    <div style="font-size: 50px; line-height: 50px; margin-bottom: 10px; border: 1px solid red; width: 700px;">Line</div>
    <div style="font-size: 14px; line-height: 40px; margin-bottom: 10px; border: 1px solid red; width: 700px;">Line</div>
    <div style="font-size: 20px; line-height: 30px; margin-bottom: 10px; border: 1px solid red; width: 700px;">Line</div>
  </body>
</html>

...

class Block_Frame_Reflower extends Frame_Reflower {
  ...
  function line_height() {

    $canvas = null;

    foreach ( $this->_frame->get_line_boxes() as $line ) {

      $height = $line->h;

      foreach ( $line->get_frames() as $frame ) {
        $style = $frame->get_style();

        if ( $style->display !== "inline" ) {
          continue;
        }

        // skip if we don't have a line height
        if ($frame->get_parent()->get_style()->has_normal_line_height()) {
          continue;
        }

        if ( !isset($canvas) ) {
          $canvas = $frame->get_root()->get_dompdf()->get_canvas();
        }

        $baseline = $canvas->get_font_baseline($style->font_family, $style->font_size);
        $fontheight = $canvas->get_font_height($style->font_family, $style->font_size);

        $lineHeight = $frame->get_parent()->get_style()->line_height;

        $y_offset = ($height * 0.8 - $baseline) / 2;

        if ( $y_offset ) {
          $frame->move(0, $y_offset);
        }
      }
    }
  }

  /**
   * Align inline children vertically.
   * Aligns each child vertically after each line is reflowed
   */
  function vertical_align() {

    $canvas = null;

    foreach ( $this->_frame->get_line_boxes() as $line ) {

      $height = $line->h;

      foreach ( $line->get_frames() as $frame ) {
        $style = $frame->get_style();

        if ( $style->display !== "inline" ) {
          continue;
        }

        if (!$frame->get_parent()->get_style()->has_normal_line_height()) {
          continue;
        }

        $align = $frame->get_parent()->get_style()->vertical_align;

        if ( !isset($canvas) ) {
          $canvas = $frame->get_root()->get_dompdf()->get_canvas();
        }

        $baseline = $canvas->get_font_baseline($style->font_family, $style->font_size);
        $fontheight = $canvas->get_font_height($style->font_family, $style->font_size);

        $y_offset = 0;


        switch ($align) {
          case "baseline":
            $y_offset = $height*0.9 - $baseline; // The 0.8 ratio is arbitrary until we find it's meaning
            break;

          case "middle":
            $y_offset = ($height*0.9 - $baseline) / 2;
            break;

          case "sub":
            $y_offset = 0.3 * $height;
            break;

          case "super":
            $y_offset = -0.2 * $height;
            break;

          case "text-top":
          case "top": // Not strictly accurate, but good enough for now
            break;

          case "text-bottom":
          case "bottom":
            $y_offset = $height* 0.9 - $baseline;
            break;
        }

        if ( $y_offset ) {
          $frame->move(0, $y_offset);
        }
      }
    }
  }

  function reflow ... {
    ...
    $this->_text_align();
    $this->vertical_align();
    $this->line_height();
    ...
  }
  ...
}

screen shot 2013-06-21 at 12 12 50 pm
screen shot 2013-06-21 at 12 13 06 pm

@bsweeney
Copy link
Member

Thanks for the feedback. Right now I can't be of too much more help. @PhenX has more knowledge of how dompdf works internally so if he has time to look into this he'll be able to provide some feedback on what you found.

@Paroca72
Copy link

This bug is still open on the 0.8.3 version!

@bsweeney
Copy link
Member

Indeed. Dompdf currently handles line-height mostly at the block level. Using the example provided earlier you can get a better rendering if you style the span elements with display: inline-block;.

@bsweeney
Copy link
Member

bsweeney commented Jan 29, 2022

alignment is generally improved with #2726 but going through the samples here I do still see some room for improvement

@bsweeney bsweeney linked a pull request Aug 25, 2022 that will close this issue
@bsweeney bsweeney modified the milestones: 2.0.1, 2.0.2 Aug 25, 2022
@bsweeney bsweeney modified the milestones: 2.0.2, 2.0.3 Dec 29, 2022
@bsweeney bsweeney modified the milestones: 3.0.1, 3.1.0 May 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants