text_renderer.cls.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <?php
  2. /**
  3. * @package dompdf
  4. * @link http://dompdf.github.com/
  5. * @author Benj Carson <benjcarson@digitaljunkies.ca>
  6. * @author Helmut Tischer <htischer@weihenstephan.org>
  7. * @author Fabien Ménager <fabien.menager@gmail.com>
  8. * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  9. */
  10. /**
  11. * Renders text frames
  12. *
  13. * @access private
  14. * @package dompdf
  15. */
  16. class Text_Renderer extends Abstract_Renderer {
  17. const DECO_THICKNESS = 0.02; // Thickness of underline. Screen: 0.08, print: better less, e.g. 0.04
  18. //Tweaking if $base and $descent are not accurate.
  19. //Check method_exists( $this->_canvas, "get_cpdf" )
  20. //- For cpdf these can and must stay 0, because font metrics are used directly.
  21. //- For other renderers, if different values are wanted, separate the parameter sets.
  22. // But $size and $size-$height seem to be accurate enough
  23. const UNDERLINE_OFFSET = 0.0; // Relative to bottom of text, as fraction of height.
  24. const OVERLINE_OFFSET = 0.0; // Relative to top of text
  25. const LINETHROUGH_OFFSET = 0.0; // Relative to centre of text.
  26. const DECO_EXTENSION = 0.0; // How far to extend lines past either end, in pt
  27. //........................................................................
  28. /**
  29. * @param Text_Frame_Decorator $frame
  30. */
  31. function render(Frame $frame) {
  32. $text = $frame->get_text();
  33. if ( trim($text) === "" )
  34. return;
  35. $style = $frame->get_style();
  36. list($x, $y) = $frame->get_position();
  37. $cb = $frame->get_containing_block();
  38. if ( ($ml = $style->margin_left) === "auto" || $ml === "none" )
  39. $ml = 0;
  40. if ( ($pl = $style->padding_left) === "auto" || $pl === "none" )
  41. $pl = 0;
  42. if ( ($bl = $style->border_left_width) === "auto" || $bl === "none" )
  43. $bl = 0;
  44. $x += $style->length_in_pt( array($ml, $pl, $bl), $cb["w"] );
  45. $font = $style->font_family;
  46. $size = $frame_font_size = $style->font_size;
  47. $height = $style->height;
  48. $word_spacing = $frame->get_text_spacing() + $style->length_in_pt($style->word_spacing);
  49. $char_spacing = $style->length_in_pt($style->letter_spacing);
  50. $width = $style->width;
  51. /*$text = str_replace(
  52. array("{PAGE_NUM}"),
  53. array($this->_canvas->get_page_number()),
  54. $text
  55. );*/
  56. $this->_canvas->text($x, $y, $text,
  57. $font, $size,
  58. $style->color, $word_spacing, $char_spacing);
  59. $line = $frame->get_containing_line();
  60. // FIXME Instead of using the tallest frame to position,
  61. // the decoration, the text should be well placed
  62. if ( false && $line->tallest_frame ) {
  63. $base_frame = $line->tallest_frame;
  64. $style = $base_frame->get_style();
  65. $size = $style->font_size;
  66. $height = $line->h * ($size / $style->line_height);
  67. }
  68. $line_thickness = $size * self::DECO_THICKNESS;
  69. $underline_offset = $size * self::UNDERLINE_OFFSET;
  70. $overline_offset = $size * self::OVERLINE_OFFSET;
  71. $linethrough_offset = $size * self::LINETHROUGH_OFFSET;
  72. $underline_position = -0.08;
  73. if ( $this->_canvas instanceof CPDF_Adapter ) {
  74. $cpdf_font = $this->_canvas->get_cpdf()->fonts[$style->font_family];
  75. if (isset($cpdf_font["UnderlinePosition"])) {
  76. $underline_position = $cpdf_font["UnderlinePosition"]/1000;
  77. }
  78. if (isset($cpdf_font["UnderlineThickness"])) {
  79. $line_thickness = $size * ($cpdf_font["UnderlineThickness"]/1000);
  80. }
  81. }
  82. $descent = $size * $underline_position;
  83. $base = $size;
  84. // Handle text decoration:
  85. // http://www.w3.org/TR/CSS21/text.html#propdef-text-decoration
  86. // Draw all applicable text-decorations. Start with the root and work our way down.
  87. $p = $frame;
  88. $stack = array();
  89. while ( $p = $p->get_parent() )
  90. $stack[] = $p;
  91. while ( isset($stack[0]) ) {
  92. $f = array_pop($stack);
  93. if ( ($text_deco = $f->get_style()->text_decoration) === "none" )
  94. continue;
  95. $deco_y = $y; //$line->y;
  96. $color = $f->get_style()->color;
  97. switch ($text_deco) {
  98. default:
  99. continue;
  100. case "underline":
  101. $deco_y += $base - $descent + $underline_offset + $line_thickness/2;
  102. break;
  103. case "overline":
  104. $deco_y += $overline_offset + $line_thickness/2;
  105. break;
  106. case "line-through":
  107. $deco_y += $base * 0.7 + $linethrough_offset;
  108. break;
  109. }
  110. $dx = 0;
  111. $x1 = $x - self::DECO_EXTENSION;
  112. $x2 = $x + $width + $dx + self::DECO_EXTENSION;
  113. $this->_canvas->line($x1, $deco_y, $x2, $deco_y, $color, $line_thickness);
  114. }
  115. if (DEBUG_LAYOUT && DEBUG_LAYOUT_LINES) {
  116. $text_width = Font_Metrics::get_text_width($text, $font, $frame_font_size);
  117. $this->_debug_layout(array($x, $y, $text_width+($line->wc-1)*$word_spacing, $frame_font_size), "orange", array(0.5, 0.5));
  118. }
  119. }
  120. }