1<?php 2 3/** 4 * webtrees: online genealogy 5 * Copyright (C) 2023 webtrees development team 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 */ 17 18declare(strict_types=1); 19 20namespace Fisharebest\Webtrees\Report; 21 22use function count; 23use function explode; 24use function str_replace; 25use function substr_count; 26 27/** 28 * Class ReportHtmlText 29 */ 30class ReportHtmlText extends ReportBaseText 31{ 32 /** 33 * Render the elements. 34 * 35 * @param HtmlRenderer $renderer 36 * @param bool $attrib Is is called from a different element? 37 * 38 * @return void 39 */ 40 public function render($renderer, bool $attrib = true): void 41 { 42 // Set up the style 43 if ($renderer->getCurrentStyle() !== $this->styleName) { 44 $renderer->setCurrentStyle($this->styleName); 45 } 46 $temptext = str_replace('#PAGENUM#', (string) $renderer->pageNo(), $this->text); 47 // underline «title» part of Source item 48 $temptext = str_replace([ 49 '«', 50 '»', 51 ], [ 52 '<u>', 53 '</u>', 54 ], $temptext); 55 56 // If any text at all 57 if (!empty($temptext)) { 58 // If called by an other element 59 if (!$attrib) { 60 $renderer->write($temptext, $this->color); 61 } else { 62 // Save the start positions 63 $startX = $renderer->getX(); 64 $startY = $renderer->getY(); 65 $width = $renderer->getRemainingWidth(); 66 // If text is wider then page width then wrap it 67 if ($renderer->getStringWidth($temptext) > $width) { 68 $lines = explode("\n", $temptext); 69 foreach ($lines as $line) { 70 echo '<div style="position:absolute;top:', $startY, 'pt;', $renderer->alignRTL, ':', $startX, 'pt;width:', $width, 'pt;">'; 71 $line = $renderer->textWrap($line, $width); 72 $startY += $renderer->getTextCellHeight($line); 73 $renderer->setY($startY); 74 $renderer->write($line, $this->color); 75 echo "</div>\n"; 76 } 77 } else { 78 echo '<div style="position:absolute;top:', $startY, 'pt;', $renderer->alignRTL, ':', $startX, 'pt;width:', $width, 'pt;">'; 79 $renderer->write($temptext, $this->color); 80 echo "</div>\n"; 81 $renderer->setX($startX + $renderer->getStringWidth($temptext)); 82 if ($renderer->countLines($temptext) !== 1) { 83 $renderer->setXy(0, $startY + $renderer->getTextCellHeight($temptext)); 84 } 85 } 86 } 87 } 88 } 89 90 /** 91 * Returns the height in points of the text element 92 * The height is already calculated in getWidth() 93 * 94 * @param HtmlRenderer $renderer 95 * 96 * @return float 97 */ 98 public function getHeight($renderer): float 99 { 100 $ct = substr_count($this->text, "\n"); 101 if ($ct > 0) { 102 $ct += 1; 103 } 104 $style = $renderer->getStyle($this->styleName); 105 106 return $style['size'] * $ct * $renderer->cellHeightRatio; 107 } 108 109 /** 110 * Get the width of text and wrap it too 111 * 112 * @param HtmlRenderer $renderer 113 * 114 * @return array{0:float,1:int,2:float} 115 */ 116 public function getWidth($renderer): array 117 { 118 // Setup the style name, a font must be selected to calculate the width 119 if ($renderer->getCurrentStyle() !== $this->styleName) { 120 $renderer->setCurrentStyle($this->styleName); 121 } 122 123 // Check for the largest font size in the box 124 $fsize = $renderer->getCurrentStyleHeight(); 125 if ($fsize > $renderer->largestFontHeight) { 126 $renderer->largestFontHeight = $fsize; 127 } 128 129 // Get the line width for the text in points 130 $lw = $renderer->getStringWidth($this->text); 131 // Line Feed counter - Number of lines in the text 132 $lfct = $renderer->countLines($this->text); 133 // If there is still remaining wrap width... 134 $wrapWidthRemaining = $this->wrapWidthRemaining; 135 if ($wrapWidthRemaining > 0) { 136 // Check with line counter too! 137 if ($lw >= $wrapWidthRemaining || $lfct > 1) { 138 $newtext = ''; 139 $lines = explode("\n", $this->text); 140 // Go through the text line by line 141 foreach ($lines as $line) { 142 // Line width in points + a little margin 143 $lw = $renderer->getStringWidth($line); 144 // If the line has to be wrapped 145 if ($lw > $wrapWidthRemaining) { 146 $words = explode(' ', $line); 147 $addspace = count($words); 148 $lw = 0; 149 foreach ($words as $word) { 150 $addspace--; 151 $lw += $renderer->getStringWidth($word . ' '); 152 if ($lw <= $wrapWidthRemaining) { 153 $newtext .= $word; 154 if ($addspace !== 0) { 155 $newtext .= ' '; 156 } 157 } else { 158 $lw = $renderer->getStringWidth($word . ' '); 159 $newtext .= "\n$word"; 160 if ($addspace !== 0) { 161 $newtext .= ' '; 162 } 163 // Reset the wrap width to the cell width 164 $wrapWidthRemaining = $this->wrapWidthCell; 165 } 166 } 167 } else { 168 $newtext .= $line; 169 } 170 // Check the Line Feed counter 171 if ($lfct > 1) { 172 // Add a new line as long as it’s not the last line 173 $newtext .= "\n"; 174 // Reset the line width 175 $lw = 0; 176 // Reset the wrap width to the cell width 177 $wrapWidthRemaining = $this->wrapWidthCell; 178 } 179 $lfct--; 180 } 181 $this->text = $newtext; 182 $lfct = substr_count($this->text, "\n"); 183 184 return [ 185 $lw, 186 1, 187 $lfct, 188 ]; 189 } 190 } 191 $l = 0; 192 $lfct = substr_count($this->text, "\n"); 193 if ($lfct > 0) { 194 $l = 2; 195 } 196 197 return [ 198 $lw, 199 $l, 200 $lfct, 201 ]; 202 } 203} 204