Private/New-VellumTextStyle.ps1
|
function New-VellumTextStyle { <# .SYNOPSIS Builds a VellumPdf.Layout.Core.TextStyle from simple scalar parameters. .DESCRIPTION Internal helper shared by the public Add-* functions so that font, size, color, and alignment handling stays in one place. Returns $null when no styling was requested, letting callers fall back to the document's default font. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Returns a new in-memory TextStyle object; performs no external/system state change.')] [CmdletBinding()] [OutputType([VellumPdf.Layout.Core.TextStyle])] param( [string]$Font, [double]$FontSize, [VellumPdf.Fonts.EmbeddedFontHandle]$FontHandle, [ValidateCount(3, 3)] [ValidateRange(0.0, 1.0)] [double[]]$Color, [string]$LinkUri, # Line leading (extra vertical space between lines), in points. [ValidateRange(0, 1000)] [double]$Leading ) $wantsColor = $PSBoundParameters.ContainsKey('Color') $wantsLeading = $PSBoundParameters.ContainsKey('Leading') # Link hygiene: whitespace-only URIs become no-link (a literal '/URI ( )' # annotation otherwise lands in the PDF), and script-capable / local-file # schemes are rejected outright - a javascript: URI in a generated document # executes in readers that honour it (e.g. Acrobat). # # The scheme check runs against a copy with ALL whitespace and control # characters removed, not just leading ones, because lenient readers strip # that noise before dispatching the scheme. Matching only a contiguous # leading keyword would let 'java<TAB>script:', a mid-keyword no-break # space, or a leading 0x01 byte smuggle a blocked scheme through. $LinkUri = if ($PSBoundParameters.ContainsKey('LinkUri')) { $LinkUri.Trim() } else { '' } $wantsLink = $LinkUri -ne '' if ($wantsLink) { $normalized = $LinkUri -replace '[\s\p{Cc}\p{Cf}]', '' if ($normalized -match '^(?i)(javascript|vbscript|data|file):') { throw ("-LinkUri uses the blocked scheme '$($Matches[1])': javascript/vbscript/data/file " + 'URIs are not allowed in generated documents. Use http(s), mailto, or another safe scheme.') } } if (-not $Font -and -not $PSBoundParameters.ContainsKey('FontSize') -and -not $FontHandle ` -and -not $wantsColor -and -not $wantsLink -and -not $wantsLeading) { return $null } $style = [VellumPdf.Layout.Core.TextStyle]::new() if ($FontHandle) { # Embedded TrueType font wins; do NOT also set Standard14 Font. $style.FontRef = [VellumPdf.Layout.Core.FontReference]::new($FontHandle) } elseif ($Font) { # Standard14 exposes one static field per base-14 font (Helvetica, etc.). $style.Font = [VellumPdf.Fonts.Standard14]::$Font } if ($PSBoundParameters.ContainsKey('FontSize')) { $style.FontSize = $FontSize } if ($wantsColor) { $style.Color = [VellumPdf.Layout.Core.ColorRgb]::new($Color[0], $Color[1], $Color[2]) } if ($wantsLink) { $style.LinkUri = $LinkUri } if ($wantsLeading) { $style.Leading = $Leading } return $style } |