From f898a24a9f0ec06398dbcf755ed7128e6e488ab9 Mon Sep 17 00:00:00 2001 From: PrinsFrank <25006490+PrinsFrank@users.noreply.github.com> Date: Sat, 3 Oct 2026 16:30:40 +0200 Subject: [PATCH] Cache charWidth for identical textState and transformationMatrix --- .../PositionedText/PositionedTextElement.php | 2 +- src/Document/Object/Decorator/Font.php | 25 ++++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Document/ContentStream/PositionedText/PositionedTextElement.php b/src/Document/ContentStream/PositionedText/PositionedTextElement.php index 0a033b56..4fcee351 100644 --- a/src/Document/ContentStream/PositionedText/PositionedTextElement.php +++ b/src/Document/ContentStream/PositionedText/PositionedTextElement.php @@ -84,7 +84,7 @@ public function getAdvanceWidth(Font $font): float { $scaleX = $this->absoluteMatrix->scaleX; $fontSize = $this->textState->getFontSize(); - $glyphAdvance = $font->getWidthForChars($this->getCodePoints(), $this->textState, $this->absoluteMatrix); // Σ (w0·Tfs + Tc + Tw·[code 32]) · scaleX + $glyphAdvance = $font->getWidthForChars($this->getCodePoints(), $this->textState->wordSpace, $this->textState->charSpace, $fontSize, $scaleX); // Σ (w0·Tfs + Tc + Tw·[code 32]) · scaleX $offsetAdvance = -($this->getTotalOffset() / 1000) * $fontSize * $scaleX; // − Σ(Tj)/1000 · Tfs · scaleX return ($glyphAdvance + $offsetAdvance) * ($this->textState->scale / 100); // · Th diff --git a/src/Document/Object/Decorator/Font.php b/src/Document/Object/Decorator/Font.php index 3a45f62c..7d730a9d 100644 --- a/src/Document/Object/Decorator/Font.php +++ b/src/Document/Object/Decorator/Font.php @@ -140,22 +140,23 @@ public function getLastChar(): ?int { ?->value; } - public function getWidthForChar(int $characterCode, TextState $textState, TransformationMatrix $transformationMatrix): float { - $characterWidth = $this->getWidths()?->getWidthForCharacter($characterCode) ?? $this->getDefaultWidth(); - - // Word spacing (Tw) applies only to the single-byte character code 32, and never to composite (Type0) fonts (spec §9.3.3). - $wordSpace = ($characterCode === 32 && $this->getDescendantFonts() === []) ? $textState->wordSpace : 0.0; - - return ($characterWidth * ($textState->getFontSize()) + $textState->charSpace + $wordSpace) * $transformationMatrix->scaleX; - } - /** @param list $chars */ - public function getWidthForChars(array $chars, TextState $textState, TransformationMatrix $transformationMatrix): float { - $totalCharacterWidth = 0; + public function getWidthForChars(array $chars, float $wordSpace, float $charSpace, float $fontSize, float $scaleX): float { + if ($chars === []) { + return 0.0; + } + + $defaultWidth = null; + $totalCharacterWidth = 0.0; $charWidthCache = []; foreach ($chars as $char) { if (isset($charWidthCache[$char]) === false) { - $charWidthCache[$char] = $this->getWidthForChar($char, $textState, $transformationMatrix); + $characterWidth = $this->getWidths()?->getWidthForCharacter($char) ?? ($defaultWidth ??= $this->getDefaultWidth()); + + // Word spacing (Tw) applies only to the single-byte character code 32, and never to composite (Type0) fonts (spec §9.3.3). + $wordSpaceForChar = ($char === 32 && $this->getDescendantFonts() === []) ? $wordSpace : 0.0; + + $charWidthCache[$char] = ($characterWidth * $fontSize + $charSpace + $wordSpaceForChar) * $scaleX; } $totalCharacterWidth += $charWidthCache[$char];